Docs
Dependabot PR merge
Dependabot PR merge is the proactive companion to Dependabot CI fix. That one repairs a dependency-update PR whose CI went red and then hands off to this one; this workflow handles every green dependency PR — both the naturally-green ones and the ones ci-fix just fixed — and is the single owner of the merge decision: it reads the diff, decides whether the bump is trivial, and enables GitHub auto-merge (squash) so the safe ones land without a human in the loop.
repo-write — needed for
the github_enable_auto_merge and github_merge_pull_request
tools. It never pushes code or rebases branches itself. It prefers to
enable auto-merge, which handles the race between the decision and a
late-created check, and merges directly only in the one case where GitHub
refuses auto-merge because there is nothing left to wait for. Both are
gated on the same fact — see The merge gate below. When a PR is
merely behind the base branch or has a lockfile conflict, it asks
the bot that opened the PR to rebase or recreate its own branch (via
github_add_issue_comment / github_add_labels)
rather than pushing a merge itself.
The merge gate
Whether the PR may be landed at all is decided by the head commit's
own check runs and statuses, resolved in code before the run starts, not by
GitHub's mergeable_state. On a repository with no
required checks a PR whose checks are failing still reports as
mergeable — that is how a red PR once got merged. So the gate is: checks
settled passing, and at least
dependencies.minSettledChecks of them.
That verdict is mayMerge, computed in code over the
resolved snapshot of the pull request and handed
to the run as a decided answer — the prompt reads it rather than re-deriving
it, so the log line, the audit comment and the admin panel all state the same
case. It is an instruction to the agent, though, not a capability
lock: the run still holds the merge tools when the gate is shut, because the
same phase also labels and comments. Separately, the dispatch gate refuses to
start a merge run at all while checks are still pending.
The same gate covers both mechanisms. Auto-merge used to be treated as the inherently safe one, on the reasoning that GitHub's required-checks gate would catch anything wrong — but that reasoning is circular: auto-merge merges as soon as GitHub's merge requirements are satisfied, and on an unprotected repository there are none beyond mergeability, so it lands an already-mergeable PR immediately. Enabling auto-merge is merging there.
A consequence worth knowing before you upgrade: a repository with no CI at
all (checksState: none) no longer has its dependency PRs
auto-merged. mergeable_state survives in the prompt only for
branch hygiene — behind / dirty — and for choosing between
the two merge mechanisms.
Major bumps: impact, not magnitude
A major version bump is not one thing. @types/node 20→21
and a runtime framework rewrite are both "major", and the version number
can't tell them apart — yet every major used to be escalated to a human on
that basis alone. Instead the run applies the dependency-impact
skill's rubric and reaches one tier, from evidence it can gather without a
checkout:
- low — a dev-only dependency, a GitHub Actions tag bump, or zero direct import sites; no documented breaking changes; CI settled passing
- medium — a runtime dependency, CI settled passing, breaking changes documented but none matching this repo's actual usage, and not security-sensitive
- high — a security-sensitive package, many import sites, breaking changes plausibly touching APIs this repo uses, CI not settled passing, or release notes missing or unparseable
The evidence is the PR body's release notes, the manifest change
(dependencies vs devDependencies), a
github_search_code count of direct import sites, the package's
domain, and the settled check result. That last one is the pivot that makes
any of this safe: the suite already ran against the bump.
Unknown counts as high — being unable to gather the
evidence is itself a signal, never a reason to guess low.
A major at or below dependencies.autoMergeMaxImpact
(medium by default) is auto-merged, and — when
dependencies.auditComment is on — gets one comment recording
the tier and the evidence behind it, which is the durable answer to "why did
this land unreviewed". Anything above the ceiling keeps the old path:
dependency-functional + requires-human. The run
also labels the tier itself: dependency-major-low /
-medium / -high, exactly one at a time.
Set autoMergeMaxImpact: none to keep every major in front of a
human.
autoMergeMaxImpact reaches the run as prompt text. No code
parses the reported tier, compares it to the ceiling, or takes the merge
tools away from a run that reported one above it. The rubric's
unknown ⇒ high rule and the settled-checks gate are what make
the default safe in practice; lowering the ceiling narrows what the
agent is told it may land, and the audit comment is how you check
afterwards that it did.
Pipeline
What it does
- Runs against a single PR at a time — its context is bounded, so it can't overflow. Inspects through the
github_list_pull_request_filestool (changed files + line counts) — no repository checkout needed — deliberately skips lockfile diffs, and pullsgithub_get_pull_request_diffonly for a small non-lockfile source change - Classifies the change conservatively: only lockfile / manifest bumps, GitHub Actions tag/SHA bumps, type-only or mechanical edits count as trivial; anything touching runtime logic or anything security-sensitive is functional. A major-version bump branches into the impact rubric above rather than being functional by definition. "Trivial" here means safe to land without a human, not small
- If trivial and the merge gate is open, enables GitHub auto-merge (squash). If GitHub refuses auto-merge because the PR is already mergeable with nothing to wait for ("clean status"), it direct-squash-merges instead — the gate is already the proof the checks are green; if the repository disallows auto-merge outright, it comments for a maintainer. Functional PRs are left for a human with a comment
- If a PR is behind the base branch or dirty (a lockfile conflict), it doesn't give up: it asks the bot that opened the PR to update its own branch —
@dependabot rebase/@dependabot recreatefor Dependabot, or Renovate'srebaselabel — because the bot regenerates lockfiles correctly. For a trivial PR it enables auto-merge at the same time, so GitHub lands it once the rebase re-runs the checks green. A non-Dependabot/Renovate PR that's behind is left for a human to rebase - When in doubt, it does not auto-merge
- Every run must sign off with a machine-readable completion marker carrying the verdict, the impact tier and the action taken; a run that inspects files but reaches no verdict and takes no action is recorded as failed, not a silent green
requires-human and — once
only — comments that the update looks safe and asks a maintainer to merge.
Separately, the merge gate needs at least
dependencies.minSettledChecks settled, passing checks, so a
repository with no CI at all gets nothing merged automatically.
Triggers
- GitHub webhook: a
check_suite.completedevent with asuccessconclusion on a dependency-update PR (surfaced internally aspr.checks_passed). The connector pre-filters to Dependabot / Renovate — by the head commit author or thedependabot//renovate/branch prefix — so ordinary green PRs fire nothing. The router routes it deterministically to this workflow. Requires the GitHub App to subscribe to Check suite events (Checks: read). - Cron backstop: a daily job whose runner finds the green Dependabot / Renovate PRs across managed repos in code (no LLM) and fans out one bounded run per PR — the same single-PR shape as the webhook. "Green" means the head commit's checks have settled passing, not just that GitHub calls the PR
clean: on a repo with no required checks a red PR is still mergeable, so the sweep asks the checks directly and drops the candidate if it can't read them. Runs queue against the global concurrency cap. Unlike the review scan, it runs alongside webhooks — a safety net for PRs that went green before boot or during a missed delivery. Auto-merge is idempotent and per-PR runs dedup by (repo, PR), so the overlap is harmless. (This replaced an agentmode: scansweep that assessed a whole repo in one session and overflowed its context on busy repos.) - Maintainer mention: an
@last-lightcomment on a green Dependabot / Renovate PR (e.g. "can you look at this?"). The router hands the PR author + check state to the classifier, which routes a green dependency PR here — the on-demand version of the webhook. (A red one routes to dependabot-ci-fix instead; an explicit "review this" still gets a normal review.)