Library Updater — keep dependencies current without breaking the build
A disciplined loop for upgrading dependencies: audit what is behind, read what
changed, apply in small reversible batches, test between each batch, and roll
back the instant a batch regresses. The build stays green from start to finish.
⚠️ Critical Constraints
- Never bump everything at once. Batch by risk (patch → minor → major,
smallest first) and test between batches. Why: a single all-in upgrade that
fails gives you no way to know which package broke it, forcing a full revert.
- WRONG:
npm update && npm test (one giant diff, no bisect path)
- CORRECT: patch batch → test → commit → minor batch → test → commit → ...
- The lockfile is part of the change. Always commit the manifest AND the
lockfile together. Why: committing
package.json without package-lock.json
(or go.mod without go.sum) ships a non-reproducible build that resolves
differently on the next machine.
- Read the changelog before a major bump, every time. Why: majors signal
breaking changes by convention; upgrading blind turns a 10-minute read into a
multi-hour debugging session.
- A clean working tree is the precondition, not a nicety. Refuse to start with
uncommitted changes. Why: rollback (
git checkout -- <manifest> <lockfile>)
is only clean when there is nothing else to lose.
- Pinned-for-a-reason stays pinned. Honor existing version pins / ranges and
any
// pinned: <reason> comments. Why: a deliberate hold (known
regression, peer-dep conflict, license) is institutional memory; silently
bumping past it reintroduces a solved problem.
Why This Exists
Dependency drift is silent until it is expensive: security advisories pile up,
majors stack so high the eventual upgrade is a rewrite, and "just update
everything" upgrades fail with no way to tell which package broke. Agents make
this worse by bumping in one shot and declaring victory before tests run. This
skill enforces the only safe shape — small batches, evidence between each,
clean rollback — so currency never costs the build.
Quick Start
# 1. Detect ecosystem + list what is behind (writes outdated.txt)
bash {baseDir}/scripts/audit-deps.sh > outdated.txt
# 2. (after each batch) verify the build still passes for THIS ecosystem
bash {baseDir}/scripts/run-tests.sh # exit 0 = green, non-zero = roll back
# 3. self-check this skill
bash {baseDir}/scripts/validate.sh
Workflow
Phase 0 — Preconditions
- Confirm a clean tree:
git status --porcelain must be empty. If not, stop and
surface it; do not proceed.
- Identify the baseline test command (CI config,
Makefile, package.json
scripts). Record it; it is the gate for every batch.
- Checkpoint: tree clean AND a known-green test command exists.
Phase 1 — Audit (current vs latest)
- Run
scripts/audit-deps.sh to enumerate outdated packages with current →
wanted → latest and the jump type (patch / minor / major).
- Note any pins, ranges, or
pinned: comments — these are excluded from bumping.
- Checkpoint:
outdated.txt lists every candidate with its jump type.
Phase 2 — Plan the batches
- Group candidates into ordered batches: patch, then minor, then each
major individually (majors are never batched together).
- For every major, read its changelog / release notes and record the breaking
changes and required code edits before touching anything.
- Checkpoint: a written batch plan; every major has a changelog summary.
Phase 3 — Apply + test, one batch at a time
- Apply exactly one batch (update manifest + regenerate lockfile).
- Run the baseline test command via
scripts/run-tests.sh.
- Green: commit the manifest + lockfile with a scoped message, then continue.
- Red: roll back this batch only (
git checkout -- <manifest> <lockfile> and
reinstall), record the failure, and either split the batch finer or skip the
offending package. Never carry a red batch forward.
- Checkpoint: after each batch the suite is green and the change is committed.
Phase 4 — Report
- Write
dependency-update-report.md: batches applied, packages bumped with
before→after versions, packages skipped (with reason), rollbacks, and remaining
majors deferred for follow-up.
- Checkpoint: report exists; tree is clean and green.
Output Specification
- Filename:
dependency-update-report.md (repo root or a path the caller gives).
- Format: sections —
Applied (table: package | from → to | jump | batch),
Skipped (package | reason), Rolled back (package | failure), Deferred
(majors needing dedicated work). Each applied batch links its commit SHA.
Quality Rubric
- Every applied batch has a corresponding green test run AND a commit — no batch
is committed without a passing suite.
- Manifest and lockfile are committed together in every batch (verifiable in
git show <sha> --stat).
- Every major version bump cites the changelog section that documents its
breaking changes.
- The report accounts for every outdated package: applied, skipped, rolled back,
or explicitly deferred — none silently dropped.
Examples
npm, mixed jumps. audit-deps.sh finds 6 outdated: 3 patch, 2 minor, 1 major
(react 18→19). Batch 1 (patches) → test green → commit. Batch 2 (minors) →
green → commit. Batch 3 (react major): read the v19 migration notes, apply, fix
the two breaking call sites, test → green → commit. Report records all three.
Rollback path. A minor batch turns the suite red. Run
git checkout -- package.json package-lock.json && npm ci, suite green again.
Bisect: re-apply the minor packages one at a time; lodash 4.17.20→4.17.21 is
the culprit. Skip it, record "skipped: 4.17.21 breaks ", continue.
Troubleshooting
| Symptom |
Likely cause |
Fix |
| Tests red after a batch |
One package in the batch regressed |
Roll back the batch, re-apply packages singly to bisect |
| Lockfile churns with no manifest change |
Transitive resolution drift |
Commit the lockfile-only change as its own batch; test first |
audit-deps.sh finds no manifest |
Unsupported / nested ecosystem |
Run from the project root; pass the manifest dir as $1 |
| Major bump compiles but fails at runtime |
Behavioral breaking change |
Re-read changelog "Breaking" section; this is a code-edit batch, not a version bump |
| Rollback leaves stale installed deps |
Reinstall step skipped |
After git checkout, rerun the install (npm ci / pip install -r / go mod download) |
See Also
scripts/audit-deps.sh — Execute: lists outdated deps with jump types.
scripts/run-tests.sh — Execute: runs the ecosystem's test gate; exit code is the verdict.
scripts/validate.sh — Execute: self-checks this skill's structure and scripts.
1---2name: dependency-update-safety-23description: Use when updating dependencies safely with changelog review, small batches, tests, and rollback. Triggers:4---5# Library Updater — keep dependencies current without breaking the build
6
7A disciplined loop for upgrading dependencies: audit what is behind, read what
8changed, apply in small reversible batches, test between each batch, and roll
9back the instant a batch regresses. The build stays green from start to finish.
10
11## ⚠️ Critical Constraints
12
13- **Never bump everything at once.** Batch by risk (patch → minor → major,
14 smallest first) and test between batches. **Why:** a single all-in upgrade that
15 fails gives you no way to know which package broke it, forcing a full revert.
16 - WRONG: `npm update && npm test` (one giant diff, no bisect path)
17 - CORRECT: patch batch → test → commit → minor batch → test → commit → ...
18- **The lockfile is part of the change.** Always commit the manifest AND the
19 lockfile together. **Why:** committing `package.json` without `package-lock.json`
20 (or `go.mod` without `go.sum`) ships a non-reproducible build that resolves
21 differently on the next machine.
22- **Read the changelog before a major bump, every time.** **Why:** majors signal
23 breaking changes by convention; upgrading blind turns a 10-minute read into a
24 multi-hour debugging session.
25- **A clean working tree is the precondition, not a nicety.** Refuse to start with
26 uncommitted changes. **Why:** rollback (`git checkout -- <manifest> <lockfile>`)
27 is only clean when there is nothing else to lose.
28- **Pinned-for-a-reason stays pinned.** Honor existing version pins / ranges and
29 any `// pinned: <reason>` comments. **Why:** a deliberate hold (known
30 regression, peer-dep conflict, license) is institutional memory; silently
31 bumping past it reintroduces a solved problem.
32
33## Why This Exists
34
35Dependency drift is silent until it is expensive: security advisories pile up,
36majors stack so high the eventual upgrade is a rewrite, and "just update
37everything" upgrades fail with no way to tell which package broke. Agents make
38this worse by bumping in one shot and declaring victory before tests run. This
39skill enforces the only safe shape — small batches, evidence between each,
40clean rollback — so currency never costs the build.
41
42## Quick Start
43
44```bash
45# 1. Detect ecosystem + list what is behind (writes outdated.txt)
46bash {baseDir}/scripts/audit-deps.sh > outdated.txt
47
48# 2. (after each batch) verify the build still passes for THIS ecosystem
49bash {baseDir}/scripts/run-tests.sh # exit 0 = green, non-zero = roll back
50
51# 3. self-check this skill
52bash {baseDir}/scripts/validate.sh
53```
54
55## Workflow
56
57### Phase 0 — Preconditions
58- Confirm a clean tree: `git status --porcelain` must be empty. If not, stop and
59 surface it; do not proceed.
60- Identify the baseline test command (CI config, `Makefile`, `package.json`
61 scripts). Record it; it is the gate for every batch.
62- **Checkpoint:** tree clean AND a known-green test command exists.
63
64### Phase 1 — Audit (current vs latest)
65- Run `scripts/audit-deps.sh` to enumerate outdated packages with current →
66 wanted → latest and the jump type (patch / minor / major).
67- Note any pins, ranges, or `pinned:` comments — these are excluded from bumping.
68- **Checkpoint:** `outdated.txt` lists every candidate with its jump type.
69
70### Phase 2 — Plan the batches
71- Group candidates into ordered batches: **patch**, then **minor**, then **each
72 major individually** (majors are never batched together).
73- For every major, read its changelog / release notes and record the breaking
74 changes and required code edits before touching anything.
75- **Checkpoint:** a written batch plan; every major has a changelog summary.
76
77### Phase 3 — Apply + test, one batch at a time
78- Apply exactly one batch (update manifest + regenerate lockfile).
79- Run the baseline test command via `scripts/run-tests.sh`.
80- **Green:** commit the manifest + lockfile with a scoped message, then continue.
81- **Red:** roll back this batch only (`git checkout -- <manifest> <lockfile>` and
82 reinstall), record the failure, and either split the batch finer or skip the
83 offending package. Never carry a red batch forward.
84- **Checkpoint:** after each batch the suite is green and the change is committed.
85
86### Phase 4 — Report
87- Write `dependency-update-report.md`: batches applied, packages bumped with
88 before→after versions, packages skipped (with reason), rollbacks, and remaining
89 majors deferred for follow-up.
90- **Checkpoint:** report exists; tree is clean and green.
91
92## Output Specification
93
94- **Filename:** `dependency-update-report.md` (repo root or a path the caller gives).
95- **Format:** sections — `Applied` (table: package | from → to | jump | batch),
96 `Skipped` (package | reason), `Rolled back` (package | failure), `Deferred`
97 (majors needing dedicated work). Each applied batch links its commit SHA.
98
99## Quality Rubric
100
101- Every applied batch has a corresponding green test run AND a commit — no batch
102 is committed without a passing suite.
103- Manifest and lockfile are committed together in every batch (verifiable in
104 `git show <sha> --stat`).
105- Every major version bump cites the changelog section that documents its
106 breaking changes.
107- The report accounts for every outdated package: applied, skipped, rolled back,
108 or explicitly deferred — none silently dropped.
109
110## Examples
111
112**npm, mixed jumps.** `audit-deps.sh` finds 6 outdated: 3 patch, 2 minor, 1 major
113(`react 18→19`). Batch 1 (patches) → test green → commit. Batch 2 (minors) →
114green → commit. Batch 3 (react major): read the v19 migration notes, apply, fix
115the two breaking call sites, test → green → commit. Report records all three.
116
117**Rollback path.** A minor batch turns the suite red. Run
118`git checkout -- package.json package-lock.json && npm ci`, suite green again.
119Bisect: re-apply the minor packages one at a time; `lodash 4.17.20→4.17.21` is
120the culprit. Skip it, record "skipped: 4.17.21 breaks <test>", continue.
121
122## Troubleshooting
123
124| Symptom | Likely cause | Fix |
125| --- | --- | --- |
126| Tests red after a batch | One package in the batch regressed | Roll back the batch, re-apply packages singly to bisect |
127| Lockfile churns with no manifest change | Transitive resolution drift | Commit the lockfile-only change as its own batch; test first |
128| `audit-deps.sh` finds no manifest | Unsupported / nested ecosystem | Run from the project root; pass the manifest dir as `$1` |
129| Major bump compiles but fails at runtime | Behavioral breaking change | Re-read changelog "Breaking" section; this is a code-edit batch, not a version bump |
130| Rollback leaves stale installed deps | Reinstall step skipped | After `git checkout`, rerun the install (`npm ci` / `pip install -r` / `go mod download`) |
131
132## See Also
133
134- `scripts/audit-deps.sh` — **Execute**: lists outdated deps with jump types.
135- `scripts/run-tests.sh` — **Execute**: runs the ecosystem's test gate; exit code is the verdict.
136- `scripts/validate.sh` — **Execute**: self-checks this skill's structure and scripts.