.cursor/skills/merge-dependabot-prs/SKILL.md
Treat each blocked PR as its own small diagnosis, not one "just merge it" action.
Confirm before anything consequential. Approving, closing, pushing to a PR
branch, merging main into someone's branch, and rerunning CI all touch shared
state. Triage everything into buckets first, then confirm the plan per bucket
with AskUserQuestion — not per PR, and not after the fact. Re-confirm if a
genuinely new kind of problem appears mid-flight (e.g. a real regression where
a mechanical fix was expected).
main merges exclusively through the merge queue ("Main Protection"
ruleset). Enqueue with gh pr merge <pr> --auto — no strategy flag; the
queue picks the method. --squash/--merge/--rebase will be rejected.quality-checks, playwright-required, database-tests,
backend-check, mypy-check, Jest Tests, required.required (in pr-integration-tests.yml) and playwright-required (in
pr-playwright-tests.yml) are aggregate needs: [...] + if: always()
jobs over the slow integration/playwright matrices. If either is absent
from gh pr checks, its matrix is still running — the PR isn't blocked.
(merge-group.yml provides instant-pass stubs of the same names inside the
queue itself.)mergeStateStatus/autoMergeRequest are unreliable for "is it actually
queued" — query the queue directly: references/graphql-queries.md.gh pr list --search "is:open author:app/dependabot assignee:<user>" \
--json number,title,headRefName,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup
PRs are labeled by ecosystem (dependabot:python, dependabot:javascript,
dependabot:docker, dependabot:actions, plus dependabot:sandbox) and
assigned per .github/dependabot.yml. Flag duplicates: two PRs bumping the
same package, or a manual bump PR overlapping a bot one.
These PRs aren't in a rush. Wait for every check to complete — required and advisory alike — and treat any red check as a failure to classify, never as noise to skip. Two advisory checks matter here even though the queue ignores them:
storybook-build (pr-storybook-build.yml) on web/** changes — never
gates the queue, but pages Slack if broken post-merge.
audit (audit.yml) — runs on every lockfile, pyproject.toml,
.github/workflows/**, and tools/ods/** change, so it runs on almost every
Dependabot PR. Treat it as required for this skill: a Dependabot PR does
not get enqueued while audit is red. A red audit means the bump either
pulled in a vulnerable version or landed next to one, and merging it ships
the finding.
Green & ready — every check completed and passing, advisory included.
Failing — mechanical — only a generated/lock file wasn't regenerated after the bump (see step 5 for the Onyx cases).
Failing — needs diagnosis — anything else; requires reading the failing job's log first, never just the check name.
Conflicting — real merge conflict against main.
Superseded — a newer PR in the batch covers it.
Independent of bucket, assess compatibility: note each PR's semver jump and whether the package is production or dev-only. Major bumps (and 0.x minors, which semver allows to break) are never covered by a blanket "enqueue the green ones" — green CI proves the build, not the behavior. Surface each one individually in the confirmation with a one-line breaking-changes summary from the release notes Dependabot embeds in the PR body, and let the user opt in per PR.
Summarize buckets and proposed actions, confirm with AskUserQuestion, then act.
Run ods audit on the PR's code before you enqueue it. CI's audit job covers
this, but it is skipped when the PR touches no audited path, and it is advisory
in the queue — so confirm it yourself for every Dependabot PR.
gh pr checkout <pr>
source .venv/bin/activate # ods ships in the repo venv
ods audit --fail-on=critical
ods audit scans bun.lock and uv.lock plus open Dependabot alerts, and
exits non-zero on an unignored finding at or above --fail-on
(tools/ods/README.md). It reads the working
tree, so the PR branch must be checked out — a run on main says nothing
about the bump.
If it exits non-zero, STOP. Don't enqueue and don't try to work out whether
the finding came from this bump or was already on main. Report the advisory ids
and let the user say how to proceed.
Then, once clean:
gh pr review <pr> --approve
gh pr merge <pr> --auto
If a PR falls out of the queue (e.g. head_ref_force_pushed after a Dependabot
rebase), re-running gh pr merge <pr> --auto is routine, not a failure.
gh pr closeOnce the bucket is approved, individual stale-generated-file fixes don't need per-PR confirmation. Known Onyx cases:
dependabot:python): the exported backend/requirements/*.txt
files go stale when only pyproject.toml/uv.lock were bumped. Regenerate
via the same pre-commit hooks CI uses:
pre-commit run --files pyproject.toml uv.lock backend/requirements/*.txt
dependabot:javascript): stale bun.lock — run
bun install in the bumped directory (repo root or web/).Getting the branch: prefer the harness's isolated-worktree feature if it has
one (Claude Code: EnterWorktree). Otherwise, if the current checkout is
clean, work in place — gh pr checkout <pr>, fix, push, and return to the
previous branch. If neither applies (e.g. dirty checkout), ask the user where
to resolve (AskUserQuestion) rather than picking a spot — and steer away
from tmpfs paths like /tmp, which can hit "Disk quota exceeded"
mid-post-checkout hook (uv sync/bun install) even when they look roomy.
gh run rerun <runId> --failed). If the same
failure recurs, stop and ask — a persisting "flake" may not be one.@dependabot rebase (or
recreate) — Dependabot owns the branch and will redo it properly.@dependabot rebase discards
non-Dependabot commits. Instead rebase onto origin/main yourself, rerun
the step 5 regeneration if lockfiles conflicted, push with
--force-with-lease, and verify git diff origin/main...HEAD --stat still
shows only the intended bump. If a pre-push hook trips on a stale local
cache (e.g. dev type-gen referencing a file deleted upstream), clear the
cache and retry — don't skip the hook.Prefer one polling loop (e.g. Monitor) over repeated manual checks: watch
both queue state and PR state (MERGED/CLOSED), and surface new failures as
they appear rather than staying silent until success.
Merged (N): #A, #B, #C
Closed as superseded (N): #D (superseded by #E)
Left for you (N): #F — <specific unresolved reason>