Update or re-adapt the feature-flow kit in a project that was ALREADY bootstrapped, without
clobbering your local adaptations — the safe path for both a newer kit version and a plain
re-adapt after structural changes. Does a 3-way merge (manifest baseline vs your files vs the
staged version), asks only on real conflicts, never touches project-owned files (PROJECT.md,
CONTEXT.md, docs/adr/, backlog), then re-runs the bootstrap re-adapt inline so
settings/hooks/rules refresh in the same pass. B...
Installs into .claude/skills of the current project.
Are you the author of Update Kit?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/mik2win-update-kit)
---
name: update-kit
disable-model-invocation: true
description: |
Update or re-adapt the feature-flow kit in a project that was ALREADY bootstrapped, without
clobbering your local adaptations — the safe path for both a newer kit version and a plain
re-adapt after structural changes. Does a 3-way merge (manifest baseline vs your files vs the
staged version), asks only on real conflicts, never touches project-owned files (PROJECT.md,
CONTEXT.md, docs/adr/, backlog), then re-runs the bootstrap re-adapt inline so
settings/hooks/rules refresh in the same pass. Backs up first and asks keep-or-rollback.
Trigger when the user says "update the kit", "pull a newer kit version", "sync the kit",
"re-adapt the kit", "/update-kit", "/sync-kit", drops a new kit version into
.claude/.kit-incoming/, or runs /bootstrap on a project that's already adapted (bootstrap
hands off here). DO NOT TRIGGER for the FIRST install of the kit (use /bootstrap), or to
remove it (/teardown).
allowed-tools: Read, Grep, Glob, Bash, Write, Edit, AskUserQuestion
effort: high
---
# /update-kit — pull a newer kit version into an already-bootstrapped project
The kit is a **copy-in bundle**, so a newer version can't auto-update itself, and re-copying it
over `.claude/` would clobber any skill you adapted. This skill is the safe path for **any
post-install adaptation** — a version bump *or* a plain re-adapt after structural changes. It
brings in the staged kit, **3-way merges** it against your local copy, resolves conflicts with
you, then re-adapts — all in **one run**. (`/bootstrap` is the front door: on an already-adapted
project it hands off here; you can also run `/update-kit` directly.) A same-version re-adapt is
just the degenerate case where everything merges quietly and only the re-adapt step does work.
Work top-to-bottom, naming each phase as you enter it — the phase headings below **are** the
checklist, and none is optional. A merge run that loses its place re-litigates a conflict the
user already resolved. New kit source: `$ARGUMENTS` (a path), or
the pre-staged `.claude/.kit-incoming/` if no path is given.
---
## The model: 3-way, not 2-way
A plain "copy and compare" is a 2-way diff (mine vs theirs) — it can't tell *"I adapted this"*
from *"the kit changed this upstream"*; both just look different. To merge safely you need a third
reference, the **BASE**: what the kit file was when it was last installed. The kit records that in
a content-hash manifest, so this works even when `.claude/` is gitignored (git is **not** used).
- **BASE** — `sha256` per file from `.claude/.kit-manifest.json` (last install/update).
- **MINE** — the file currently in `.claude/`.
- **THEIRS** — the same file in the new kit source (staged).
### Which files this merges (class A)
Only the **persistent, pristine-by-default kit files**:
`skills/**` (kit skills), `agents/**`, `hooks/**` **except `guard-bash.sh`**, `rules/_generic/**`,
`output-styles/**`, `schemas/**`, `docs/**` (kit docs — `docs/adr/` is project-owned, see below).
**Carve-out inside class A: a rule's `paths:` frontmatter is project-owned.** `/bootstrap`
narrows each installed rule's globs to the project's real layout (Phase 5.2), so THEIRS carries
the kit's `"**/*"` *template default* while MINE carries the deliberate project scope. Merge the
rule **body** normally and **keep MINE's `paths:` block** — taking THEIRS silently re-widens the
rule to every file touch and quietly inflates the standing context budget, which is the kind of
regression nobody notices until a session is paying for rules it never needed. Surface it instead:
when THEIRS changes a `paths:` block, report it as a **suggested** re-scope with both globs shown,
and let the user apply it. Same treatment for a rule that gains or loses `paths:` entirely — moving
a rule into or out of the always-on set is a context-budget decision, not a file sync.
Everything else falls out naturally and is **not** file-merged:
- **Project-owned (never touched):** `.claude/PROJECT.md`, `CONTEXT.md`, `docs/adr/`, the backlog,
and any project-specific skill/agent the user created — these aren't in the kit source at all, so
the sync physically can't reach them. A path under `.claude/` that is **absent from the manifest**
is project-owned by definition — leave it.
- **Mixed (kit template + project inserts) → regenerated by re-adapt, not merged:**
`.claude/settings.json`, `.claude/hooks/guard-bash.sh`, `CLAUDE.md`, `.gitignore`. The kit's
templates for these (`settings.template.json`, `CLAUDE.snippet.md`) and the placeholder
`guard-bash.sh` come in THEIRS only to feed the re-adapt phase.
- **Build-time (staged for re-adapt, then cleaned):** `_kit/**`, `*.template.*`,
`CLAUDE.snippet.md`, `settings.stop-gate.example.json`.
---
## Phase 0 — Preconditions & staging the new version
1. Confirm this project is **already bootstrapped**: `.claude/PROJECT.md` exists with
`profile_status: ACTIVE`. If it's missing or still `TEMPLATE`, STOP — tell the user to run
`/bootstrap` first (this skill updates an existing install; it is not the first install).
2. Stage **THEIRS**:
- If `$ARGUMENTS` is a path to a new kit checkout, copy it into the staging dir, excluding the
kit's own dev dirs:
```bash
mkdir -p .claude/.kit-incoming
rsync -a --delete --exclude='.git' --exclude='.claude' --exclude='.claude copy' \
--exclude='_backlog' --exclude='guide' "$ARGUMENTS"/ .claude/.kit-incoming/
```
- Else if `.claude/.kit-incoming/` already exists (the user dropped it there manually), use it.
- Else STOP and tell the user: drop the new kit version into `.claude/.kit-incoming/` (or pass
its path), then re-run.
3. Sanity-check the staged source looks like the kit (`.kit-incoming/_kit/KIT.md` and
`.kit-incoming/skills/` present). If not, stop and report.
## Phase 0.5 — Back up before any writes
Same mechanism as `/bootstrap` Phase 0.5 — reuse it so backup/rollback behave identically:
```bash
TS=$(date +%Y%m%d-%H%M%S); BK=".claude/.bootstrap-backup/$TS"; mkdir -p "$BK"
: > "$BK/created.txt" # paths this run newly creates — for a clean rollback
```
Back up every class-A file **before** you overwrite it (mkdir its parent under `$BK`, `cp -p`).
Append each **newly created** path to `$BK/created.txt`. On re-run, add a new snapshot — never
delete earlier ones.
## Phase 1 — Load the baseline (BASE)
Read `.claude/.kit-manifest.json`. Define a hash helper:
```bash
hashof() { shasum -a 256 "$1" 2>/dev/null | cut -d' ' -f1 || sha256sum "$1" | cut -d' ' -f1; }
```
- **Manifest present** → full 3-way (the normal, quiet path). Also read its optional `excluded`
array — kit paths this project removed on purpose (e.g. an agent replaced by a project-owned
one). Phase 2 skips them entirely.
- **Manifest absent** (a legacy project bootstrapped before manifests existed) → **degraded 2-way
mode**: there is no BASE, so any class-A file that differs from THEIRS becomes a conflict to ask
about (can't auto-tell adapted from upstream-changed). **Warn the user** it'll be noisier this
once, and that Phase 6 writes a manifest so future updates are quiet.
## Phase 2 — Classify
Enumerate the class-A paths present in `.kit-incoming/` (the list above; **exclude
`hooks/guard-bash.sh`** and every path in the manifest's `excluded`). For each, compute BASE (from manifest), MINE (`hashof` the local file if
present), THEIRS (`hashof` the staged file). Bucket by this matrix:
| BASE | MINE | THEIRS | Verdict | Action |
|---|---|---|---|---|
| present | == BASE | any | untouched locally | **take-new** (quiet) |
| present | != BASE | == BASE | you edited, kit didn't | **keep-mine** (quiet) |
| present | != BASE | == MINE | converged | **take-new** (quiet) |
| present | != BASE | != BASE, != MINE | **real conflict** | → Phase 3 |
| — (absent) | absent | present | new kit file | **add** (quiet) |
| present | absent | present | you deleted a kit file | ask: **re-add**, or **exclude** for good (move the path from `files` to `excluded`) |
| present | present | absent (gone upstream) | removed upstream | offer **delete** (confirm) |
A path in `excluded` never reaches this matrix: without the list, a removed kit file whose entry
is dropped from `files` reads as *new kit file* and is silently re-added on the next run, and one
whose entry is kept is asked about on every run.
In **degraded 2-way mode** collapse to: `MINE == THEIRS` → nothing; `MINE` absent → add;
`THEIRS` absent → offer delete; otherwise → **conflict** (Phase 3).
Produce two lists: **quiet actions** and **conflicts**.
## Phase 3 — Resolve conflicts (one batch of focused questions)
For each conflict show a short diff (MINE vs THEIRS; mention if THEIRS also moved from BASE) and
ask via `AskUserQuestion`: **take-new** / **keep-mine** / **merge** (hand-combine — you do the
edit, preserving the user's intent and the new upstream improvement).
For an adapted **skill** specifically, add the kit's guidance so the conflict stops recurring:
- *General improvement* (useful in any project) → **upstream it**: keep your version now, and open a
change in the kit repo so the next release carries it.
- *Genuinely project-specific* → **rename it** to a project-owned skill (a name not in the manifest);
then kit updates will never collide with it again, per the kit's design (skills stay invariant;
project specifics live in `PROJECT.md`/rules or in project-owned skills).
Group related conflicts; don't ask twenty separate questions when a few grouped ones cover it.
## Phase 4 — Apply the file merge
Apply the resolved class-A actions: **take-new** (copy THEIRS over MINE), **merge** (write the
combined file), **add** (copy new file), **delete** (remove, confirmed). Back up each overwritten
file into `$BK` first; log each newly created path to `$BK/created.txt`. **Do not** touch class-B
(project-owned) or class-C (mixed) files here — class C is the next phase's job.
Stage the build-time inputs the re-adapt needs, logging them as created:
`cp -R .claude/.kit-incoming/_kit .claude/_kit` and copy the contracts
(`PROJECT.template.md`, `settings.template.json`, `CLAUDE.snippet.md`,
`settings.stop-gate.example.json`) into `.claude/`.
## Phase 5 — Re-adapt (inline, automatic — no separate command)
Within this same run, perform the bootstrap re-adapt so settings/hooks/rules refresh against the
new version. **Follow `skills/bootstrap/SKILL.md` Phases 3–6** against the freshly staged `.claude/_kit`
and contracts (it sees `profile_status: ACTIVE`, so it updates in place):
- re-select & **reconcile** stack rule packs, **reusing the decisions already recorded in
`PROJECT.md` → "Rules notes"** (don't re-ask what's already answered);
- regenerate `.claude/settings.json` from the new template + the profile's permissions;
- regenerate `.claude/hooks/guard-bash.sh` (kit regions from the new version + the project's
`__BOOTSTRAP_PROJECT_BLOCKS__` from the deny decisions; keep `__VCS_PUBLISH_BLOCKS__` per policy);
- replace the `feature-flow-kit:begin…end` block in `CLAUDE.md` and in `.gitignore`.
Do **not** re-interview the domain or re-touch `PROJECT.md` content beyond what reconcile records;
leave `CONTEXT.md`, `docs/adr/`, and the backlog alone (bootstrap already treats them as project-owned).
## Phase 6 — Write the new manifest (new BASE)
Record, for every class-A path this run kept in sync, the hash of **THEIRS — the staged kit file
as the kit shipped it**, not the local copy, and write `.claude/.kit-manifest.json`:
```json
{
"kit_version": "<from .kit-incoming/_kit/KIT.md version or the date>",
"installed_at": "<ISO-8601>",
"files": { "skills/analyst/SKILL.md": "<sha256 of .kit-incoming/skills/analyst/SKILL.md>", "...": "..." },
"excluded": ["agents/<removed-on-purpose>.md"]
}
```
BASE means *the kit version this project last merged*. For a pristine file THEIRS and the local
copy hash the same, so nothing changes; the difference is every **adapted** file — a merge, a
keep-mine, a narrowed `paths:` block. Hash the local copy there and the next run reads it as
*MINE == BASE → untouched locally → take-new*, and silently overwrites the adaptation this run just
preserved. Hashing THEIRS keeps it reading as *MINE != BASE*, so it stays keep-mine until the kit
changes it, and then it is a conflict you are asked about. Carry `excluded` forward, plus any path
the user chose to exclude in Phase 2. Check before writing: every adapted file must still differ
from its recorded hash — if one does not, you hashed the wrong copy.
## Phase 7 — Report & next step
Output:
- **File merge:** a table per class-A path — `unchanged · updated · merged · added · deleted ·
kept-yours · excluded · skipped(project-owned)`.
- **New paths-scoped rules:** any rule that arrived new with template `paths:` (`sql.md` is the
first) needs the narrowing `/bootstrap` does — name it and this project's DB directories.
- **Re-adapt:** what bootstrap regenerated (settings/hooks/CLAUDE.md/.gitignore) and the
reconciliation summary.
- **To upstream:** the adapted skills you chose to keep that are worth contributing back to the kit repo.
- **Next step:** smoke-test — run `/analyst` (it should read the refreshed profile) and the
profile's `test` command; if anything looks off, you can still roll back (Phase 8).
- **Re-check hook registration.** This run may have rewritten `settings.json` hook entries, and a
hook that failed to register is indistinguishable from a silent one. `/hooks` → non-zero count
per event + source label = your settings file; when `/hooks` is unavailable (TUI-only), provoke
a hook into output and look for an `attachment` / `hook_success` record carrying `command` in
the session transcript. Procedure: `_kit/KIT.md` § Hook & permission configuration.
## Phase 8 — Keep or roll back (ask)
Ask via `AskUserQuestion`: **Keep** or **Roll back** (identical to `/bootstrap` Phase 8).
- **Keep** → Phase 9.
- **Roll back** → undo this run from `$BK`: delete every path in `$BK/created.txt`, restore every
backed-up file, strip any `feature-flow-kit` block this run added to a file it created. Leave
`.kit-incoming/` so the user can retry. Report exactly what was undone.
## Phase 9 — Clean up (ask first)
After the user keeps the result, remove the build-time material this run staged (same as
`/bootstrap` Phase 9): `rm -rf .claude/_kit`, delete `.claude/*.template.*`,
`.claude/CLAUDE.snippet.md`, `.claude/settings.stop-gate.example.json`, and `.claude/.kit-incoming/`.
Offer to prune old `.claude/.bootstrap-backup/*` snapshots. Leave a clean `.claude/` plus the
updated `.kit-manifest.json`.
---
## Hard rules
- **Single command.** One `/update-kit` run does load-new + merge-old + re-adapt. Never make the
user run `/bootstrap` separately afterward.
- **3-way, not 2-way.** Use the manifest BASE; only a genuine BASE≠MINE≠THEIRS divergence is a
conflict worth a question. Quiet on everything else.
- **BASE is the kit's file, never yours.** The new manifest records THEIRS hashes (Phase 6) — a
local hash there turns every adaptation into a silent overwrite on the next run.
- **Exclusions are durable.** A path in `excluded` is never added, re-added, merged, or asked about.
- **Project-owned is sacred.** Anything not in the manifest is the project's — never overwrite
`PROJECT.md`, `CONTEXT.md`, `docs/adr/`, the backlog, or user-created skills/agents.
- **Idempotent.** Re-running with the same source yields zero conflicts and zero changes.
- **Reversible.** Back up before writing; confirm keep-or-rollback before cleanup; a rolled-back
run leaves no trace.
- **No git dependency.** Detection is hash-based so it works when `.claude/` is gitignored.
## See also
- **`/bootstrap`** — first install + the re-adapt phases this skill calls inline.
- **`/teardown`** — remove the kit or its leftovers (also cleans `.kit-incoming/` and the manifest).
- **`/writing-skills`** — when an adapted skill should be upstreamed into the kit.