dependency-upgrade-review
Give a merge verdict on a dependency-upgrade pull request (Dependabot, Renovate or a hand-made bump) across npm, pip, Go, Cargo and Maven lockfiles and GitHub Actions pins. Reads the release notes for every skipped version, lists what the lockfile changes beyond the PR title (transitive bumps, new and removed packages, install scripts, registry changes), checks each SHA pin against its release tag and against the PR's other pins, checks raised runtime floors against the images and runners that install it, says whether CI ran the changed code, traces what each caller of a changed API now does and writes the rollback. The reply leads with MERGE, MERGE AFTER CHECKS or DO NOT MERGE and the reasons that decide it. Use when the user says "review this Dependabot PR", "is this Renovate bump safe to merge", "can I merge this dependency upgrade", "check this lockfile diff", or "is this action SHA pin right".
Other ways to install
With the sibling skills it hands off to:
The whole pack it belongs to:
By hand, from a clone of the repo:
In Claude Code, with the dev-team plugin installed, invoke it as:
Try it
A realistic prompt from the skill's acceptance evals:
Dependabot opened PR #212 on harbor-notes: "Bump quillmark from 3.4.1 to 4.1.0". CI is green. The PR diff is in pr.diff, quillmark's changelog is quillmark-CHANGELOG.md, and I've attached src/render/, test/ and .github/workflows/ci.yml from the repo. Can I merge it?
What a good result looks like
Example output
Worked example: Ledgerline, a Poetry patch bump that earns MERGE · the skill's own worked example, source
Most worked examples end in a block. This one shows what it takes to close every check, so MERGE is earned rather than assumed.
Input
The user says: "Can I merge PR #57 on ledgerline, 'chore(deps): bump tidyparse to 2.2.2'? CI is green." and supplies:
- the diff,
inputs/ledgerline.diff(pyproject.tomlandpoetry.lock) - tidyparse's changelog for 2.2.1 and 2.2.2
- the repo:
app/ingest.py,tests/test_ingest.py,.github/workflows/ci.yml
Changelog excerpt as supplied:
## 2.2.2
- Security: a single line longer than 10 MB is now rejected with RowTooLongError
(a subclass of ParseError) instead of being read into memory.
## 2.2.1
- Fixed: a quoted field containing a newline was split into two rows.
Repo excerpts as supplied:
# app/ingest.py
12 def import_statement(path):
13 try:
14 rows = tidyparse.parse_rows(path, dialect="excel")
15 except tidyparse.ParseError as exc:
16 raise StatementRejected(str(exc)) from exc
# tests/test_ingest.py
3 from app.ingest import import_statement
9 def test_quoted_newline_stays_one_row(tmp_path): ...
17 def test_malformed_file_is_rejected(tmp_path): ...
.github/workflows/ci.yml runs pytest -q on pull_request.
Script output (real; the header, the fixed footer and the empty sections trimmed)
python3 scripts/upgrade_diff.py examples/inputs/ledgerline.diff --title "chore(deps): bump tidyparse to 2.2.2"
**Floor verdict: none from the diff** (mechanical; the changelog, usage and CI checks are still to do, and only they can make it MERGE)
## Changed (3)
| Package | Ecosystem | Old → New | Class | File | Notes |
|---|---|---|---|---|---|
| `charset-sniff` | pip | 1.4.0 → 1.4.1 | patch | `poetry.lock` | lockfile only (transitive); not named in the title |
| `tidyparse` | pip | 2.2.0 → 2.2.2 | patch | `poetry.lock` | direct |
| `tidyparse` | pip | ^2.2.0 → ^2.2.2 | patch | `pyproject.toml` | |
## Beyond the title (1)
- `charset-sniff` changed: 1.4.0 → 1.4.1 (poetry.lock)
No install scripts, sources, licences or pins appear. The floor says only that the diff itself raises nothing; the notes, the search and CI decide the rest.
Review (what the agent hands back)
MERGE. Two patch releases; the only behaviour change, 2.2.2's new 10 MB line limit, raises an error the import code already handles, and the PR's tests run that code.
- Both releases read. 2.2.1 fixes quoted newlines splitting rows, covered by
test_quoted_newline_stays_one_row(tests/test_ingest.py:9). 2.2.2 is a security fix: lines over 10 MB raiseRowTooLongError, a subclass ofParseError. git grep -n "tidyparse" -- '*.py'finds one call,app/ingest.py:14, insideexcept tidyparse.ParseError(app/ingest.py:15), so the new error becomesStatementRejectedlike any malformed file.ci.ymlrunspytest -qon the PR andtests/test_ingest.py:3importsimport_statement, so the changed code ran.
Also in the lockfile: charset-sniff 1.4.0 → 1.4.1 (transitive patch). No new packages, install scripts, sources, runtime changes or pins.
Rollback: git revert the merge commit, or poetry add tidyparse@2.2.0 and commit pyproject.toml and poetry.lock; that reopens the 2.2.2 memory issue, so treat it as a stopgap.
About 150 words. No package table: two packages fit in a line. No "To confirm": nothing is open.
Why this is MERGE and not MERGE AFTER CHECKS
Every check in the verdict rule is closed with evidence in the reply: both releases read, the one changed behaviour searched and found handled, the calling code run by a PR test, no pins, no install-time code, no new source. Remove any one of those (no repo to search, a release with no notes, a test that does not import app/ingest.py) and the verdict drops to MERGE AFTER CHECKS with that item as the check.
The same shape when it blocks
Suppose instead the PR moved tidyparse to 3.0.0 and the notes (invented for this illustration) said 3.0.0 requires Python 3.11 and parse_rows() now returns a RowSet instead of a list. The reply keeps the order and stays short:
DO NOT MERGE. 3.0.0 needs Python 3.11 and the production image runs 3.10, and the import code indexes a result that is no longer a list.
🟥 1.
Dockerfile:1builds onpython:3.10-slim; CI runs 3.12 (ci.yml:12), so the PR passed and the image build fails at install. Move the image to 3.11 in this PR. 🟥 2.app/ingest.py:17doesrows[0]on what is now aRowSet; no test reads the first row, so CI missed it. Userows.first().Also in the lockfile:
charset-sniff1.4.0 → 1.4.1. Rollback:git revertthe merge commit and rebuild the image.I can make both changes on this branch.
The lead names both blockers; each blocker says what breaks, where, why CI missed it and the fix; nothing is in the reply that does not change the decision.
How it's checked
Measured against plain Claude Code (2026-10-23): it met 65% of its checks, against 41% without it, and a blind judge preferred it. How skills are checked
59 assertions across 7 acceptance evals, and 9 trigger queries. Every skill's checks
What the output must do
When it should and shouldn't activate
Should activate:
- Dependabot wants to bump express from 4.19 to 5.0, can I merge the PR?
- review this Renovate PR, it updates 14 packages in package-lock.json
- is this actions/checkout SHA pin in the dependabot PR actually the v4.2.2 commit?
- I bumped pydantic and regenerated poetry.lock, anything in the lockfile diff I should worry about before merging?
- check this go.mod / go.sum diff from the deps update PR, CI is green
Should leave to another skill:
- review my PR that adds rate limiting to the checkout API before I merge
- write the release notes for our 3.2.0 release from the merged PRs
- plan our migration from React 17 to React 19 across the four frontend apps
- scan the skills I'm about to install for risky scripts
Hands off to
- migration-plan — when the upgrade is a major framework or runtime jump that cannot land as one PR. Plan the staged migration, the compatibility shims and the cutover instead of forcing the bump through.
- pre-merge-review — when the PR also carries hand-written code changes beyond manifests, lockfiles and pins. Review the code change itself with the full correctness, security and quality pass.
Related skills
Source
SKILL.md · the whole folder on GitHub.