
GitHub's Agentic Execution Environment
You could already run AI in GitHub Actions. gh-aw's real novelty is the sandboxed execution environment around it, and one Renovate review showed why that matters.
I finally discovered Renovate can update version strings in arbitrary files with its regex manager, and immediately used it for both my homelab and client infra.
Today I got to know a Renovate feature that is more than six years old. Which is also a mildly embarrassing sentence to write down publicly.
But let me back up a little bit.
Renovate is great. It is basically Dependabot, except much more flexible and not tied to GitHub. I run Forgejo in my homelab and use it to drive deployments for a lot of my home infrastructure. Yes, still overkill. Still fun.
The problem was that some of my pinned version strings had just kind of been sitting there since February. Not because I had consciously decided they should stay frozen forever. More because they lived in places that are easy to ignore: a --version in a Makefile, an appVersion in a Chart.yaml, some image tags in values files, a version string in a script, that sort of thing.
This was all behind an up-to-date OPNsense box, so it was not an immediate disaster. But stale versions are not only about missing security fixes. You also miss bugfixes, new features, and eventually the pleasant surprise of realizing you are now several releases behind and should probably stop pretending that is fine.
I already had a couple of helper scripts for some of this. They worked. They were also not really the grown-up answer.
The grown-up answer, obviously, was Renovate.
That in itself was not news to me. We had already rolled out Renovate in a client repository as well. What was news to me was that Renovate can also handle what I had mentally filed under “arbitrary files”. Which, in retrospect, was me underestimating Renovate more than anything else.
And honestly, AI is part of why I finally noticed this. This had been bothering me for a while, but for some reason I was oddly reluctant to really challenge the assumption that these awkward version pins would just stay manual forever. One of the useful things about AI in day-to-day development is that it sometimes points at the solution you should probably have tried months ago. This was one of those cases.
The feature is now documented as a custom manager with customType: 'regex'. Older posts and examples may still call it regexManagers, because that was the old name. Either way, the idea is the same: if Renovate does not have a built-in manager for the place where you pinned a version, you can teach it how to find that version with a regex.
This is not even new. The feature shipped on 6 March 2020 in Renovate v19.159.0. So this was not some hidden beta thing I stumbled upon. This has just been sitting there for years while I apparently decided “well, I guess that one has to stay manual” often enough to start believing it.
What the regex manager really does is connect three pieces of information:
In Renovate terms that usually means depName, datasource, and currentValue, with versioning often falling back to a sensible default.
Once you see it that way, the whole thing becomes much less mystical. You are not asking Renovate to “understand any file”. You are just giving it enough metadata to map some random-looking version string back to a real dependency.
One pattern I ended up liking a lot is putting the metadata directly above the version pin instead of hiding all the logic in renovate.json5.
For example, if you install a Helm chart in a shell block inside a workflow, you can do this:
# renovate: datasource=helm depName=kyverno registryUrl=https://kyverno.github.io/kyverno/
--version 3.8.1 \
And then your Renovate config teaches the regex manager how to read that:
{
customManagers: [
{
customType: 'regex',
managerFilePatterns: ['/^\\.github\\/workflows\\/.*\\.ya?ml$/'],
matchStrings: [
'# renovate: datasource=(?<datasource>\\S+) depName=(?<depName>\\S+) registryUrl=(?<registryUrl>\\S+)\\s+--version (?<currentValue>[\\d.]+)',
],
},
],
}
That is basically the whole trick. The inline comment says what the dependency is. The regex extracts the fields. Renovate does the rest.
There is a slightly different version of the same idea for local Helm charts where appVersion mirrors the image tag:
# renovate: image=prom/pushgateway
appVersion: 'v1.11.2'
Then you can hardcode the datasource in the manager itself:
{
customManagers: [
{
customType: 'regex',
datasourceTemplate: 'docker',
managerFilePatterns: ['/(^|/)Chart\\.yaml$/'],
matchStrings: ["# renovate: image=(?<depName>.*?)\\s+appVersion: '(?<currentValue>[\\w+.\\-]*)'"],
},
],
}
That second variant was especially useful in my homelab, because several of my charts use .Chart.AppVersion as the default image tag anyway. So if that field drifts away from the real image tag, you eventually get confusion for free.
Once I started thinking about version pins this way, I noticed them all over the place.
Not just the obvious ones in package manifests. I mean the annoying ones:
helm upgrade --install ... --version ...Chart.yaml appVersion fields that actually matterThat was the part I had mentally written off before. I had basically accepted that anything outside the usual package-manager-shaped files would either stay manual or would need one-off scripts forever.
Turns out that was nonsense.
In my homelab repo, I had already expanded Renovate quite a bit, but the regex manager was what made the weird pins feel manageable instead of second-class citizens. It let me keep the dependency metadata right next to the pinned value, which is honestly where it belongs anyway.
That also made the repo easier to read later. If I see this:
# renovate: image=ghcr.io/open-webui/open-webui
appVersion: 'v0.6.32'
I do not need to go spelunking through Renovate config to understand what is meant to update it. The file documents itself.
The funny part is that once I had done this at home, I immediately noticed the exact same blind spot in a client repository.
We already used Renovate there as well. But there were still a few Kubernetes-related version pins that had just been silently accepted as manual: Helm chart versions in workflow shell blocks, chart versions in CDK HelmChart props, a Karpenter version in a script, and a couple of things around load balancer controller resources.
None of those were impossible for Renovate to understand. They were just not in places a built-in manager scans by default.
So the solution was the same:
renovate: comment directly above the pinned versionThat last part matters. Regex managers are not magic, and infrastructure updates are not the kind of thing I want merged blindly just because a pattern matched. Renovate can tell me that a newer version exists. It cannot tell me whether that Karpenter bump also wants an IAM policy change, whether some CRD update has side effects, or whether the changelog contains one charming sentence that translates to “your Friday evening is gone now.”
Still, getting Renovate to at least surface those updates is a massive improvement over forgetting they exist.
This is the part where I should probably save someone else a bit of confusion before somebody copy-pastes this and decides regex managers are magic.
First, the regex manager works on file content, not on some magical semantic understanding of the file. It also matches per file, not per line. So if you change formatting too much without updating the regex, you can break detection.
Second, the comment format needs to match what your regex expects. In one of my setups, the attribute order mattered. depName before registryUrl worked. Swapping them did not.
Third, you still need to pick the right datasource. One nice example from the client setup was Karpenter: although it is conceptually a Helm chart install, the lookup needed the docker datasource because the chart was being pulled as an OCI artifact from public ECR. That is the sort of detail that makes total sense once you know it and is mildly annoying five minutes before you know it.
So yes, regex managers are powerful. They are also a little bit fragile. But in a very normal, understandable way.
The main thing I took away from this was not “wow, regex can do anything.” Regex cannot do anything. Regex can definitely also ruin your afternoon.
The useful lesson is simpler: go audit your repository for version strings Renovate is currently not seeing.
If you have ever said one of these sentences, this is probably for you:
Maybe you really do have a case where leaving it manual is the right call. But I suspect a lot of us, me included, have accepted manual update work mostly because the dependency was in an awkward place and we never came back to question that assumption.
I should have known about this feature earlier. I did not. Fine.
At least now a few more version strings in my repos, and in one client repo, no longer get to hide from Renovate just because they picked an unusual file to live in.
Explore more articles on similar topics

You could already run AI in GitHub Actions. gh-aw's real novelty is the sandboxed execution environment around it, and one Renovate review showed why that matters.

My homelab was already working fine, but I rebuilt it anyway to get easier rollbacks, simpler disaster recovery, and a faster way to ship changes with AI.

From babysitting commands to fire-and-forget confidence: how Agent Skills transformed my git workflow and why they matter for AI-assisted development.