Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions .claude/commands/upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ kit's copy against this repo: `uv run /tmp/agentic-dev-kit/scripts/kit_doctor.py
--manifest /tmp/agentic-dev-kit/kit-manifest.json`.

The report gives you, per kit-owned file: `unchanged` / `differs` / `missing` /
`unknown-version`, plus four installation-level checks. **Read all four** — each is a
silent failure mode:
`missing-required` / `unknown-version`, plus four installation-level checks.
**Read all four** — each is a silent failure mode:

- **config schema version** — unversioned or behind means migrations are pending.
- **`paths.engines` resolves to a directory that actually holds engines.** A `✗` here is
Expand Down Expand Up @@ -112,12 +112,36 @@ Work through `kit_doctor`'s file list. You are already on the branch from Step 2
`init.sh` refreshed itself and migrated the config there, so those changes are captured
too. Confirm with `git branch --show-current` before the first copy.

**Install every `missing-required` file first, before any other copy in this step.**
Those are the kit's own libraries — `lib/kitconfig.py` above all, which every Python
engine imports — and refreshing a component on top of an absent one produces a broken
install: `check_doc_budget.py` dies with `ModuleNotFoundError`, and `pr_watch.py` warns
and silently falls back to built-in defaults, leaving the adopter's entire `review.*`
config inert. `kit_doctor` derives this set from the Python import graph, so it is
answering "what do *this* tree's installed components need", not a fixed list.

**Then re-run `kit_doctor` after installing anything.** The set is computed against the
components present *when the report ran*: a file is `missing-required` only if something
that depends on it is already installed. So installing a previously-`missing` engine or
hook can introduce requirements the first report had no reason to classify. Re-run
before you rely on the list again, and treat the report as converged only when a run
that installed nothing still shows no `missing-required`.

- **`missing-required`** → install it. This is the one absent-file case that is **not**
an operator decision: an installed component depends on it, and the report names
which. Do not carry it into the `missing` conversation below.
- **`unchanged`** → copy the new version straight in. It is provably untouched, so there
is nothing to lose.
- **`missing`** → decide, don't assume. A sized-down adoption omits engines deliberately
(one surveyed repo installs 2 of 6 on purpose). Ask the operator whether each missing
piece is wanted before installing it. If a piece stays out, note it in the PR body so
the next upgrade doesn't re-litigate it.
the next upgrade doesn't re-litigate it. Nothing installed here depends on these **by
the graph `kit_doctor` derives**, which is what separates them from the bullet above.
That graph covers **Python imports only** — it does not read shell `source`, so
`lib/repo_root.sh` (which `dev_session.sh` and `reconcile_sessions.sh` both source)
will appear here rather than above. It is a much better prior than the old blanket
"decide, don't assume", not a proof: if a piece you are declining is a library a
shell component plausibly reaches for, check before dropping it.
- **`differs`** → `diff` the local file against the kit's, and read the diff:
- Only kit-authored changes (the local copy is simply older) → replace it.
- Local edits present → for each, find where that value now lives in
Expand Down
24 changes: 23 additions & 1 deletion kit-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,12 @@
},
"scripts/kit_doctor.py": {
"role": "engine",
"sha256": "78ff1093fb5f243b05d0f32b7946552883322f4869bd42730fee3315867d4605"
"sha256": "a70626b4f784f56ec683d2239150a2e39ed866ff0f28f599cc877c4abbf13b6f"
},
"scripts/lib/atomic_write.py": {
"required_by": [
"scripts/archive_plan_sessions.py"
],
"role": "engine",
"sha256": "f9657f36f8bbcf3741382b616ae19be19cf516fc5fa4f36c53384579e96202b3"
},
Expand All @@ -107,6 +110,16 @@
"sha256": "a4c29fb1808e0b3ec0a2ba80ffa97ba6c894f1a784463a5d126169542c300ef2"
},
"scripts/lib/kitconfig.py": {
"required_by": [
"scripts/archive_plan_sessions.py",
"scripts/check_doc_budget.py",
"scripts/check_memory_budget.py",
"scripts/hooks/pr_followup_hook.py",
"scripts/hooks/pre-push",
"scripts/kit_doctor.py",
"scripts/panel_prompt.py",
"scripts/pr_watch.py"
],
"role": "engine",
"sha256": "4ab496661883d8f4ad590a6612a48b31f8cbf770283bb09794096149276634e6"
},
Expand All @@ -119,14 +132,23 @@
"sha256": "691a7df06a3bf9019b5faca8b8ebdb9d54463d231d492a632fd54c16cd51a2c6"
},
"scripts/lib/state_paths/paths.py": {
"required_by": [
"scripts/lib/state_paths/resolver.py"
],
"role": "engine",
"sha256": "f54fd7d970402f8581f6c5080aa9614ce41cb2dafa2010c08406129731799397"
},
"scripts/lib/state_paths/repo_root.py": {
"required_by": [
"scripts/lib/state_paths/resolver.py"
],
"role": "engine",
"sha256": "d9412f1fe395b944a86126bcc39f85d6838382b0fc29d68c8b29b965cd530b5a"
},
"scripts/lib/state_paths/resolver.py": {
"required_by": [
"scripts/lib/state_paths/__init__.py"
],
"role": "engine",
"sha256": "e39fca241d6fbf28596ed3954f28a55e65831181cedb02c7c15e372895bb5bd2"
},
Expand Down
Loading
Loading