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.

Permission profile: 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.

The ceiling is policy, not a lock. The tier is the agent's own judgement — reported in the completion marker — and 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

Assess trivial? → auto-merge

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_files tool (changed files + line counts) — no repository checkout needed — deliberately skips lockfile diffs, and pulls github_get_pull_request_diff only 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 recreate for Dependabot, or Renovate's rebase label — 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
Auto-merge needs "Allow auto-merge" enabled on the repository. If it isn't available, the workflow labels the PR 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.completed event with a success conclusion on a dependency-update PR (surfaced internally as pr.checks_passed). The connector pre-filters to Dependabot / Renovate — by the head commit author or the dependabot/ / 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 agent mode: scan sweep that assessed a whole repo in one session and overflowed its context on busy repos.)
  • Maintainer mention: an @last-light comment 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.)