Let the routine MintMaker PRs merge themselves
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.
##What a run looks like
Open Claude Code in the repository where you want to enable automerge, and run:
/mintmaker-automerge:setupA read-only script scans the repository, and then fourteen short steps ask a few questions each, with a recommended answer for all but 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"],
"platformAutomerge": true,
"tekton": {
"automerge": true,
"schedule": ["at any time"]
},
"packageRules": [
{
"matchManagers": ["dockerfile"],
"pinDigests": true
},
{
"matchManagers": ["dockerfile"],
"matchUpdateTypes": ["digest", "patch", "minor"],
"automerge": true,
"groupName": "base images"
},
{
"matchManagers": ["github-actions"],
"matchDepTypes": ["action"],
"rangeStrategy": "pin"
},
{
"matchManagers": ["github-actions"],
"matchUpdateTypes": ["patch", "minor"],
"matchDepNames": ["actions/checkout", "actions/setup-java"],
"automerge": true,
"groupName": "GitHub Actions"
},
{
"matchManagers": ["maven"],
"matchUpdateTypes": ["patch", "minor"],
"automerge": true,
"groupName": "Maven dependencies"
},
{
"matchManagers": ["maven"],
"matchPackageNames": ["io.quarkus*"],
"automerge": false,
"groupName": null
},
{
"matchManagers": ["npm"],
"matchUpdateTypes": ["patch", "minor"],
"automerge": true,
"groupName": "npm dependencies"
}
]
}- Pins GitHub Actions to commit SHAs, a security measure. See Why actions get pinned to a SHA, and images to a digest for more details.
- Renovate arms GitHub’s auto-merge feature on each PR, and GitHub merges it as soon as the required checks of the base branch pass. See How a PR merges with no approval for more details.
- Konflux pipeline updates in
.tekton/. - Overrides MintMaker’s default, which batches Konflux pipeline updates on Saturdays.
- Pins
FROMlines totag@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. - Digest, patch and minor bumps of the base images merge on their own, since the Konflux PR build tests the image.
- The digest, patch and minor bumps of the base images share one PR, "Update base images", so they land in one Konflux build and one merge. If one bump fails a check, the whole PR waits until that bump is fixed or excluded with a rule of its own.
- Pins each action to its full version,
v4.38.1rather thanv4, in one manual PR. See Why actions get pinned to a SHA, and images to a digest for more details. - 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/andgithub/, 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. - 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.
- Quarkus opts out of the Maven group: a group only automerges when every member does, so a dependency that never automerges would hold it.
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.
##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.
The version next to the SHA has to be a full one, v4.38.1 rather than v4.
Renovate never changes a floating tag such as v4, so every release would arrive as a digest PR, the same shape as a moved tag.
The plugin’s rangeStrategy rule pins each action to its full version in one manual PR.
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 required checks of the base branch, the only checks a merge waits for, as covered in How a PR merges with no approval.
The pinning rules, for actions and for images, stay in the file once everything is pinned. They cost nothing then, and an action or image added later on a movable tag gets its pin PR.
##How a PR merges with no approval
Renovate’s default, which MintMaker keeps, leaves the merge to GitHub’s auto-merge feature, when the repository allows it. Renovate arms it on each PR it opens, and GitHub merges the PR minutes after the branch rules are met, with no MintMaker run involved. When the branch requires an approval, the merge waits for a review that an unattended PR never gets. So the Konflux app has to be a bypass actor, an account that a GitHub ruleset allows to skip a rule such as the required approval. GitHub’s auto-merge does not honor the bypass in its "Always allow" and "For pull requests only" modes: it keeps waiting for an approval, and the PR stays blocked with every check green. Auto-merge works with the Exempt mode, where the rules are not evaluated at all for the Konflux app, so there is nothing to wait for.
An exemption goes further than a bypass: an exempt actor skips every rule of its ruleset, for pull requests and for pushes alike, and GitHub logs no bypass for it. So the Konflux app must be exempt from a ruleset that holds "Require a pull request before merging" and nothing else. The required checks and "Block force pushes" go in a second one that nobody bypasses: next to the approval rule, they would be skipped too, and the app could merge a PR with a red check or force-push the branch. Those required checks are the whole gate, because GitHub’s auto-merge reads nothing else: a check that is not required never holds a merge, red or not, and with no required check at all, a PR merges as soon as it opens.
##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 fourteen 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
/plugin install mintmaker-automerge@claude-ichiba
/reload-plugins- 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:setupClaude 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.