@sabaiway/agent-workflow-kit 11.0.0 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,120 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
4
4
  is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
5
5
  every `migrations/<version>-<slug>.md` newer than it, in semver order.
6
6
 
7
+ ## 11.2.0 — a field report is triaged through a rendered procedure over a checked record (AD-132)
8
+
9
+ Three consumer field reports were triaged ad hoc — verify each claim on HEAD, record the verdict,
10
+ queue with a hand ratchet bump — with no record shape, no anchor check and nothing rendering the
11
+ steps. The answer is not a skill: a fourth activity, a record grammar a checker can refuse, and a
12
+ procedure the advisor renders. Contract: `docs/ai/specs/kit/feedback-triage.md` (live, S1–S15 bound).
13
+
14
+ **The fourth activity.** `ACTIVITIES` in `tools/carriers.mjs` gains `feedback-triage` with ONE slot,
15
+ `review`, and `policy: false` — a chore inside a session like `routine`; no `carrier` slot, no
16
+ autonomy block. `procedures feedback-triage` renders the engine's canon section verbatim (Record ·
17
+ Verify · Check · review {recipe} · Rows · Fold; Definition of Done: a checked record, its rows in the
18
+ queue, the ratchet moved by exactly the rows rendered). Every activity list names it (four mode docs name
19
+ it and `recommendations.md` carries the count, both READMEs, the engine SKILL and README, the methodology slot — the outgoing three-activity
20
+ fragment joins `KNOWN_PRIOR_METHODOLOGY_SLOT`); `set-recipe`, `recipes`, `status` and the registry
21
+ survey take the slot; the golden active-recipes line carries `feedback-triage.review = reviewed`
22
+ (computed default); the tarball pin counts 287.
23
+
24
+ **The record and its checker.** `docs/plans/FEEDBACK-<date>-<slug>.md` — scratch by the in-flight-plan
25
+ prefix — is one grammar, version 1: `# Feedback:` title, `Source:`, `Head: <object id>`, `## Claims`
26
+ and ONE pipe table (`#` · claim · backticked `path:line[-line]` anchors · `confirmed` / `corrected` /
27
+ `refuted` / `works-as-designed` · `queue <ROW-ID>` / `already-queued <ROW-ID>` / `declined: <reason>` /
28
+ `folded: <reason>`), optional `## Notes`. `tools/feedback-record.mjs` (the pure half: parse, judge,
29
+ render rows, render excerpts, the ratchet line — imports nothing) and `tools/feedback-record-cli.mjs`
30
+ (`--check <record>`, `--check <record> --excerpts <out>`, `--rows <record>`; `main(argv, deps)` never
31
+ exits). `--check` reads the record and every anchor no-follow and capped, realpath-contained under
32
+ the cwd, decodes fatally, compares `Head:` to `git rev-parse HEAD` under the git-location leaf with
33
+ `GIT_OPTIONAL_LOCKS=0`, then proves tracking POSITIVELY: each anchor's LEXICAL git-top-relative path
34
+ rides ONE `git status --porcelain -z` and ONE `git ls-files -v -z` as the pathspec `:(literal)<rel>`
35
+ — a rel the index does not list is `anchor-dirty` "not tracked at the stamped HEAD" (`.git/config`,
36
+ an untracked file, a path through a symlinked parent), a tag other than `H` is `anchor-dirty` behind
37
+ a concealing index bit, `H` with a status entry "differs", `H` and clean is proof. Every defect has
38
+ one name from a closed set (`title` · `source` · `head` · `table` · `row-cells` · `claim-id` ·
39
+ `anchor-grammar` · `anchor-path` · `verdict` · `disposition` · `anchor-absent` · `anchor-unreadable`
40
+ · `anchor-line` · `anchor-dirty` · `git-location` · `head-mismatch` · `excerpts-destination` ·
41
+ `excerpts-budget` · `excerpts-write` · `EEXIST`): a structural defect (title, source, head, table)
42
+ ends the read with its name, a row defect is listed per row and an anchor finding per anchor —
43
+ never the first only. Exit 0 accept · 1 findings · 2 usage. `--excerpts` writes the verbatim anchor lines — the `--facts` payload of
44
+ the record's agy review — under `grounding.mjs`'s scratch-destination guard with an exclusive create,
45
+ budgeted at `DEFAULT_MAX_PROMPT_BYTES` minus the record minus `EXCERPTS_FRAMING_RESERVE_BYTES` (4096),
46
+ each text split once, the walk stopped at the budget, tail-trimmed through `trimToBudget`; a text
47
+ that would not begin with an excerpt line is `excerpts-budget`, nothing written. `--rows` prints one
48
+ skeleton queue row per distinct `queue <ROW-ID>` and the `--max-rows` ratchet line read from the git
49
+ top's `docs/ai/gates.json`. Suites: `feedback-record.test.mjs`, `feedback-record-cli.test.mjs`,
50
+ `feedback-record-cli-anchors.test.mjs` (the S9 state table) over the shared
51
+ `feedback-record-cli-harness.test.mjs`.
52
+
53
+ **The advisor renders the record as the review artifact.** For `feedback-triage` the procedures
54
+ advisor suppresses the driving contracts and the grounding pre-step and renders, after the slot's
55
+ reason, the check line with `--excerpts`, then one line per review member — `codex-review plan
56
+ <record>`, `agy-review plan <record> --facts @<facts>`, a ready lens's brief over the record plus the
57
+ excerpts, a skipped line for a not-ready member — and `review-rounds-cli --artifact <record>
58
+ --activity feedback-triage` followed by the persisted-obligation fact whenever the slot carries a
59
+ bridge obligation (a lens-only roster gets the no-receipt fact); `<record>` and `<facts>` stay
60
+ literal. The JSON key is `feedbackTriage`; the lens survey seam is `ctx.surveyLens ?? ((spec) => …)`.
61
+
62
+ **The seed note.** The canonical `_README` names four activities and states the defaults honestly —
63
+ the seed keeps its two-activity shape, so `feedback-triage.review` is silent and "reviewed as soon as
64
+ a review backend is ready (solo until then)"; the outgoing four-activity note joins
65
+ `KNOWN_PRIOR_README` and both seed twins carry the canonical byte for byte.
66
+
67
+ **Recorded tech debt (queue).** The note's "every slot seeded below" clause is a claim about the file;
68
+ the plain-`solo` render of the activity; the status flags decide nothing after the positive proof;
69
+ the registry suite walks one direction only; the import-boundary pin's grammar; S1's wording; a
70
+ submodule anchor reads "not tracked"; `status` / Recommendations drop `r.roster`; the `--kit-tools`
71
+ tier cannot take the checker.
72
+
73
+ ## 11.1.0 — the bootstrap offers enforcement on every project, and the advisor closes the loop (AD-131)
74
+
75
+ Bootstrap steps 8–9 (the enforcement scripts + the pre-commit hook) used to decide by the step-1
76
+ recon — a Python, Go or Rust project was denied the caps gate, the archivers and the hook for no
77
+ proven reason, then `upgrade` reported `skipped-no-node-evidence` on the very tree the bootstrap left
78
+ bare. The scripts are dependency-free Node the agent host already runs for step 7's navigator.
79
+ Contract: `node-evidence.md` rev 2 (S8–S10 bound).
80
+
81
+ **The offer, on every project.** `references/modes/bootstrap.md` steps 8–9 offer the scripts and the
82
+ hook preview-first with a one-line why: the bootstrap seeds on `package-json` OR
83
+ `deployed-node-scripts` OR the fact that the agent host is running the kit; the only skip condition
84
+ is that the agent host cannot run them; the residual is stated (the hook runs `node scripts/<x>.mjs`,
85
+ so a committer without `node` on PATH gets the hook's own loud failure). `deploy-tail.md` carries the
86
+ same sentence once; the Windsurf launcher's step list names the offer once and copies nothing
87
+ unconditionally; the by-hand "Non-Node projects follow the policy by hand" claims left the READMEs.
88
+ The step-1 recon is a stack fact, never the criterion.
89
+
90
+ **The advisor's `enforcement` item.** On a `docs/ai` tree whose node evidence answers `none` and
91
+ whose `scripts/` is absent or holds no basename of the kit's own bundle (listed at run time through
92
+ the probe's own `scriptsBundleRoot` seam, never a hardcoded list), Recommendations renders ONE
93
+ optional offer: the exact bootstrap tail as a `HAND-APPLY:` line with both paths shell-quoted.
94
+ Every other cell is silence or a stated skip naming the path — `package-json` /
95
+ `deployed-node-scripts` render nothing and never list the bundle; a wrong-kind path, an unreadable
96
+ probe (`<root>: <code> on <rel>`), an existing, linked or unreadable destination each skip by name;
97
+ no `docs/ai` renders nothing. The probe spawns no git; the installer's refusal over a hook it did not
98
+ write is stated in the posture note (pinned). The commit-guard item's installer-absent skip carries
99
+ its own 155-char remedy (deploy the scripts, bootstrap steps 8–9, install the hook, re-run) on ANY
100
+ evidence — never "run upgrade first".
101
+
102
+ **A declined offer leaves no false claim.** Every install claim in the family is conditional on
103
+ the yes — `installed on a yes` in the READMEs and the seeded `changelog.md` / `decisions.md`
104
+ templates, `where installed` in the seeded `agent_rules.md`, `and the enforcement offer was
105
+ accepted` in both visibility contracts — pinned by one (file, literal, count) table in
106
+ `test/enforcement-offer-docs.test.mjs`; the visible wiring of `package.json` scripts is conditional
107
+ on an existing `package.json` AND an accepted offer; on a no the docs command slots of
108
+ `env_commands.md` and `AGENTS.md` carry a note (the caps + index gate run from the agent's own skill
109
+ copy; the archive rotations need the scripts deployed) and never the skill's absolute path.
110
+
111
+ **Pins, unchanged scripts.** The deployed scripts' basename fallback (no or a malformed
112
+ `package.json` → the directory basename) was already there — `install-git-hooks.test.mjs` and
113
+ `archiver-structure.test.mjs` pin it with a package.json-named control; no script changed.
114
+
115
+ **Measured on itself (the first-pass-quality series' acceptance metric).** Executed delegated on ONE
116
+ held codex session, eight accounted dispatches, every fold through it. Diff council: round 1 codex
117
+ revise 0 blockers + 3 majors, agy SHIP, lens 0 + 2 majors; rounds 2–3 resolved the decline-path
118
+ subarea at altitude; round 4 CLEAN from all three — four rounds against the 13-round baseline
119
+ (AD-130). Three fold-induced findings, each caught by a test or gate before a receipt attested it.
120
+
7
121
  ## 11.0.0 — the per-fold walk is a record, the cap is a refusal at the round table's own signal, and the fingerprint argv has one home (AD-130)
8
122
 
9
123
  Plan 2's two attestation rounds on CONVERGED bytes each found one member of the kit's own robustness
package/README.md CHANGED
@@ -117,12 +117,12 @@ your-repo/
117
117
  ├── tech_reference.md ← configs & patterns
118
118
  ├── pages/ ← one spec per page/route
119
119
  └── history/ ← changelog archive (HOT→WARM→COLD)
120
- + scripts/ ← caps · index · archive (Node path)
121
- + pre-commit hook ← keeps it all honest (Node path)
120
+ + scripts/ ← caps · index · archive (installed on a yes)
121
+ + pre-commit hook ← keeps it all honest (installed on a yes)
122
122
  ```
123
123
 
124
124
  The Markdown memory is **stack-agnostic**; the `scripts/` + pre-commit hook are the **Node path**
125
- (dependency-free, `node --test`). Non-Node projects keep the same policy by hand.
125
+ (dependency-free, `node --test`). They are offered on every project because the agent host runs them; a committer without Node on PATH gets a loud hook failure.
126
126
 
127
127
  Two **visibility** modes, chosen at deploy time: **visible** (committed with the repo) or **hidden**
128
128
  (same files in-tree but git-ignored via the project-local `.git/info/exclude`, so the repo "looks
@@ -225,15 +225,15 @@ file), or run the guarded `/agent-workflow-kit uninstall`.
225
225
 
226
226
  | Command | When | What happens |
227
227
  |---------|------|--------------|
228
- | `/agent-workflow-kit` | new / empty project | recon → **asks visible-or-hidden** + **conversational language** + **agent attribution** (default off) → deploys `AGENTS.md` + `docs/ai/` filled with real recon data → installs enforcement → **asks before committing** |
228
+ | `/agent-workflow-kit` | new / empty project | recon → **asks visible-or-hidden** + **conversational language** + **agent attribution** (default off) → deploys `AGENTS.md` + `docs/ai/` filled with real recon data → offers enforcement (installed on a yes) → **asks before committing** |
229
229
  | `/agent-workflow-kit upgrade` | existing deployment | reads `docs/ai/.workflow-version`, shows the changelog diff, preserves your authored memory, applies migrations, re-stamps — then prints a **read-only** one-line backend-status line (what's set up vs missing); refreshes the already-placed bridges from the kit's bundled copies (never installs a new one — set one up with `/agent-workflow-kit setup`) |
230
230
  | `/agent-workflow-kit help` | any time | **read-only command index** — every command, grouped (Inspect / Configure / Orchestrate / Lifecycle) and tagged read-only / writer / guarded. The discoverable entry point, and where any unrecognized invocation lands (always read-only — a garbage invocation never writes). Never writes, never commits, never runs a subscription CLI. |
231
231
  | `/agent-workflow-kit backends` | any time | **read-only** check of the optional execution-backends (the `codex` / `agy` bridges): what's set up vs missing and the next step. Never writes, never commits, never runs a subscription CLI (credentials = marker-file presence, not a live login). |
232
232
  | `/agent-workflow-kit gates` | any time | **project gate runner** — runs the verification commands **your project itself declares** in `docs/ai/gates.json` (seeded at deploy; hand-editable `{ id, title, cmd }` entries plus the optional boolean `lcovProducer`, each `cmd` one bash line) as one batch: a per-gate **PASS/FAIL table** + one machine-readable summary line, exit 0 iff all green; a failing gate's own output is shown verbatim; `--only <id>` re-runs one. Honest distinct outcomes for a missing / empty / malformed declaration — never a silent green. The runner writes nothing **by default** and never commits — opt-in `--final` runs the FULL declared matrix and mints ONE final-run receipt into the git-dir core-evidence store (status green/red, pre/post tree fingerprints, the declaration, the consumed lcov's sha; the receipt the commit-guard binds); it executes only your own declared commands (a batching convenience, not a sandbox). The velocity tier auto-approves only the exact no-`--final` form — the recording run stays explicit. |
233
233
  | `/agent-workflow-kit setup [backend]` | opt-in, any time | **link-only** auto-setup of a bridge: places the bundled bridge skill (only into an absent / empty / managed dir — never overwrites an unmanaged one) + links its wrappers onto `PATH` via managed symlinks (idempotent; refuses to clobber a non-symlink; try `--dry-run` to preview). The binary install + the one-time subscription login stay **manual**: it prints the exact **login** command and points the binary install at each bridge's `setup/README.md`. POSIX wrappers — on Windows use WSL. Never commits, never runs a subscription CLI. |
234
234
  | `/agent-workflow-kit status` | any time | **read-only** single view of **versions + deployment + settings + bridges**: which members (kit / memory / engine / the two bridges) are installed and at what version (with an honest "installed on this machine" note when one is behind) and — in a project — what's deployed (`docs/ai`, the version stamps, and the **visibility**: visible / hidden / unclear), and the **feature-spec adoption state** (`not adopted` / `adopting (N draft)` / `adopted (N live, M draft)` / `could not be read`, plus `declined` when recorded), plus your settings (orchestration recipes, attribution, velocity) and the bridges' readiness. The two version axes (package number vs deployment-structure head) stay decoupled. Never writes, never commits, never runs a subscription CLI. |
235
- | `/agent-workflow-kit recipes` | any time | **read-only** orchestration advisor: presents five named recipes for composing the carriers of a step — the bridges and the full-tool executor subagent — into plan → execute → review — **Solo / Reviewed / Council / Delegated / Subagent** — plans + recommends one for your environment (degrading with a stated reason when a backend isn't ready, or when the executor vehicle is missing/unusable), and offers the choice. The activity/slot registry (three activities) is rendered by `procedures` and by `set-recipe --help`. The orchestrator runs it via the bridge skills or the executor vehicle and **always commits**; the kit never executes a recipe, never runs a subscription CLI, never commits. |
236
- | `/agent-workflow-kit procedures <activity>` | any time | **read-only** activity-procedures advisor: prints a named activity's ordered steps (`plan-authoring` / `plan-execution` / `routine`) read **live** from the engine, plus the **resolved recipe per slot** from your `docs/ai/orchestration.json` (agent-writable via `set-recipe`, or hand-edited) + carrier readiness (`plan-authoring`: author, fold, review; default Reviewed when a backend is ready, Council on request; slot-aware incl. Delegated and Subagent) — and, for every dispatched backend, the **full driving contract at the point of use** (exact copy-pasteable invocation, grounding levers like agy's `--facts`/`--decided`, the round-2 `--continue` delta, guarded passthrough), verbatim from the bridge manifests (drift-guarded; each wrapper's `--help` prints the same). `--override <slot>=<value>` adjusts one slot per run. Composes with `recipes`; never writes, never commits, never runs a subscription CLI. |
235
+ | `/agent-workflow-kit recipes` | any time | **read-only** orchestration advisor: presents five named recipes for composing the carriers of a step — the bridges and the full-tool executor subagent — into plan → execute → review — **Solo / Reviewed / Council / Delegated / Subagent** — plans + recommends one for your environment (degrading with a stated reason when a backend isn't ready, or when the executor vehicle is missing/unusable), and offers the choice. The activity/slot registry (four activities) is rendered by `procedures` and by `set-recipe --help`. The orchestrator runs it via the bridge skills or the executor vehicle and **always commits**; the kit never executes a recipe, never runs a subscription CLI, never commits. |
236
+ | `/agent-workflow-kit procedures <activity>` | any time | **read-only** activity-procedures advisor: prints a named activity's ordered steps (`plan-authoring` / `plan-execution` / `routine` / `feedback-triage`) read **live** from the engine, plus the **resolved recipe per slot** from your `docs/ai/orchestration.json` (agent-writable via `set-recipe`, or hand-edited) + carrier readiness (`plan-authoring`: author, fold, review; default Reviewed when a backend is ready, Council on request; slot-aware incl. Delegated and Subagent) — and, for every dispatched backend, the **full driving contract at the point of use** (exact copy-pasteable invocation, grounding levers like agy's `--facts`/`--decided`, the round-2 `--continue` delta, guarded passthrough), verbatim from the bridge manifests (drift-guarded; each wrapper's `--help` prints the same) — except `feedback-triage`, whose record-bound block carries the check with `--excerpts`, the resolved member lines (ready bridge commands, the ready lens brief, or explicit skipped members), and either the record round-table command for a bridge obligation or the no-receipt fact otherwise: the record is the artifact. `--override <slot>=<value>` adjusts one slot per run. Composes with `recipes`; never writes, never commits, never runs a subscription CLI. |
237
237
  | `/agent-workflow-kit set-recipe` | any time | **config writer** for `docs/ai/orchestration.json`: tell the agent your preference in plain language and it maps it to explicit `--set <activity>.<slot>=<value>` / `--unset` ops; the kit validates, **previews by default**, and writes only on `--write` (deployment-gated, atomic, symlink/TOCTOU-safe), resolving the effective recipe vs live readiness. Writes **only** that file — **never runs a backend or a subagent, never commits**; hand-editing stays fully supported. |
238
238
  | `/agent-workflow-kit review-state` | any time | **read-only review-receipt checker** — makes "reviewed ≠ shipped" detectable: the bridge review wrappers append a receipt per successful review (into a file inside the git dir — never committable); this checks that every backend your configured `plan-execution.review` recipe names holds a **fresh, grounded receipt for the current uncommitted tree** (any later edit moves the fingerprint and stales the receipt; a review continuation never re-attests a folded tree). `--check` gives a gate exit code to declare in `docs/ai/gates.json` **by hand or via the consent-gated seeder** (preview → your explicit yes; never without consent). `--await [--timeout <s>]` (AD-049) BLOCKS until every recipe-named backend has receipted the current tree — the durable completion signal is the receipt, never a process event — so you wait for the bridges instead of hand-polling. Never writes, never commits, never runs a subscription CLI; it spawns read-only `git` queries to fingerprint the tree — and `git commit --no-verify` stays possible (discipline, not a sandbox). |
239
239
  | `/agent-workflow-kit sandbox-masks` | any time | **cosmetic exclude lane for sandbox device masks** — an OS sandbox (Claude Code) injects character-device masks into the work tree as untracked `git status` noise; the review domain already ignores them **by construction** (never-committable untracked classes — char/block devices, FIFOs, sockets — are excluded from the fingerprint, the assembled review payload, and the clean checks). This mode hides them from `git status` too: flagless = read-only probe (derives the CURRENT mask set from the unfiltered walk + lstat — never a frozen list — and revalidates fenced entries, loudly flagging one that became a real path); `--apply` = consent-gated FULL-BLOCK replace of its own fenced block in `git rev-parse --git-path info/exclude` (stale masks drop by construction; `--clear` always means REMOVE the block — it takes precedence over the derivation). Writes ONLY its fence — never `.gitignore`, never global config; symlinked/non-regular exclude paths and malformed fences fail closed. Watch note: a real file at an excluded path is silently skipped by bulk staging (`git add -A`/`git add .`) — delete the stale line first; the probe flags exactly this case. |
@@ -270,7 +270,7 @@ It **never auto-commits** and **never overwrites** an existing `AGENTS.md` witho
270
270
  - **Plan lifecycle** — a capped plan (goal and boundary, module ledger, verification), ephemeral plan files, and a mandatory Cleanup phase.
271
271
  - **No silent failures** — every guard that rejects an action logs structured context.
272
272
 
273
- Enforcement ships as dependency-free **Node** scripts (`node --test`, no package manager assumed). Non-Node projects follow the same policy by hand.
273
+ The dependency-free **Node** enforcement scripts (`node --test`, no package manager assumed) and their hook are offered on every project because the agent host runs them; a committer without Node on PATH gets a loud hook failure.
274
274
 
275
275
  ---
276
276
 
@@ -284,7 +284,8 @@ agent-workflow-kit — the composition root (installed via npx … init)
284
284
  on /agent-workflow-kit in a repo, the kit:
285
285
  ├─ delegates ─▶ memory substrate (healthy copy, else bundled fallback)
286
286
  ├─ injects ─▶ workflow methodology (live from the installed engine)
287
- ├─ deploys ─▶ AGENTS.md + docs/ai/ + Node scripts + pre-commit hook
287
+ ├─ deploys ─▶ AGENTS.md + docs/ai/
288
+ │ + Node scripts + pre-commit hook (installed on a yes)
288
289
  ├─ detects ─▶ optional backends (codex / agy, read-only)
289
290
  └─ sets up ─▶ a bridge (opt-in) (place skill + link wrappers)
290
291
  ```
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: agent-workflow-kit
3
3
  description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow".
4
4
  disable-model-invocation: true
5
5
  metadata:
6
- version: '11.0.0'
6
+ version: '11.2.0'
7
7
  ---
8
8
 
9
9
  # agent-workflow-kit
package/capability.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "agent-workflow-kit",
5
5
  "kind": "composition-root",
6
- "version": "11.0.0",
6
+ "version": "11.2.0",
7
7
  "provides": [],
8
8
  "roles": {},
9
9
  "detect": {
@@ -26,8 +26,8 @@ reinvent any of it here; the kit's `SKILL.md` is the single source of truth.
26
26
  attribution) as ONE structured multi-question prompt; record each answer individually,
27
27
  write nothing until ALL are answered** →
28
28
  create `AGENTS.md` (+ `CLAUDE.md` symlink) from `<KIT_DIR>/references/templates/` →
29
- deploy `docs/ai/` → copy `<KIT_DIR>/references/scripts/*.mjs` (Node projects) →
30
- wire/hide per visibility → install the pre-commit hook → stamp `docs/ai/.workflow-version`.
29
+ deploy `docs/ai/` → offer the enforcement scripts + pre-commit hook (on a yes: copy `<KIT_DIR>/references/scripts/*.mjs`, install the hook) →
30
+ wire/hide per visibility → stamp `docs/ai/.workflow-version`.
31
31
  4. Report what was filled with real data vs left as TODO, then **ask before committing** —
32
32
  never auto-commit.
33
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabaiway/agent-workflow-kit",
3
- "version": "11.0.0",
3
+ "version": "11.2.0",
4
4
  "description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -17,7 +17,7 @@ The user chooses at bootstrap whether the AI artifacts are visible in the repo o
17
17
  **explicit up-front question** (bootstrap step 2), never an assumed default. The two modes then
18
18
  diverge:
19
19
 
20
- - **visible** — artifacts are committed. Wire the project's `package.json` scripts (`docs:check` / `docs:index` / `docs:index:check` / `docs:archive` / `docs:archive:check` / `docs:archive:issues` / `docs:archive:issues:check` / `prepare: node scripts/install-git-hooks.mjs`) and add a minimal `.gitignore` (`docs/plans/`, `.claude/settings.local.json`). This is the canonical model.
20
+ - **visible** — artifacts are committed. When a `package.json` exists and the enforcement offer was accepted, wire the project's `package.json` scripts (`docs:check` / `docs:index` / `docs:index:check` / `docs:archive` / `docs:archive:check` / `docs:archive:issues` / `docs:archive:issues:check` / `prepare: node scripts/install-git-hooks.mjs`); add a minimal `.gitignore` (`docs/plans/`, `.claude/settings.local.json`) either way. This is the canonical model.
21
21
  - **hidden** (in-tree) — same files on disk, but the repo "looks normal": the AI/agent footprint is git-ignored via **one managed block in the project-local `.git/info/exclude`** (resolved with `git rev-parse --git-path info/exclude` — never the machine-global `core.excludesFile`, which would affect every repo on the host; **AD-014** amends **AD-006**). The kit's `tools/hide-footprint.mjs` is the single writer: it covers `KIT_OWN_PATHS ∪ the present subset of KNOWN_FOOTPRINT` (the full footprint table below — the kit's own artifacts **and** every other AI/agent tool's files). Per path: a **tracked** file → **ASK** (an exclude does nothing for it; only `git rm --cached` un-tracks it — the tool prints that command and never runs it); an untracked path already covered by a **tracked `.gitignore`** → dropped (redundant); a **present** file whose name is generic enough to be ambiguous (`falsePositiveRisk`) → **ASK**; everything else → **hidden**. `asks` are excluded from the block unless explicitly opted in. **Verify** treats a path as hidden only when it is **untracked AND ignored by our project-local block** (or a tracked `.gitignore`) — being ignored by the global excludes does **not** count. Re-running re-derives the block wholesale (sorted/deduped) → a clean re-run is a **zero-diff** no-op. On an existing global-excludes deployment the tool **detects + reports the residual legacy machine-global block and keeps it by default** (a harmless double-ignore; the local block wins precedence); removal is the explicit `--remove-global` (it prints the removed lines as a restorable backup), which **the agent only runs after asking** — another of the user's hidden repos on the same host may rely on the same root-anchored global lines. **Do not edit `package.json`** — that is a tracked change and would leak; the pre-commit hook (always untracked in `.git/hooks/`) calls the scripts via `node scripts/<x>.mjs` directly. Windows is supported (text edit, no symlinks; CRLF preserved).
22
22
 
23
23
  **Visibility changes what git sees — never how the agent works (the load-bearing invariant).** Both modes carry the **same** working memory and run the **same** session protocol: `docs/ai` and the deployed workflow artifacts (`AGENTS.md`, the added `scripts/`) are read at session start and maintained on task completion **identically** whether visible or hidden. (Hidden mode git-ignores a *wider* footprint — other AI/agent tools' files too — but that is only a **visibility** surface; the working memory the agent actually reads and maintains is `docs/ai` plus those artifacts.) Hidden mode only makes the repo *look* normal to git; it is **never** a license to skip, defer, or down-prioritise a doc/state update. The single difference is the destination: in hidden mode those updates live on disk and never enter a commit (the footprint is excluded), so a commit there carries only the project's own tracked files while `docs/ai` is still kept current locally — **git-ignored ≠ optional-to-maintain**. An agent that reads "git-ignored / `git status` clean" and infers the working memory is optional has the model backwards. (This is why bootstrap/upgrade never wire hidden-mode docs into a commit, yet the session protocol still mandates maintaining them.)
@@ -1,6 +1,6 @@
1
1
  ### Mode: bootstrap
2
2
 
3
- <!-- opt-in-capability: none — the deployment action itself; the advisor only renders inside an existing deployment -->
3
+ <!-- opt-in-capability: enforcement -->
4
4
 
5
5
  Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md · ${CLAUDE_SKILL_DIR}/references/shared/composition-handoff.md · ${CLAUDE_SKILL_DIR}/references/shared/deploy-tail.md · ${CLAUDE_SKILL_DIR}/references/shared/command-shapes.md
6
6
 
@@ -23,9 +23,9 @@ Requires: ${CLAUDE_SKILL_DIR}/references/shared/report-footer.md · ${CLAUDE_SKI
23
23
  5. **Entry-point doc.** If `AGENTS.md` / `CLAUDE.md` already exist (step-1 recon), do **not** overwrite — show the user and ask whether to merge or replace. Otherwise create `AGENTS.md` (the cross-agent standard — Codex / Cursor / Devin Desktop / Copilot read it natively) from `${CLAUDE_SKILL_DIR}/references/templates/AGENTS.md`, and symlink `CLAUDE.md -> AGENTS.md` (`ln -s AGENTS.md CLAUDE.md`) for Claude Code — single source, no duplication. For nested context, add a subdir `AGENTS.md` (+ a `CLAUDE.md` symlink beside it for Claude Code).
24
24
  6. **Deploy `docs/ai/`.** Create every `docs/ai/` file + `pages/` + the seed `adr/` store + the seed `specs/` store from `${CLAUDE_SKILL_DIR}/references/templates/` (the template loop deploys every template except `AGENTS.md`, `adr-record.md` and `SPEC_TEMPLATE.md` — the latter two are skill-home authoring references, never deployed). This deploys the HOT ADR window **`docs/ai/decisions.md`** and the seed navigator **`docs/ai/adr/log.md`** (its `adr/` subdir copies in wholesale), the spec store root **`docs/ai/specs/index.md`** (its `specs/` subdir copies in wholesale), the `.md` docs, **and** the three seeded, user-editable strict-JSON configs: **`docs/ai/orchestration.json`** (the per-project recipe defaults the `procedures` advisor reads), **`docs/ai/gates.json`** (the project's gate declaration — seeded as the no-consent EMPTY list; FILLING it is the consented `gates-init` preview, `${CLAUDE_SKILL_DIR}/references/modes/gates.md`), and **`docs/ai/autonomy.json`** (the per-project autonomy policy — seeded SPARSE with the onboarding note only, so it is exactly the computed defaults until the user declares levels via `/agent-workflow-kit set-autonomy` or by hand). Keep each `.md` file's frontmatter (`type / lastUpdated / scope / staleAfter / owner / maxLines`); the `.json` seeds carry no frontmatter (the docs cap-validator globs `*.md` only, so they are inherently skipped).
25
25
  7. **Fill templates** per the table below. **Then materialize the navigator, as the last `docs/ai` step:** the entry point declares `docs/ai/index.md` always-loaded and it is a GENERATED artifact with no template, so run `node ${CLAUDE_SKILL_DIR}/references/scripts/check-docs-size.mjs --ensure-index --root=<project>` and relay its one outcome line (`ensure-index: regenerated` / `already-current`, or a `write-refused` / `probe-failed` line naming the offending path — either is a STOP: resolve it before reporting the deploy, since the navigator the entry point declares does not exist yet). The generator runs from **this skill's own directory**, so a project with **no Node runtime** is covered too: the agent host runs it, and step 8's copy is not a precondition.
26
- 8. **Install enforcement (Node projects).** Copy `${CLAUDE_SKILL_DIR}/references/scripts/*.mjs` (+ `*.test.mjs`) into the project's `scripts/`. They self-configure (project name from `package.json`, hierarchical/on-demand sections auto-discovered). **If the project has no Node runtime** (step-1 recon), skip this step and the hook in step 9 — follow the cap/archive/index policy manually, or port the scripts to the project's language.
27
- 9. **Wire / hide** per visibility (see [Visibility contract](${CLAUDE_SKILL_DIR}/references/contracts.md#visibility-contract)). Install the pre-commit hook (Node projects): `node scripts/install-git-hooks.mjs`. If the installer reports a pre-existing non-marker hook, stop and ask the user to merge it manually rather than overwriting. Once the gate declaration is final-run-capable, the installer's optional consented `--commit-guard <kit commit-guard.mjs path>` arm binds commits to the green `run-gates --final` receipt (the Recommendations advisor surfaces the exact one-liner).
28
- - **visible** — wire the `package.json` scripts + add the minimal `.gitignore`. **Do not run the hide tool.**
26
+ 8. **Offer enforcement on every project, preview-first.** Explain in one line that the dependency-free Node scripts are available because the agent host already runs their step-7 navigator; the only skip condition is that the agent host cannot run them. Preview the source and destination list and ask; on a yes copy `${CLAUDE_SKILL_DIR}/references/scripts/*.mjs` (+ `*.test.mjs`) into the project's `scripts/`. On a no, skip the hook in step 9 and say so; the docs command slots then name no project-local command — fill `env_commands.md` and the `Docs caps + index freshness` row of `AGENTS.md` with the same note: the caps + index gate run from the agent's own skill copy (the step-7 `--root=<project>` form) and the archive rotations need the scripts deployed. Never write the skill's absolute path into a deployed doc. They self-configure (project name from `package.json` or, without one, the directory basename; hierarchical/on-demand sections auto-discovered). The hook calls `node scripts/<x>.mjs` directly, so a committer without `node` on PATH gets the hook's own loud failure.
27
+ 9. **Wire / hide** per visibility (see [Visibility contract](${CLAUDE_SKILL_DIR}/references/contracts.md#visibility-contract)). When the user accepts the enforcement offer, install the pre-commit hook: `node scripts/install-git-hooks.mjs`. If the installer reports a pre-existing non-marker hook, stop and ask the user to merge it manually rather than overwriting. Once the gate declaration is final-run-capable, the installer's optional consented `--commit-guard <kit commit-guard.mjs path>` arm binds commits to the green `run-gates --final` receipt (the Recommendations advisor surfaces the exact one-liner).
28
+ - **visible** — when a `package.json` exists and the offer was accepted, wire its scripts (never create one for this); add the minimal `.gitignore` either way. **Do not run the hide tool.**
29
29
  - **hidden** — run the kit's hide writer (one managed block in the **project-local** `.git/info/exclude`, covering the kit's own artifacts **and** every known AI/agent tool's footprint — never the machine-global excludes): `node ${CLAUDE_SKILL_DIR}/tools/hide-footprint.mjs --dir <project> --dry-run` **first** (changes nothing, prints the plan), then the same without `--dry-run`. Handle what it surfaces, in plain language (never the tool's internal terms):
30
30
  - A path it reports as **already committed** can't be hidden by ignoring it and is **never un-tracked silently** — show the user the printed `git rm --cached <path>`, let them decide, then opt it in with `--include=<path>`.
31
31
  - A **present file with a generic name** it flags (e.g. `GEMINI.md`) → ask before `--include=<path>`.
@@ -58,5 +58,5 @@ Fill strategy:
58
58
  | `tech_reference.md` | Carry over real configs/patterns found in deps. |
59
59
  | `active_plan.md`, `handover.md` | TODO seed (e.g. "Bootstrap session — fill domain sections after first real work"). |
60
60
  | `decisions.md` | The HOT ADR window — seed `AD-001` (adopting this memory system), newest at the bottom. |
61
- | `adr/log.md` | The seed navigator — deployed as-is (the generator over the seeded HOT); regenerated by `archive-decisions.mjs`, never hand-edited. |
61
+ | `adr/log.md` | The seed navigator — deployed as-is (the generator over the seeded HOT); regenerated by `archive-decisions.mjs` where the enforcement scripts are deployed (installed on a yes), otherwise it stays the seed — never hand-edited either way. |
62
62
  | `known_issues.md`, `changelog.md`, `pages/shared-patterns.md` | Empty template / first bootstrap entry. |
@@ -4,11 +4,12 @@
4
4
 
5
5
  Read-only **activity-procedures advisor**. Answers *"what are the steps of this named activity, and which recipe applies at each slot here?"* It composes the orchestration recipes (`${CLAUDE_SKILL_DIR}/references/modes/recipes.md`) into **named activities** with **typed recipe slots**. It **never writes, never commits, never runs a subscription CLI** — the deterministic resolution lives in the kit; the orchestrator runs the resolved recipe via the bridge skills or the executor vehicle and **owns any commit when the activity has a commit boundary** (every other carrier never commits). Not every activity commits: `plan-authoring` ends at approval and produces no commit (plans are ephemeral, never committed); `plan-execution` commits per ledger row.
6
6
 
7
- The three activities (canon in the **installed engine**, `references/procedures.md`; the registry is `tools/carriers.mjs`):
7
+ The four activities (canon in the **installed engine**, `references/procedures.md`; the registry is `tools/carriers.mjs`):
8
8
 
9
9
  - **`plan-authoring`** (slots: `author`, `fold`, `review`) — research → draft (the resolved `author` carrier drafts: Solo writes it, Subagent drafts from the orchestrator's brief) → self-review with the readers sweep first → **review {recipe}** → consult, then fold/loop through the resolved `fold` carrier → present for approval; enforce the mandatory Cleanup.
10
10
  - **`plan-execution`** (slots: `execute`, `review`) — per ledger row: resolve the recipe → if Delegated, dispatch execution first; if Subagent, dispatch file-disjoint slices to the executor vehicle and verify each returned slice → implement → self-review → **review {recipe}** → gates → commit boundary; after the last row, the project-declared stages and Phase: Cleanup run as rows of their own.
11
11
  - **`routine`** (slots: `carrier`, `parallel`) — name the chore and its file-disjoint slices → resolve → carry it (Solo, or Subagent: a read-only slice rides a placed read-only vehicle, a write-capable one rides the executor; `parallel` on → concurrently) → verify every returned slice; the commit boundary is unchanged.
12
+ - **`feedback-triage`** (slot: `review`) — record → verify every claim by code on the stamped HEAD → `feedback-record-cli --check` → **review {recipe}** over the record, the excerpts as agy's `--facts` payload → `--rows` renders the queue rows and the ratchet line → fold only a false statement in shipped copy.
12
13
 
13
14
  Value sets per slot type: `review` accepts `solo | reviewed | council`; `execute` accepts `solo | delegated | subagent`; a carrier slot (`author`, `fold`, `carrier`) accepts `solo | subagent`; `parallel` is a **switch**, `on | off`, resolved outside the recipe lattice. Defaults when the config is silent: `review` → Reviewed if a review-capable backend is ready, else Solo; `author`, `fold`, `execute`, `carrier` → Solo (a placed executor never flips a default); `parallel` → on. The orchestrator owns every commit; every other carrier — a bridge or a subagent — never commits.
14
15
 
@@ -38,6 +39,8 @@ Run **`node ${CLAUDE_SKILL_DIR}/tools/procedures.mjs <activity> [--override <slo
38
39
 
39
40
  **Robustness-brief block (`plan-execution` only).** The advisor renders `node ${CLAUDE_SKILL_DIR}/tools/robustness-brief.mjs --plan <plan>` populated when exactly one plan is in flight and names the zero/several-plan placeholder reason otherwise. `--json` carries the identical lines under **`robustnessBrief`**, an empty array outside `plan-execution`; human and structured renders share one block.
40
41
 
42
+ **Record-bound review block (`feedback-triage` only).** In place of the driving contracts and the grounding pre-step the advisor renders the check-with-excerpts line, then one line per review member — a ready bridge's plan-mode command, a ready lens's brief (the record plus the excerpts), a skipped line for a not-ready member — and the round-table line while the slot carries a bridge obligation (a roster naming no bridge: the no-receipt fact in its place; a fully degraded reviewed or council slot keeps the line). The round-table line is followed by the standing fact that the table judges the obligation `review-rounds-cli` resolves from `docs/ai/orchestration.json`, never this run's `--override`. `--json` carries the identical lines under **`feedbackTriage`** (an empty array for the other activities).
43
+
41
44
  **Cap-soft-skip degradation (the feature's only AUTO route).** The activity procedures are auto-discoverable only through the one-line **`workflow:methodology`** pointer (this kit + the engine carry `disable-model-invocation:true`, so NL like "write a plan" does **not** auto-load this skill). On a deployment whose methodology pointer was cap-soft-skipped — or whose pre-existing customized pointer lacks the procedures clause — the procedures are still reachable by **explicitly** invoking `/agent-workflow-kit procedures`; surface that plainly rather than treating it as a gap.
42
45
 
43
46
  **Invariants:** read-only · never writes · never commits · never runs a subscription CLI · the deterministic resolution is the kit's, the recipe execution is the orchestrator's.
@@ -16,7 +16,7 @@ The five recipes (defined over each bridge's `provides` roles — `codex`: execu
16
16
  2. **Offer the choice** via **`AskUserQuestion` where your agent supports it** (`AskUserQuestion` in Claude Code) — one option per recipe, the `recommendRecipe` choice listed **first** — otherwise in prose. Then print `planRecipe(chosen, detection)` (the per-stage dispatch + degradation reasons + quota/health notes) so the user sees exactly what running it entails.
17
17
  3. **Availability = `readiness === ready`, full stop.** Every other readiness supplies the human reason (needs-skill → "not installed — `/agent-workflow-kit setup`"; needs-cli → "install the CLI"; needs-credentials → "log in"; degraded → "wrapper not on PATH — `/agent-workflow-kit setup`"). This is set-up state only — **never** a claim that a backend's service is responsive (the detector cannot observe a runtime stall; `agy`'s Issue-001 is a *standing advisory*, not a readiness signal).
18
18
 
19
- **The activities and their slots.** One registry (`tools/carriers.mjs`, re-exported by `recipes.mjs`) names **three** activities and their typed slots: `plan-authoring` → `author`, `fold`, `review`; `plan-execution` → `execute`, `review`; `routine` → `carrier`, `parallel`. Each slot's accepted values follow its TYPE — `review` accepts `solo|reviewed|council`; `execute` accepts `solo|delegated|subagent`; `carrier` accepts `solo|subagent`. **`parallel` is a flag (`on|off`), not a recipe:** it resolves OUTSIDE the recipe lattice, never degrades, and never reaches the planner. A silent slot takes its **computed default** — `solo` for `author`, `fold`, `execute` and `carrier` (placing the executor vehicle never flips a default; the subagent carrier is opt-in exactly as `delegated` is), `reviewed`/`solo` by readiness for `review`, and `on` for `parallel`.
19
+ **The activities and their slots.** One registry (`tools/carriers.mjs`, re-exported by `recipes.mjs`) names **four** activities and their typed slots: `plan-authoring` → `author`, `fold`, `review`; `plan-execution` → `execute`, `review`; `routine` → `carrier`, `parallel`; `feedback-triage` → `review`. Each slot's accepted values follow its TYPE — `review` accepts `solo|reviewed|council`; `execute` accepts `solo|delegated|subagent`; `carrier` accepts `solo|subagent`. **`parallel` is a flag (`on|off`), not a recipe:** it resolves OUTSIDE the recipe lattice, never degrades, and never reaches the planner. A silent slot takes its **computed default** — `solo` for `author`, `fold`, `execute` and `carrier` (placing the executor vehicle never flips a default; the subagent carrier is opt-in exactly as `delegated` is), `reviewed`/`solo` by readiness for `review`, and `on` for `parallel`.
20
20
 
21
21
  **The configured-recipe line (`--active-line`, read-only).** `node ${CLAUDE_SKILL_DIR}/tools/recipes.mjs --active-line` prints exactly **one** machine-composed line: the **CONFIGURED** recipe of every activity/slot, resolved from the target project's `docs/ai/orchestration.json` (read from the current directory) + live readiness — each slot with its source (configured vs computed default), its degradation stated, and its dispatched wrapper set — explicitly contrasted with the readiness **recommendation** (which is informational; the configured recipes are what runs). Paste it verbatim: it fills the session-start discovery step (the deployed `agent_rules.md` §1.1) and the handover "Active recipes:" slot; `set-recipe` echoes the same line after every successful write. A malformed config fails loud (exit 1), never a silent fallback.
22
22
 
@@ -20,7 +20,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/recommendations.mjs --cwd <project-root> [--
20
20
  3. **The apply-through-agent lane — an explicit informed-consent checkpoint:** after presenting, OFFER to apply; the user selects items in plain language; for each selected item you **surface its posture note inline** where one exists (the per-item notes below cover exactly the risk-marked keys; for `sandbox-lane` the note INCLUDES the sandbox-lanes ladder — present the whole ladder inline at the consent moment, never as a bare pointer). The user **explicitly confirms**, and **only then** — **no command runs before confirmation** — do you run the rendered command. Do NOT infer safety from the presence or absence of an `--apply` flag: most items' rendered command IS the mutation and completes on that one run, **including a no-`--apply` mutation** such as `family-freshness`'s `npx … init`. Some items instead render a **dry-run preview** that changes nothing and prints an explicit follow-up `--apply`/mutating command to run NEXT (e.g. `sandbox-lane`'s ack-write — a NEUTRAL recipe fingerprint into the family-owned `docs/ai/acks.json`, never a security key — and the `gates-declaration` seeder): after the SAME confirmation you run that printed follow-up command — no second ask, no improvisation (each writer keeps its own consent semantics: previews, `--apply` flags, refusals). An item marked **HAND-APPLY** (e.g. the `read-lane` stale/missing arms) is **never run by you and never written by the kit** — hand the user its rendered line together with its posture note; HAND-APPLY is **maintainer territory wherever it renders** — the apply slot or the `recipe:` line. For `worktrees-dir` the two classes COMPOSE in one item and the ORDER is part of the contract: its `recipe:` line is the HAND-APPLY grant advice, its apply one-liner is the dry-run ack preview, and you **wait for the maintainer to confirm the grant is applied (or the terminal fallback chosen)** before running that preview and the exact `--apply` command it prints — the ack RECORDS a choice that must already have been made, and against a trusted host NO the item renders no ack at all.
21
21
  4. Registry strings (benefits + item texts) are frozen tool data, fact-true, ONE line under the pinned shape cap — posture/risk detail lives in the notes below at the consent moment, never inline in the overview. The dual velocity+security wording (`safer — blast radius bounded by the OS sandbox, not human attention`) rides ONLY the items with a real security delta (the autonomy render, the sandbox provisioning); the bridge-wrappers item claims **velocity only**.
22
22
 
23
- **The `executor-vehicle` item (the carrier the project already CONFIGURED — beside the `agents` offer, never the same item).** It fires on ONE pair of facts: a slot in `docs/ai/orchestration.json` names `subagent` while the executor vehicle (`.claude/agents/executor.md`) is `missing` or `unusable` — so every such slot silently degrades to solo. That is a configured declaration that is broken, hence **`attention`**, not an offer; its text names the state, its reason and how many configured slots are affected across the three activities. **`placed` and `customized` render NOTHING** (a working vehicle is not a recommendation), a config naming no `subagent` slot renders nothing, and a config the validated reader refuses is a stated **skip**, never an item computed over a shape nothing accepted. It is deliberately DISTINCT from its two neighbours, neither of which can observe this state: the `agents` offer converges the moment nothing is left to PLACE — which a present-but-unusable executor also satisfies — and the review-recipe probe skips a slot configured `subagent` by construction. Its apply is the agents writer's own `cheap-agents.mjs --apply` (the same writer the `agents` item previews; here the rendered line IS the mutation, so read the item's state before confirming), and its `recipe:` line is the hidden-mode reconcile follow-up (`hide-footprint --reconcile`), for a hidden deployment only. Honest limit on convergence: the apply places an ABSENT vehicle, so it clears `missing`; it never overwrites a diverged file and STOPs on a symlink, so on `unusable` the item's apply line carries a `HAND-APPLY:` precondition (fix or remove the file, then run the writer) and an `unusable` vehicle converges only after the maintainer fixes or deletes the file the reason names (the delete-to-reseed the agents mode documents) and applies then. Risk profile: create-only writes under `.claude/agents/` — never `settings.json`, never a commit.
23
+ **The `executor-vehicle` item (the carrier the project already CONFIGURED — beside the `agents` offer, never the same item).** It fires on ONE pair of facts: a slot in `docs/ai/orchestration.json` names `subagent` while the executor vehicle (`.claude/agents/executor.md`) is `missing` or `unusable` — so every such slot silently degrades to solo. That is a configured declaration that is broken, hence **`attention`**, not an offer; its text names the state, its reason and how many configured slots are affected across the four activities. **`placed` and `customized` render NOTHING** (a working vehicle is not a recommendation), a config naming no `subagent` slot renders nothing, and a config the validated reader refuses is a stated **skip**, never an item computed over a shape nothing accepted. It is deliberately DISTINCT from its two neighbours, neither of which can observe this state: the `agents` offer converges the moment nothing is left to PLACE — which a present-but-unusable executor also satisfies — and the review-recipe probe skips a slot configured `subagent` by construction. Its apply is the agents writer's own `cheap-agents.mjs --apply` (the same writer the `agents` item previews; here the rendered line IS the mutation, so read the item's state before confirming), and its `recipe:` line is the hidden-mode reconcile follow-up (`hide-footprint --reconcile`), for a hidden deployment only. Honest limit on convergence: the apply places an ABSENT vehicle, so it clears `missing`; it never overwrites a diverged file and STOPs on a symlink, so on `unusable` the item's apply line carries a `HAND-APPLY:` precondition (fix or remove the file, then run the writer) and an `unusable` vehicle converges only after the maintainer fixes or deletes the file the reason names (the delete-to-reseed the agents mode documents) and applies then. Risk profile: create-only writes under `.claude/agents/` — never `settings.json`, never a commit.
24
24
 
25
25
  **Per-item posture notes (the consent moment — surface BEFORE running or handing over the apply):**
26
26
 
@@ -33,6 +33,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/recommendations.mjs --cwd <project-root> [--
33
33
 
34
34
  - `source-size` — the practice's arms differ by what the declared gate actually IS. **`adopted-elsewhere`** — the gate runs a DIFFERENT real copy of this checker (a vendored deployment): the practice is running, the advisor simply cannot resolve it as its own sibling, and the realpath anchor deliberately does not widen (it is what stops a lookalike from certifying). So the convergence is the ack writer's preview (`--lane source-size-copy` → `sourceSizeCopyAck`), never `--adopt`, which would mint the record and then be refused by the fill on the id already declared. The fingerprint binds the declared claims AS AUTHORED, sorted — not their resolved paths, which are machine-specific and would churn a committed ack between machines — so a second external copy re-fires it. **`id-squatter`** — a gate carries the `source-size` id and is not this checker under any reading: the id claims the practice while nothing measures module size, so it is **HAND-APPLY** (rename the id, or repoint the cmd at this checker's `--check` form). **`unminted`** stays what it was for both copies: a gate certain to refuse on every run, attention, and NO acknowledgement silences it — only the rendered verb differs (with the gate already declared elsewhere the missing half is the record alone, so the line is `--write-baseline`). Risk profile: `docs/ai/gates.json` is a PRIVILEGED file, so every arm here either records an acknowledgement or hands you an edit — the kit declares nothing on its own.
35
35
  - `gate-hook` — the base arm is the ordinary opt-in wiring offer. The **`marker-stale`** arm is not: the placed hook validates your declaration through its OWN baked copy and goes dark on any key it does not know, so a declaration carrying the `lcovProducer` key under a hook that predates it silently turns auto-approval OFF, and every gate prompts again with no error anywhere. The condition is the key's PRESENCE, not its value — an older hook rejects a key it does not know whatever that key says, so `"lcovProducer": false` darkens it exactly as `true` does. The arm is deliberately marker-scoped — a stale hook is otherwise harmless — and its recovery is the writer's own: `gate-hook --apply` places only an ABSENT target, so converging means deleting the placed hook and re-placing it. That makes it a destructive **HAND-APPLY** (`rm` + `--apply`, absolute path so it can only delete this project's hook), never something the consent flow runs for you. When the read-lane is also enabled, this arm and `read-lane.stale` would report the same file with the same recovery, so exactly one renders — **this one**, because its cause is the true one: a hook that postdates the read-lane and merely predates the marker key reads `lanes.json` perfectly well, and the read-lane arm's wording would be false over it. Risk profile: deleting one placed hook file, then re-placing it from the bundle; the declaration is never touched.
36
+ - `enforcement` — copies the bundled `references/scripts/*.mjs` runnable scripts and their tests, then installs the pre-commit hook. It is HAND-APPLY: the agent never runs it; the offer renders only when `scripts/` is absent or a plain directory contains no bundled basename, so the copy never clobbers an existing file and never follows a link. The hook invokes `node` directly, so a committer without it on PATH gets a loud failure. The installer refuses to overwrite a pre-commit hook it did not write — on that refusal stop and merge the hook by hand (bootstrap step 9); the copied scripts stay in place. Risk profile: local tooling and a Git hook are added only when the maintainer applies the shown command.
36
37
  - `mcp-channel` — the offer is to REGISTER the kit's read-only stdio MCP server in this project, which is a different kind of consent from the other velocity items: a registration is a command your MCP client will RUN, so the apply here is the mode's own **flagless preview**, which prints the exact entry and writes nothing — the `--apply` that follows is a SEPARATE step you run after reading that entry, and the consent flow never carries it. What the registration buys: path questions and literal searches become typed tool calls whose arguments are named JSON fields instead of a string handed to a shell, so a pipe, a redirect or a quote inside a pattern or a path stays DATA and is never interpreted — they are perfectly legal bytes to search for, there is simply no shell to read them as operators. Posture: the server is a **read-only child of your client** (path/type/size/line facts and literal search over this project root; no write and no exec API), and like the client itself it runs **outside the Bash sandbox** — the sandbox is not what bounds it, the server's own root containment is. The two allow rules it adds make those two tools promptless and nothing else. Two arms are **HAND-APPLY** and never run for you: **`.differing`** — an `agent-workflow` entry already stands in `.mcp.json` and **structurally differs** from what this kit copy would write (another kit copy, a hand-edited path, an added `env`; the comparison ignores key order, so re-serialized identical bytes are the same registration), and silently changing what an MCP server launches is exactly what consent must not slide past, so the remedy is your edit; and the **masked** arm, where an OS sandbox hides `.mcp.json` behind a device node — the kit cannot write there, so it hands you the text to paste from outside the sandbox. When the file is masked but the settings half is already complete, the item **does not render at all**: what is unobservable becomes a stated SKIP, so optimality is withheld rather than a registration you already made being offered again. Stated limit: this item does **not** detect a `disabledMcpjsonServers` veto, so a converged `mcp-channel` means *what the mode writes is in place*, not *the client will load it* — see `${CLAUDE_SKILL_DIR}/references/modes/mcp.md` for why that check was subtracted rather than half-built. Risk profile: a new read-only channel your client will launch; no write or exec exposure, and no existing declaration is touched.
37
38
  - ADDITIONAL `gates-inert` arms (the third outcomes) — two further arms, and they differ in whether anything is BROKEN. **`producer-unrecognized`** — a checker with no producer anywhere in the declaration, on a tracked tree the changed-line coverage domain cannot reach (`.ts`/`.tsx`/`.jsx`/`.mts`/`.cts` strictly outnumber `.mjs`/`.cjs`/`.js`): the dead pair is real, so this arm is **HAND-APPLY** and the two remedies are marking the real producer with `"lcovProducer": true` or dropping the checker. Never a `node --test` prescription over a project that has no such suite, never the fill preview, and never an acknowledgement — a dead pair is broken, not narrow, and removing a producer after an acknowledgement lands right back in this arm. **`coverage-domain-narrow`** — the producer/checker pair IS live and the tree is still dominated by what the domain excludes: nothing is broken, and the honest sentence is that certification covers the assessable minority. Its apply is the consent-gated **ack writer** preview (a NEUTRAL fingerprint into `docs/ai/acks.json` as `coverageDomainAck`, never a security key); after the SAME confirmation you run the `--apply` it prints. The fingerprint binds the FACT — the verdict plus the unsupported extensions present, never the file counts — so an acknowledged project stays quiet as it grows and re-fires when a new unsupported language arrives or the verdict flips. The census reads the TRACKED tree with a read-only `git ls-files`; a tree it cannot read (a non-git deployment) becomes a stated skip, so optimality is withheld rather than assumed. Risk profile: no enforcement change of any kind — one acknowledgement recorded in a family-owned file, and one hand edit that stays the maintainer's.
38
39
  - `spec-adoption` — the feature-spec layer's ADOPTION STATE, judged from `docs/ai/specs/` alone through the same census `spec-check --all` runs, so a store the checker would refuse to observe is never counted here either. Both arms are OFFERS (`optional`) — the layer is opt-in, and `attention` stays reserved for a configured declaration that is broken. **`not-adopted`** (no store): every plan then cites zero governing specs by default and nothing says adoption never started; its apply is the spec-layer ensure one-liner (`ensure-configs --reconcile --only specs`, the same seed `upgrade` runs — it writes the reader/checker pairs and the store root, create-only, and skips with a stated reason where no Node evidence exists), and its `recipe:` line carries a NAMED **HAND-APPLY alternative** — the DECLINE preview (`ack-write --lane spec-adoption`, a dry-run that prints the exact `--apply`), which records `specAdoptionAck` in the family-owned `docs/ai/acks.json`. **The two are exclusive, and the order is part of the contract:** ask which the maintainer wants BEFORE the confirmation; on "seed" run the apply; on "decline" run NOTHING — hand over the preview line and let them run it and its printed `--apply`; never run the seed after a decline was chosen, and never run the decline preview for them. **`adopting`** (a store with no live contract): an optional item naming the draft count; its apply is that same decline preview (a dry-run; after the SAME confirmation you run the `--apply` it prints), and the honest remedy is authoring a contract from the skill's `SPEC_TEMPLATE.md`. A recorded decline silences BOTH arms and shows on `status` as ` — declined`; one live contract makes the decline moot. An unreadable store is a stated skip, never `flow optimal`. Risk profile: the seed writes only create-only files under `scripts/` and `docs/ai/specs/`; the decline writes one key into the ack store; nothing here authors a spec or blocks a plan.
@@ -21,13 +21,14 @@ mapping their wording onto them is your job, not a shipped phrase list.
21
21
 
22
22
  Run **`node ${CLAUDE_SKILL_DIR}/tools/set-recipe.mjs [--set <activity>.<slot>=<value>]… [--unset <activity>.<slot>]… [--write] [--json]`**:
23
23
 
24
- 1. **Grammar — always fully-qualified `<activity>.<slot>`** (the kit never guesses the activity; a bare `review=council` is rejected). The writer takes **every slot of the three activities**, and `--help` prints the registry (`tools/carriers.mjs`) as two blocks:
24
+ 1. **Grammar — always fully-qualified `<activity>.<slot>`** (the kit never guesses the activity; a bare `review=council` is rejected). The writer takes **every slot of the four activities**, and `--help` prints the registry (`tools/carriers.mjs`) as two blocks:
25
25
 
26
26
  ```
27
27
  Activities and their slots:
28
28
  plan-authoring → author, fold, review
29
29
  plan-execution → execute, review
30
30
  routine → carrier, parallel
31
+ feedback-triage → review
31
32
 
32
33
  Accepted values per slot type:
33
34
  review slots accept solo | reviewed | council
@@ -13,7 +13,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/family-registry.mjs --json [--dir <project>]
13
13
  > **Status reads `refresh`; the shared version block + the bootstrap/upgrade footers stay `notes`-based (unchanged this release).** `${CLAUDE_SKILL_DIR}/references/modes/status.md` has its OWN status-only render (above), keyed on `installed[].refresh.behind` / `refresh.recommend`. The shared **version block** (under *The version block + welcome mat* in `${CLAUDE_SKILL_DIR}/references/shared/report-footer.md`) and the bootstrap (step 11) + every upgrade (steps 4 / 8) report footer still consume `installed[].notes` verbatim — that wiring is deliberately **untouched** here (their migration onto `refresh` is deferred). Do not rewrite those footers onto `refresh`.
14
14
  2. **Deployment (`--dir`)** (from `project`): whether `docs/ai/` is deployed + the deploy stamps by `display`; and **visibility** — render `project.visibility.state` in **user-safe words only**: *visible (tracked)* / *hidden (git-ignored, local-only)* / *unclear (uncommitted or partially set up)* — **never** the words "hidden fence" or any marker term. A `visibility.error` → surface it plainly. When `project.adrLayout` is **`old`** or **`old-unrotated`**, add a plain-language note that the project still uses an **older ADR layout** and should run the opt-in **`/agent-workflow-kit migrate-adr-store`** to move to the one-file-per-ADR store (preview first; it never commits) — the note is the SAME for both, they differ only in how the older layout was detected (`old` = a retired archive file is still on disk; `old-unrotated` = the project's deployed rotation script predates the store); `migrated` / `none` need no note. Then **one `specs` line, always** (from `project.specs` — the feature-spec layer's adoption state, judged from the store alone): `not adopted` (no `docs/ai/specs/` — the layer was never seeded), `adopting (N draft)` (a store with no live contract yet), `adopted (N live, M draft)`, or `could not be read — <reason>` (the store or a document in it could not be observed; never counted as any of the other three). A recorded decline (`project.specs.declined`) appends ` — declined` to the first two. The internal tokens are `not-adopted` / `adopting` / `adopted` / `unreadable`; render the plain phrases above, never the tokens. An envelope without the field says the installed kit predates it — say so rather than inventing a state.
15
15
  3. **Settings (`--dir`, one line each)** (from `project.settings`):
16
- - **recipes** — the effective recipe per slot, **one line per slot** over the three activities (`plan-authoring.author` / `.fold` / `.review`, `plan-execution.execute` / `.review`, `routine.carrier` / `.parallel`); each line also carries **where the value came from** (`source` — the project's config, an explicit override, or a computed default) and, when the resolved recipe is not the one that was asked for, **what it degraded from** (`degradedFrom`). Say both in plain words (never the field names): an effective recipe alone cannot tell a deliberate choice from a default, nor a degrade from a config that really names the resolved recipe — and a slot showing `solo` after a degrade from `subagent` is exactly the case the **subagents** line below explains. Detail → `/agent-workflow-kit procedures` / `recipes`; a `recipes.detectError` → say the backends couldn't be checked, so bridge-backed recipes floored at solo; the executor vehicle is unaffected.
16
+ - **recipes** — the effective recipe per slot, **one line per slot** over the four activities (`plan-authoring.author` / `.fold` / `.review`, `plan-execution.execute` / `.review`, `routine.carrier` / `.parallel`, `feedback-triage.review`); each line also carries **where the value came from** (`source` — the project's config, an explicit override, or a computed default) and, when the resolved recipe is not the one that was asked for, **what it degraded from** (`degradedFrom`). Say both in plain words (never the field names): an effective recipe alone cannot tell a deliberate choice from a default, nor a degrade from a config that really names the resolved recipe — and a slot showing `solo` after a degrade from `subagent` is exactly the case the **subagents** line below explains. Detail → `/agent-workflow-kit procedures` / `recipes`; a `recipes.detectError` → say the backends couldn't be checked, so bridge-backed recipes floored at solo; the executor vehicle is unaffected.
17
17
  - **attribution** — `includeCoAuthoredBy` effective; call out a **local override** only when `local` is non-null **and** differs from `project` (a `null` `local` means the key is absent there, so the project value stands — that is not an override).
18
18
  - **velocity** — the effective `permissions.defaultMode` + whether an allowlist is seeded (detail → `/agent-workflow-kit velocity`).
19
19
  - **subagents** — how many of the kit's subagent vehicles are placed (`agents.placed` of `agents.bundled`; zero placed → the optional `/agent-workflow-kit agents` opt-in), then the **split the line always states separately**: the **read-only vehicles** (`agents.readOnly` — four; none of them grants a shell, three ride a cheap model for mechanical work and one is a read-only review lens) and the **ONE full-tool `executor`**, whose own state is `agents.executor`: *placed* / *customized* (both dispatchable) / *unusable* (`agents.executorReason` carries the reason — say it) / *missing*. That state is what decides whether a slot configured `subagent` can ride it: on **unusable** or **missing** every such slot runs solo instead, so surface it plainly beside the recipes lines and point at `/agent-workflow-kit agents` to place it. It is a claim about the FILE, never about the host. An envelope with no executor state says the installed kit predates the field — say so rather than inventing a state.
@@ -1,8 +1,9 @@
1
1
  import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { readFileSync } from 'node:fs';
4
- import { dirname, resolve } from 'node:path';
5
- import { fileURLToPath } from 'node:url';
3
+ import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { basename, dirname, join, resolve } from 'node:path';
6
+ import { fileURLToPath, pathToFileURL } from 'node:url';
6
7
 
7
8
  // Structural pin (green by construction, a tripwire not a proof): all three archivers read
8
9
  // documents through the ONE shared tokenizer. A fourth archiver — or a future edit that reaches
@@ -12,6 +13,50 @@ import { fileURLToPath } from 'node:url';
12
13
 
13
14
  const DIR = dirname(fileURLToPath(import.meta.url));
14
15
  const ARCHIVERS = ['archive-changelog.mjs', 'archive-issues.mjs', 'archive-decisions.mjs'];
16
+ const ARCHIVER_CLOSURE = ['archive-changelog.mjs', 'archive-issues.mjs', 'archive-caps.mjs', 'markdown-blocks.mjs'];
17
+ const FIXED_DATE = '2026-09-02';
18
+ const MALFORMED_PACKAGE_JSON = '{ not json';
19
+ const NAMED_PACKAGE_JSON = '{"name":"named-fixture"}';
20
+ const NAMED_FIXTURE = 'named-fixture';
21
+
22
+ const buildArchiveHeadings = async (packageJson) => {
23
+ const root = mkdtempSync(join(tmpdir(), 'archiver-name-'));
24
+ const scripts = join(root, 'scripts');
25
+ mkdirSync(scripts);
26
+ for (const name of ARCHIVER_CLOSURE) cpSync(join(DIR, name), join(scripts, name));
27
+ if (packageJson !== null) writeFileSync(join(root, 'package.json'), packageJson);
28
+ const changelog = await import(pathToFileURL(join(scripts, 'archive-changelog.mjs')).href);
29
+ const issues = await import(pathToFileURL(join(scripts, 'archive-issues.mjs')).href);
30
+ const result = {
31
+ fallback: basename(root),
32
+ changelog: changelog.buildRecent([], FIXED_DATE),
33
+ issues: issues.buildResolvedFile(null, [], FIXED_DATE),
34
+ };
35
+ rmSync(root, { recursive: true, force: true });
36
+ return result;
37
+ };
38
+
39
+ const assertArchiveHeadings = (result, projectName) => {
40
+ assert.ok(result.changelog.includes(`# Changelog WARM Archive \u2014 ${projectName}`));
41
+ assert.ok(result.issues.includes(`# Resolved Issues \u2014 ${projectName}`));
42
+ };
43
+
44
+ describe('the archivers head their archives with the directory basename when no package.json, or a malformed one, names the project', () => {
45
+ it('no package.json names the directory basename', async () => {
46
+ const result = await buildArchiveHeadings(null);
47
+ assertArchiveHeadings(result, result.fallback);
48
+ });
49
+
50
+ it('a malformed package.json names the directory basename', async () => {
51
+ const result = await buildArchiveHeadings(MALFORMED_PACKAGE_JSON);
52
+ assertArchiveHeadings(result, result.fallback);
53
+ });
54
+
55
+ it('a named package.json wins', async () => {
56
+ const result = await buildArchiveHeadings(NAMED_PACKAGE_JSON);
57
+ assertArchiveHeadings(result, NAMED_FIXTURE);
58
+ });
59
+ });
15
60
 
16
61
  describe('every archiver reads through the tokenizer — no raw scan survives', () => {
17
62
  for (const name of ARCHIVERS) {
@@ -8,12 +8,15 @@ import { describe, it } from 'node:test';
8
8
  import assert from 'node:assert/strict';
9
9
  import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync, cpSync, existsSync } from 'node:fs';
10
10
  import { tmpdir } from 'node:os';
11
- import { join, dirname, resolve } from 'node:path';
11
+ import { basename, join, dirname, resolve } from 'node:path';
12
12
  import { fileURLToPath } from 'node:url';
13
13
  import { spawnSync } from 'node:child_process';
14
14
 
15
15
  const HERE = dirname(fileURLToPath(import.meta.url));
16
16
  const INSTALLER_SRC = join(HERE, 'install-git-hooks.mjs');
17
+ const MALFORMED_PACKAGE_JSON = '{ not json';
18
+ const NAMED_PACKAGE_JSON = '{"name":"named-fixture"}';
19
+ const NAMED_FIXTURE = 'named-fixture';
17
20
 
18
21
  // The installer anchors ROOT at <its dir>/.. — deploy it into a fixture's scripts/ like a consumer.
19
22
  const mkProject = () => {
@@ -39,6 +42,33 @@ const hooksPathOf = (root) => {
39
42
  return resolve(root, r.stdout.trim());
40
43
  };
41
44
 
45
+ const markerFor = (name) => `# ${name}:install-git-hooks.mjs`;
46
+ const readHook = (root) => readFileSync(join(hooksPathOf(root), 'pre-commit'), 'utf8');
47
+
48
+ describe('install-git-hooks \u2014 beside no package.json, or a malformed one, the marker names the directory basename', () => {
49
+ it('no package.json, then a MALFORMED one \u2014 the marker names the directory basename', () => {
50
+ const { root } = mkProject();
51
+ const expected = markerFor(basename(root));
52
+ const absent = runInstaller(root);
53
+ assert.equal(absent.status, 0, absent.stderr);
54
+ assert.ok(readHook(root).split('\n').includes(expected));
55
+ writeFileSync(join(root, 'package.json'), MALFORMED_PACKAGE_JSON);
56
+ const malformed = runInstaller(root);
57
+ assert.equal(malformed.status, 0, malformed.stderr);
58
+ assert.ok(readHook(root).split('\n').includes(expected));
59
+ rmSync(root, { recursive: true, force: true });
60
+ });
61
+
62
+ it('a named package.json wins \u2014 the marker carries its name', () => {
63
+ const { root } = mkProject();
64
+ writeFileSync(join(root, 'package.json'), NAMED_PACKAGE_JSON);
65
+ const result = runInstaller(root);
66
+ assert.equal(result.status, 0, result.stderr);
67
+ assert.ok(readHook(root).split('\n').includes(markerFor(NAMED_FIXTURE)));
68
+ rmSync(root, { recursive: true, force: true });
69
+ });
70
+ });
71
+
42
72
  describe('install-git-hooks — the hooks path comes from git plumbing (C7)', () => {
43
73
  it('a normal repo installs at the git-path hooks location', () => {
44
74
  const { root } = mkProject();
@@ -9,7 +9,7 @@ The non-obvious traps — scan these before bootstrapping or upgrading. Each is
9
9
  - **`CLAUDE.md` is a symlink, not a copy.** `ln -s AGENTS.md CLAUDE.md` — single source, no duplication. A copy drifts; a symlink can't.
10
10
  - **Never overwrite an existing entry point or hook.** If `AGENTS.md` / `CLAUDE.md` already exist, or the installer reports a pre-existing non-marker git hook, **stop and ask** the user to merge vs replace — don't clobber.
11
11
  - **Unrecognized invocations are read-only.** Only a **known** subcommand reaches its mode; the **bare** invocation bootstraps (and an existing `docs/ai/` makes it ask upgrade-vs-bootstrap first, never overwrite); **any other / ambiguous** token routes to `help` (read-only). A garbage invocation never writes. The mapping is pinned by `tools/commands.mjs` `routeInvocation` (unit-tested) — don't hand-route around it.
12
- - **No Node runtime → skip enforcement.** If the project has no Node (recon step 1), skip bootstrap steps 8–9 (scripts + hook) and follow the cap/archive/index policy manually, or port the scripts to the project's language. **A skip names a PROVEN fact, never a proxy:** the upgrade ensures judge Node by EVIDENCE — a root `package.json` OR any kit-seeded `scripts/*.mjs` already deployed — and their `skipped-no-node-evidence` line lists every probe that answered absent; a `skipped-*` outcome whose reason the tool could itself disprove is a tool defect, not an outcome. **A skip line that contradicts the observed tree is raised as a finding in the report, never pasted as neutral** — when the tree you can see disproves a skip's stated reason, report the contradiction with the fact named and do not build on the skip.
12
+ - **Enforcement is offered on every project.** The dependency-free scripts are available because the agent host already runs the navigator; for the offer, the only skip condition is that the agent host cannot run them. The hook calls `node scripts/<x>.mjs`, so a committer without `node` on PATH gets the hook's own loud failure. **A skip names a PROVEN fact, never a proxy:** upgrade ensures judge Node by EVIDENCE — a root `package.json` OR any kit-seeded `scripts/*.mjs` already deployed — and the `skipped-no-node-evidence` line lists every probe that answered absent; a reason the tool could disprove is a tool defect. **A skip line that contradicts the observed tree is raised as a finding in the report, never pasted as neutral** — report the contradiction with the proven fact and do not build on the skip.
13
13
  - **Conversational language never translates artifacts.** It governs *dialogue only*. Code, identifiers, paths, commands, log output, abbreviations, and every deployed `docs/ai/` / `AGENTS.md` file stay in their source language. See [Communication contract](${CLAUDE_SKILL_DIR}/references/contracts.md#communication-contract).
14
14
  - **Never auto-commit.** Report quality-gate results and wait for explicit approval — in both modes.
15
15
  - **Never leak kit internals to the user — and a tool-COMPOSED user-facing line holds the same bar at the source.** No ADR ids, tool / function / operation names (`reconcile`, `inject`, `ensureSlot`), marker / slot / fragment / anchor terminology, or verbatim tool stderr **inside the human sentence** of anything the user reads. Translate every tool outcome into plain language a third-party user — who has never read this `SKILL.md` — can understand and act on (e.g. the cap-refusal report in `${CLAUDE_SKILL_DIR}/references/modes/upgrade.md` step 3). The composed lines themselves are **user-grade** language: machine tokens and tool self-labels belong to the **machine-line channel** — the `[run-gates] status=…` grammar (`${CLAUDE_SKILL_DIR}/references/modes/gates.md`), a line's leading self-label/prefix, or a runnable command/path the user can act on — never mid-sentence; alarm words (`PARTIALLY`, `incomplete`, `failed`, `broken`, `persists`) render only in outcomes gated on a **detected abnormal condition**. ONE designed exception, stated not implied: the configuration ensures' LEADING outcome token — one closed-vocabulary token, a failure's closed cause word opening its detail line — is that contract's own machine slot, not a leak. The **verbatim**-paste contract stays: the agent pastes tool-composed outcome lines as written and never re-composes their facts — the lines are user-grade at the source, so pasting them verbatim IS the plain language.
@@ -37,7 +37,7 @@ Read in order, then confirm before starting:
37
37
  Before claiming "done":
38
38
  1. Run all quality gates (lint + type-check + tests) — all green.
39
39
  2. Update docs: `current_state.md` (feature ready), `changelog.md` (entry), `handover.md` (**REPLACE** the last-session block — session delta, never append; older deltas live in `changelog.md` → `history/`), `pages/<page>.md` (matches implementation), the governing spec (its revision lands with the code: `draft` -> `live` on the landing row). Only bump "Last Updated" when content actually changed.
40
- 3. Run the docs cap-validator + index-freshness gate (pre-commit also enforces). On failure: trim the offending file, or run the changelog rotation if the offender is `changelog.md`.
40
+ 3. Run the docs cap-validator + index-freshness gate (the pre-commit hook also enforces it where installed). On failure: trim the offending file, or run the changelog rotation if the offender is `changelog.md`.
41
41
  4. If the work executed a plan file — run that plan's final **Phase: Cleanup** (see the planning skill / §5). Without it the plan is not done.
42
42
  5. **Ask before committing** (§4): report lint / type-check / test counts + docs status, then wait for explicit approval. DO NOT auto-commit.
43
43
 
@@ -20,7 +20,7 @@ maxLines: 700
20
20
  **Changes:**
21
21
  - Created `AGENTS.md` (entry point) + `CLAUDE.md` symlink.
22
22
  - Created `docs/ai/` with the spec files + `pages/`.
23
- - Installed the docs cap-validator / index-freshness / archive scripts + pre-commit hook.
23
+ - Offered the docs cap-validator / index-freshness / archive scripts + pre-commit hook (installed on a yes).
24
24
  - Recorded the real stack, scripts, and architecture into the relevant files.
25
25
 
26
26
  **Quality gates:** n/a (no code changes).