Let the routine MintMaker PRs merge themselves
|
This post was written with the help of AI. |
If your repository is onboarded in Konflux, the open source software factory that builds and releases container images, MintMaker, a service built on top of Renovate, opens a pull request for every dependency update. Reviewing and approving each PR takes time, and until someone does, the update waits, security fixes included.
It does not have to be that way. Renovate can merge a PR on its own, under conditions you choose. The challenge is to automate the merges without giving up security or stability, and it comes down to a series of decisions: which updates may merge on their own and which ones stay out, on which days a merge may happen, which checks gate it, and whether GitHub Actions and base images get pinned to a SHA or a digest first.
I built MintMaker Automerge, a Claude Code plugin, to help you make those decisions in about twenty minutes. It guides you through the decisions one at a time, with a recommended answer and a short explanation of what is at stake, so you end up understanding the config as well as owning it. This post explains what the plugin does, why it is safe, and how to try it.
|
In a hurry? The Try it section has the install commands, and the run explains itself as it goes. |
|
This plugin only works on a GitHub repository onboarded in Konflux, the only place MintMaker runs, and refuses to run on a repository that is not onboarded. |
What a run looks like
Open Claude Code in the repository where you want to enable automerge, and run:
/mintmaker-automerge:setup
A read-only script scans the repository, and then thirteen short steps ask a few questions each, with a recommended answer for every one of them.

Nothing is written on disk before you approve the summary.
Nothing is pushed before you approve the pull request.
The GitHub requirements for automerge are explained, checked when the GitHub CLI, gh, is logged in, and never changed by the plugin.
Automerge is a trust decision, and every choice that matters stays yours.
Every step also teaches: a note explains what the choice changes, in Renovate, in GitHub or in Konflux, and asking why in the session gets a longer explanation.

This post does not walk through the steps: the run explains them better than this post can, one screen at a time. The sections below cover what a run cannot show: the reasoning behind the design.
One reviewer per kind of bump
Human review of MintMaker’s PRs, one per dependency bump, is expensive and slow, and it stops scaling as soon as several repositories are onboarded in Konflux. Delegating the reviews to an AI is tempting, but it costs tokens on every PR, and a routine one is not worth that cost. The third option is to let Renovate rules decide: they cost one decision, the one this plugin helps you make, and nothing per PR after that, but they cannot handle the more complex bumps.
None of the three options works well for every bump. Combined, they can each take the kind of bump they handle best:
-
Renovate rules for the routine bumps, which merge without anyone watching.
-
An AI review for the bumps a rule cannot express, such as a framework that must stay on a long-term support (LTS) version, or an upgrade that comes with a migration guide to apply.
-
A human for the riskiest bumps, and for the ones too complex for an AI.
The plugin sets up the Renovate rules. The AI review is future work, described in What’s next.
What lands in the repository
This is the renovate.jsonc file a run writes at the root of the repo for a Quarkus service with an npm frontend, Dockerfiles on Red Hat’s UBI base images, and a CI workflow using actions/checkout and actions/setup-java, trimmed and stripped of its comments:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["helpers:pinGitHubActionDigests"], (1)
"platformAutomerge": false, (2)
"ignoreTests": false, (3)
"tekton": { (4)
"automerge": true,
"schedule": ["at any time"] (5)
},
"packageRules": [
{
"matchManagers": ["dockerfile"],
"pinDigests": true (6)
},
{
"matchManagers": ["dockerfile"],
"matchUpdateTypes": ["digest", "patch", "minor"],
"automerge": true (7)
},
{
"matchManagers": ["github-actions"],
"matchUpdateTypes": ["patch", "minor"],
"matchDepNames": ["actions/checkout", "actions/setup-java"], (8)
"automerge": true
},
{
"matchManagers": ["maven"],
"matchUpdateTypes": ["patch", "minor"],
"automerge": true
},
{
"matchManagers": ["maven"],
"matchPackageNames": ["io.quarkus*"],
"automerge": false (9)
},
{
"matchManagers": ["npm"],
"matchUpdateTypes": ["patch", "minor"],
"automerge": true
}
]
}
| 1 | Pins GitHub Actions to commit SHAs, a security measure explained in Why actions get pinned to a SHA, and images to a digest. |
| 2 | Renovate merges each PR itself instead of leaving it to GitHub’s auto-merge feature, for a reason explained in Why Renovate merges the PR itself. |
| 3 | The merge gate: every check on the PR must pass, required or not. See Why Renovate merges the PR itself for the alternative. |
| 4 | Konflux pipeline updates in .tekton/. |
| 5 | Overrides MintMaker’s default, which batches Konflux pipeline updates on Saturdays. |
| 6 | Pins FROM lines to tag@sha256, so rebuilds of a tag arrive as digest PRs, in a rule of its own because Renovate decides the pin before it knows the update type. |
| 7 | Digest, patch and minor bumps of the base images merge on their own, since the Konflux PR build tests the image. |
| 8 | Only the actions named here are automerged, because an action runs arbitrary code in CI with the workflow’s secrets. Those maintained by GitHub, under actions/ and github/, are the recommended set. A third-party one is a trust decision of its own. Patch and minor only, so a moved tag with no version change never merges alone. |
| 9 | Quarkus stays manual: a Renovate rule cannot tell an LTS version from another, and a Quarkus update can come with a migration guide to check and apply. |
The renovate.jsonc file itself is never automerged: any change to it, from a teammate or from Renovate’s own migration PRs, is an ordinary PR that needs a review, so the bot can never loosen its own rules.
The plugin also adds a GitHub workflow under .github/workflows/ that runs MintMaker’s own config validator whenever the file changes, unless the repository already has one.
That validator catches syntax and schema errors, and settings Renovate has retired, but not a wrong name, so the plugin checks the names itself before the file is committed, since a misspelled package or action would pass and match nothing.
The release-age delay
Renovate can wait before it opens a PR for a new release, a setting called the release-age delay. The file above does not mention it because MintMaker’s global configuration sets a default for every onboarded repository. Most automerged bumps get that delay, and the two warnings below cover the ones that do not.
A compromised version is usually caught and pulled within days, and during that time Renovate proposes nothing, so the compromised version never even runs in your CI. The delay doesn’t help when a compromise is found weeks later: the xz backdoor, planted in a compression library that Linux distributions load into their SSH server, sat unnoticed for five weeks in 2024.
|
Renovate does not delay vulnerability fixes by default, and MintMaker keeps that default: a fix that matches your automerge rules merges as soon as the checks pass. An advisory can be wrong or planted, so a fix that merged without the delay is worth a look afterwards. |
|
The delay does not apply to base images outside Docker Hub: Renovate only learns image publish dates there, and MintMaker treats a release without one as old enough.
An image from |
Why actions get pinned to a SHA, and images to a digest
The delay guards against a new release that turns out bad, and does nothing against a version that already exists and changes under you, which is what pinning is for.
actions/checkout@v4 tells CI to run version 4 of the action, but v4 is a movable label, so CI runs whatever it points at today.
If someone moves it to malicious code, CI runs that with no PR to warn you.
This is what happened to the tj-actions/changed-files action in March 2025: release tags were moved to a commit that read secrets from the runner, and the workflows that referenced the action by tag ran it, while those pinned to a commit SHA did not.
A commit SHA cannot be moved, so the plugin proposes to pin every action to one, and a hijacked tag can then only arrive as a PR that never automerges.
A base image tag such as ubi9/openjdk-21:1.20 can be rebuilt by the registry at any time, and your next build pulls the new image with no PR and no test.
A digest, the hash of one exact build, cannot change, so once a FROM line is pinned to tag@sha256, every rebuild arrives as a PR that the Konflux PR pipeline builds and tests before it merges.
Since those images get no release-age delay, the Konflux pipeline is their only protection: keep it among the checks a merge waits for, as covered in Why Renovate merges the PR itself.
Why Renovate merges the PR itself
Renovate’s default, which MintMaker keeps, leaves the merge to GitHub’s auto-merge feature, when the repository allows it.
A GitHub ruleset can let some accounts, called bypass actors, skip a rule such as the required approval, and the Konflux app can be one of them.
When that bypass is what satisfies the approval rule, GitHub’s auto-merge never completes: the PR stays blocked with every check green.
This is a bug first reported in January 2025 and reproduced with a clean test on GitHub’s forum in July 2026, with no answer from GitHub and no fix as of September 2026.
So the plugin turns the feature off, with platformAutomerge set to false, and Renovate merges the PR itself on a later MintMaker run, which comes every four hours, so hours after the checks went green rather than minutes.
The API call Renovate uses to merge respects the bypass, unlike the auto-merge feature, so the Konflux app can merge on a branch that requires an approval once it is allowed to skip that rule.
By default, Renovate merges only once every check on the PR is green, required or not, and the plugin recommends keeping it that way: a red check is worth a look before anything merges.
It means that a failure unrelated to the PR, a vulnerability scan on a new advisory for instance, holds every automerge, which happened on one of our repositories.
The alternative, ignoreTests set to true, lets Renovate merge as soon as the branch’s Required checks pass, whatever the rest say, so the list of required checks has to be chosen carefully.
With no required checks at all, a PR merges on red CI.
The pull request the plugin opens lists what you acknowledged: the bypass, and the required checks if you chose ignoreTests, so a reviewer can verify them before merging.
How I made it reliable
The facts of a run come from a script, not from the model.
A read-only shell script goes through the repository for its ecosystems, base images, actions, branches and existing config, asks GitHub for the branch rules when gh is logged in, and prints a report that the steps read from, so two runs on the same repository see the same facts.
The model only does what a script cannot: it frames each decision and writes the config from your answers.
That part is not deterministic, so the plugin repository holds evals, automated tests that run the skill as a person would.
Seven small repositories cover the cases, from a Quarkus service with a dependabot.yml to a Go module with an old config to migrate, and one of them is not on Konflux, so the skill must stop.
A script acts as the user through the Agent SDK, answers every menu, and then checks the transcript and the working tree: the thirteen screens came in order, nothing was written before the approval, the config holds the expected rules, and nothing was committed.
The evals run on every pull request that touches the skill. A run fails now and then, and a failing repository gets one rerun before the job goes red.
Why the Renovate config is not a shared preset
Renovate can load rules from a preset hosted in another repository, and MintMaker itself publishes presets that way, so a shared automerge preset may look like a good idea for an organization. The plugin does the opposite, one self-contained file per repository, and I want to explain why.
What a shared preset does well:
-
One change reaches every repository at once, which matters when the policy itself changes: a setting such as
platformAutomergeflipping for every repository is one commit in a preset, and one PR per repository otherwise. -
Turning automerge on for dependency updates takes one line in a config, where the plugin asks for twenty minutes of decisions.
Why the plugin does not use one:
-
The decision belongs to the repository owner, and a preset moves it to whoever can merge in the shared repository, with no PR in the repository that uses the preset, unless that repository pins it to a version.
-
The rules that matter most are repository-specific: the actions allowed by name, the packages kept manual, the image choices.
-
The file is small and almost never changes, so there is no stream of changes to centralize.
-
A preset adds a second repository to read, and a precedence question on top of MintMaker’s global configuration, for whoever asks why a PR merged on its own.
What the plugin shares is the reasoning: the same questions and the same recommended answers, applied to what each repository contains.
I am open to being wrong about this: if a shared preset works for your organization, please reach out or use the comments to change my mind.
Try it
You need Claude Code and a GitHub repository onboarded in Konflux.
A gh login is optional.
With it, the run checks the branch rules on GitHub for you and opens the pull request at the end.
Without it, the run uses a GitHub token from your environment if there is one, and otherwise gives you a link and the text to paste to open the pull request yourself.
When your branch requires an approval, nothing merges until you allow the Konflux app to skip that rule.
The run explains how, and you change the setting yourself.
Install the plugin from a Claude Code session:
/plugin marketplace add gwenneg/claude-ichiba (1)
/plugin install mintmaker-automerge@claude-ichiba
/reload-plugins
| 1 | Full disclosure: claude-ichiba is my own plugin marketplace. It also hosts Soundings, a release risk plugin I wrote about recently. |
Then, from the repository where you want to enable automerge:
/mintmaker-automerge:setup
Claude Code only updates plugins from its official marketplace automatically.
Enable auto-update for claude-ichiba in the /plugin panel, or refresh it yourself from time to time:
/plugin marketplace update claude-ichiba
/reload-plugins
What’s next
When the scan finds Quarkus, Spring Boot, Django or Angular, the plugin recommends keeping it on manual review. Each framework is one line in the scan script, with its reason and a link. If your stack has a package that should never be automerged, a pull request adding its line is welcome, and so are issues from your first run.
The plugin covers the bumps a Renovate rule can judge, and the next step is an AI agent for two things a rule cannot:
-
The bumps that need reading, a framework kept on its LTS version with a migration guide to apply: the agent picks the target, applies the guide, runs the tests, and opens a PR that a human reviews.
-
The PRs that qualify for automerge and sit open on a failed check: the agent reads the failure, tells a flaky job from a real break, and pushes the fix so the checks run again.
If you try MintMaker Automerge on one of your repositories, please let me know how the run went.
Leave a comment