@nurix/etna 0.18.11 → 0.18.12

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.
Files changed (58) hide show
  1. package/README.md +8 -9
  2. package/bin/etna.js +63 -2
  3. package/data/harness-index.json +1 -1
  4. package/data/harnesses/code/CLAUDE.md +9 -10
  5. package/data/harnesses/code/agents/brainstorm.md +3 -3
  6. package/data/harnesses/code/agents/change-review.md +4 -4
  7. package/data/harnesses/code/agents/maintenance.md +177 -59
  8. package/data/harnesses/code/agents/spec-mode.md +3 -3
  9. package/data/harnesses/code/harness.json +2 -2
  10. package/data/harnesses/code/hooks/generate-ownership-index.mjs +148 -0
  11. package/data/harnesses/code/hooks/hooks.json +12 -0
  12. package/data/harnesses/code/skills/boundary/references/boundary-taxonomy.md +3 -3
  13. package/data/harnesses/code/skills/brainstorm/README.md +11 -9
  14. package/data/harnesses/code/skills/brainstorm/SKILL.md +2 -2
  15. package/data/harnesses/code/skills/brainstorm/harvest.md +5 -6
  16. package/data/harnesses/code/skills/distiller/SKILL.md +3 -3
  17. package/data/harnesses/code/skills/distiller/references/docs-mode.md +7 -7
  18. package/data/harnesses/code/skills/documentation/SKILL.md +23 -23
  19. package/data/harnesses/code/skills/documentation/references/templates.md +24 -65
  20. package/data/harnesses/etna/CLAUDE.md +18 -27
  21. package/data/harnesses/etna/agents/brainstorm.md +3 -3
  22. package/data/harnesses/etna/agents/change-review.md +4 -4
  23. package/data/harnesses/etna/agents/maintenance.md +177 -59
  24. package/data/harnesses/etna/agents/spec-mode.md +3 -3
  25. package/data/harnesses/etna/harness.json +2 -2
  26. package/data/harnesses/etna/hooks/generate-ownership-index.mjs +148 -0
  27. package/data/harnesses/etna/hooks/hooks.json +12 -0
  28. package/data/harnesses/etna/rules/npm-cli.md +88 -0
  29. package/data/harnesses/etna/skills/boundary/references/boundary-taxonomy.md +3 -3
  30. package/data/harnesses/etna/skills/brainstorm/README.md +11 -9
  31. package/data/harnesses/etna/skills/brainstorm/SKILL.md +2 -2
  32. package/data/harnesses/etna/skills/brainstorm/harvest.md +5 -6
  33. package/data/harnesses/etna/skills/distiller/SKILL.md +3 -3
  34. package/data/harnesses/etna/skills/distiller/references/docs-mode.md +7 -7
  35. package/data/harnesses/etna/skills/documentation/SKILL.md +23 -23
  36. package/data/harnesses/etna/skills/documentation/references/templates.md +24 -65
  37. package/data/harnesses/hr/harness.json +1 -1
  38. package/data/harnesses/hr/skills/evaluator/criteria/testing.md +4 -4
  39. package/data/harnesses/mobile/CLAUDE.md +9 -10
  40. package/data/harnesses/mobile/agents/brainstorm.md +3 -3
  41. package/data/harnesses/mobile/agents/change-review.md +4 -4
  42. package/data/harnesses/mobile/agents/maintenance.md +177 -59
  43. package/data/harnesses/mobile/agents/spec-mode.md +3 -3
  44. package/data/harnesses/mobile/harness.json +2 -2
  45. package/data/harnesses/mobile/hooks/generate-ownership-index.mjs +148 -0
  46. package/data/harnesses/mobile/hooks/hooks.json +12 -0
  47. package/data/harnesses/mobile/skills/boundary/references/boundary-taxonomy.md +3 -3
  48. package/data/harnesses/mobile/skills/brainstorm/README.md +11 -9
  49. package/data/harnesses/mobile/skills/brainstorm/SKILL.md +2 -2
  50. package/data/harnesses/mobile/skills/brainstorm/harvest.md +5 -6
  51. package/data/harnesses/mobile/skills/distiller/SKILL.md +3 -3
  52. package/data/harnesses/mobile/skills/distiller/references/docs-mode.md +7 -7
  53. package/data/harnesses/mobile/skills/documentation/SKILL.md +23 -23
  54. package/data/harnesses/mobile/skills/documentation/references/templates.md +24 -65
  55. package/package.json +1 -1
  56. package/data/harnesses/code/agents/harness-manager.md +0 -184
  57. package/data/harnesses/etna/agents/harness-manager.md +0 -184
  58. package/data/harnesses/mobile/agents/harness-manager.md +0 -184
package/README.md CHANGED
@@ -28,9 +28,9 @@ your-project/
28
28
  ├── .vscode/settings.json ← editor settings (markdown formatter on save)
29
29
  └── .claude/
30
30
  ├── skills/ ← documentation, boundary, distiller, brainstorm, workflow-mapper
31
- ├── agents/ ← harness-manager, spec-mode, brainstorm, maintenance, change-review, performance-review
31
+ ├── agents/ ← spec-mode, brainstorm, maintenance, change-review, performance-review
32
32
  ├── rules/ ← general.md, nomenclature.md
33
- ├── hooks/ ← post-commit, post-tool-failure, session-stop + lib/redact (knowledge-ledger capture)
33
+ ├── hooks/ ← generate-ownership-index (SessionStart), session-reflect (SessionEnd), prompt-recall (UserPromptSubmit) + lib/redact
34
34
  ├── settings.json ← the hooks are deep-merged in here (your existing keys preserved)
35
35
  └── harness.json ← {version, digest} — the installed-harness sentinel
36
36
  ```
@@ -43,20 +43,19 @@ Re-run `npx @nurix/etna --name=code` anytime to refresh the harness content with
43
43
 
44
44
  Installing only _drops the files_ — the harness isn't active for your repo until you **baseline** it. Open Claude Code in the project and drive the reconcile chain once (the installed `CLAUDE.md` carries the same steps under its `## Bootstrap` heading, for the agent):
45
45
 
46
- 1. **"baseline this repo"** (or "reconcile the harness") — runs the **`harness-manager`** agent. It builds the `docs/` tree to the harness shape, stamps `docs/structure.md` with the installed `harness-version`, then hands back.
47
- 2. If it asks for boundaries (a real codebase whose `docs/boundaries/` is still empty) — run **`/boundary generate`**. It detects your stack + information architecture and writes the typed boundary files.
48
- 3. **"reconcile the harness"** again — `harness-manager` now proposes **modules** from those boundaries.
46
+ 1. **"baseline this repo"** (or "reconcile the harness") — runs the **`maintenance`** agent, which auto-selects **baseline mode** from the missing/behind `harness-version`. It builds the `docs/` tree to the harness shape, stamps `docs/structure.md` with the installed `harness-version`, proposes **modules** (as `module:` labels, derived from your code's bounded contexts), then hands back.
47
+ 2. If it hands back with a follow-up (typically the module proposal), re-invoke it to finish.
49
48
 
50
- Then work normally. This brownfield path reads your _actual_ code, not a blank slate, so it's safe to run on an existing project with real history.
49
+ Then work normally. Boundaries aren't generated as files — the `boundary` skill diagnoses cross-cutting contracts from source at plan time. This brownfield path reads your _actual_ code, not a blank slate, so it's safe to run on an existing project with real history.
51
50
 
52
51
  Two things worth knowing on an existing repo:
53
52
 
54
53
  - **Your root `CLAUDE.md` is replaced** with the harness policy file (the old one is saved to `CLAUDE.md.bak.<ISO>`). If it held project-specific instructions, fold them back in after install — the harness file is the policy skeleton; your domain specifics sit alongside it.
55
- - **The ledger starts on your next commit.** The `post-commit` hook appends to `docs/memory/ledger/`; once enough entries accrue, the `maintenance` agent _proposes_ a `distiller` run that distills them into provenance-linked fact-cards and, eventually, proposed `docs/` updates. Nothing runs on its own — it proposes, you approve.
54
+ - **Memory capture starts on your next session.** The `session-reflect` hook (SessionEnd) distils each session's lessons into the per-actor inbox `docs/memory/inbox/`; once enough entries accrue, the `maintenance` agent _proposes_ a `distiller` run that distils them into provenance-linked fact-cards under `docs/memory/facts/` and, eventually, proposed `docs/` updates. Nothing runs on its own — it proposes, you approve.
56
55
 
57
56
  ### Optional: semantic retrieval (qmd)
58
57
 
59
- If the [`qmd`](https://www.npmjs.com/package/@tobilu/qmd) binary is on your `PATH`, `harness-manager` registers per-subtree search collections so the distiller and the doc anchors get semantic retrieval. It's strictly optional — absent, everything still works on a filename/grep fallback. Install it whenever.
58
+ If the [`qmd`](https://www.npmjs.com/package/@tobilu/qmd) binary is on your `PATH`, the `maintenance` agent (baseline mode) registers per-subtree search collections so the distiller and the doc anchors get semantic retrieval. It's strictly optional — absent, discovery rides the generated ownership index + `keywords:` frontmatter and everything still works on a filename/grep fallback. Install it whenever.
60
59
 
61
60
  ## Migrating from 0.1.x
62
61
 
@@ -90,7 +89,7 @@ Two kinds of membership:
90
89
  name: code
91
90
  skills: [boundary, brainstorm, distiller, documentation, workflow-mapper]
92
91
  rules: [general, nomenclature, typescript]
93
- agents: [brainstorm, change-review, harness-manager, maintenance, performance-review, spec-mode]
92
+ agents: [brainstorm, change-review, maintenance, performance-review, spec-mode]
94
93
  ---
95
94
  ```
96
95
 
package/bin/etna.js CHANGED
@@ -5,6 +5,10 @@
5
5
  // prompts you to pick one. Drops the harness's CLAUDE.md + project-root config
6
6
  // files (.prettierrc.json, .vscode/settings.json, …) at the project root, and
7
7
  // copies its skills, agents, rules, scripts, and hooks into <project>/.claude/.
8
+ // Agents — the brainstorm facilitator plus the generic governance agents
9
+ // (spec-mode, maintenance, change-review, performance-review) —
10
+ // are vendored per-project into <project>/.claude/agents/, the same lifecycle as
11
+ // skills and rules. The CLI writes only inside the target folder; nothing global.
8
12
  // No marketplace, no plugin enablement — files live in the project,
9
13
  // version-controlled and editable per project. Re-run `etna` to refresh.
10
14
  // Harnesses are addressed by their harness/<folder> name; several harnesses may
@@ -181,6 +185,51 @@ function retireOldHooks(targetDir) {
181
185
  return removed;
182
186
  }
183
187
 
188
+ // Component subdirs whose membership is tracked so a removed-from-the-harness component
189
+ // can be pruned on refresh. Hooks are excluded — retireOldHooks owns them (it must also
190
+ // prune the matching settings.json entry, which a name-only diff can't reach).
191
+ const PRUNABLE_SUBDIRS = ['skills', 'agents', 'rules', 'scripts'];
192
+
193
+ // The set of component names the bundle ships, per prunable subdir — the manifest of what
194
+ // THIS harness owns. Written into the installed harness.json so the next refresh can diff.
195
+ function bundledOwned(bundledHarnessDir) {
196
+ const owned = {};
197
+ for (const sub of PRUNABLE_SUBDIRS) {
198
+ const dir = join(bundledHarnessDir, sub);
199
+ owned[sub] = existsSync(dir) ? readdirSync(dir).sort() : [];
200
+ }
201
+ return owned;
202
+ }
203
+
204
+ // Read the `owned` manifest the PREVIOUS install recorded in the project's harness.json.
205
+ // Absent (first install, or pre-pruning version) ⇒ {} ⇒ nothing is pruned this round.
206
+ function readInstalledOwned(targetDir) {
207
+ const path = join(targetDir, '.claude', 'harness.json');
208
+ if (!existsSync(path)) return {};
209
+ const owned = readJson(path).owned;
210
+ return owned && typeof owned === 'object' ? owned : {};
211
+ }
212
+
213
+ // Remove vendored components a prior harness version owned but this one no longer ships
214
+ // (e.g. a retired agent like harness-manager). Only names present in the PRIOR `owned`
215
+ // manifest are eligible, so a project's own components — never in that manifest — survive.
216
+ function pruneOrphanedComponents(targetDir, priorOwned, newOwned) {
217
+ const removed = [];
218
+ for (const sub of PRUNABLE_SUBDIRS) {
219
+ const had = priorOwned[sub] || [];
220
+ const has = new Set(newOwned[sub] || []);
221
+ for (const name of had) {
222
+ if (has.has(name)) continue;
223
+ const target = join(targetDir, '.claude', sub, name);
224
+ if (existsSync(target)) {
225
+ rmSync(target, { recursive: true, force: true });
226
+ removed.push(`orphaned ${sub.replace(/s$/, '')} ${name}`);
227
+ }
228
+ }
229
+ }
230
+ return removed;
231
+ }
232
+
184
233
  // True if an event's matcher-group already carries a hook with this command string.
185
234
  function groupHasCommand(group, command) {
186
235
  return (group.hooks || []).some((h) => h.command === command);
@@ -300,16 +349,28 @@ async function installHarness(harnessName, harnesses) {
300
349
  cpSync(bundledClaudeMd, claudeMdDest, { force: true });
301
350
  installed.push('CLAUDE.md → ./');
302
351
 
352
+ // What a prior install recorded as harness-owned — read before we overwrite the marker,
353
+ // so we can prune anything this bundle has since dropped.
354
+ const priorOwned = readInstalledOwned(targetDir);
355
+
303
356
  for (const sub of PLUGIN_SUBDIRS) {
304
357
  const count = copyHarnessSubdir(join(bundledHarnessDir, sub), join(targetDir, '.claude', sub));
305
358
  if (count > 0) installed.push(`${count} ${sub} → .claude/${sub}/`);
306
359
  }
307
360
 
308
- // Copy the harness marker so harness-manager can resolve the installed version.
361
+ // Prune components a prior harness version owned but this bundle no longer ships (e.g. a
362
+ // retired agent). Only prior-owned names are eligible, so the user's own files survive.
363
+ const newOwned = bundledOwned(bundledHarnessDir);
364
+ for (const r of pruneOrphanedComponents(targetDir, priorOwned, newOwned)) notices.push(`removed ${r}`);
365
+
366
+ // Write the harness marker — plus the `owned` manifest the next refresh diffs against —
367
+ // so the maintenance agent (baseline mode) can resolve the installed version.
309
368
  if (existsSync(bundledHarnessJson)) {
310
369
  const harnessJsonDest = join(targetDir, '.claude', 'harness.json');
311
370
  mkdirSync(dirname(harnessJsonDest), { recursive: true });
312
- cpSync(bundledHarnessJson, harnessJsonDest, { force: true });
371
+ const marker = readJson(bundledHarnessJson);
372
+ marker.owned = newOwned;
373
+ writeJson(harnessJsonDest, marker);
313
374
  }
314
375
 
315
376
  // Verbatim project-root files bundled outside the plugin route (.prettierrc.json,
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "e369db06df16",
2
+ "fingerprint": "acbb6d687e95",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -6,9 +6,9 @@ This file defines how AI agents (Claude, GPT, etc.) should work on this project.
6
6
 
7
7
  ## Bootstrap
8
8
 
9
- > A missing `docs/structure.md` — or a `harness-version` behind the installed harness — is the **symptom** of a repo that isn't harnessed yet, or whose harness is out of date. Don't reconcile it by hand. Drive the **reconcile chain** — you (the main session) own it, because `harness-manager` is a sub-agent that can't run skills or spawn sub-agents:
9
+ > A missing `docs/structure.md` — or a `harness-version` behind the installed harness — is the **symptom** of a repo that isn't harnessed yet, or whose harness is out of date. Don't reconcile it by hand. Drive the **reconcile chain** — you (the main session) own it, because `maintenance` is a sub-agent that can't run skills or spawn sub-agents:
10
10
  >
11
- > 1. Invoke **`harness-manager`** (`"baseline this repo"` / `"reconcile the harness"`). It reconciles `docs/`, stamps the version, then hands back.
11
+ > 1. Invoke **`maintenance`** (`"baseline this repo"` / `"reconcile the harness"`). It auto-selects **baseline mode** from the missing/behind `harness-version`, reconciles `docs/`, stamps the version, then hands back.
12
12
  > 2. If it hands back with a follow-up (typically the module proposal), re-invoke it to finish.
13
13
  >
14
14
  > Then continue. Each component's internals live in the component, not here.
@@ -36,7 +36,7 @@ Three peer modes plus a Completion step — enter wherever the user's thinking a
36
36
  | **Spec** | new feature work | `spec-mode` agent + `documentation` skill | Plan |
37
37
  | **Plan** | a spec is approved | `documentation` skill → `docs/history/plans/YYYY-MM-DD-{slug}.md` | Completion |
38
38
 
39
- On **Completion**: freeze the plan (`Status: Complete`) and flip the feature spec to `Status: Active`, extending it with how-it-works sections; then distil the plan's trail — if the memory inbox (`docs/memory/inbox/`) holds entries, run `distiller facts` (inbox→fact-cards), then `distiller docs` for the just-completed feature's doc drafts any pending deltas for approval (presented, never auto-written). The `boundary` skill gates every approved plan before coding — it reads the source the plan touches and reports what would break (see **Boundaries** below); on brainstorm close, harvest by scope — module pillars → `docs/modules/{m}/pillars/`, cross-module doctrine + contract changes (the deployed-design SOT) → `docs/architecture/` with its decision record → `docs/history/adr/`, backlog → `docs/history/`. Open questions block close.
39
+ On **Completion**: freeze the plan (`Status: Complete`) and flip the feature spec to `status: active`, extending it with how-it-works sections and confirming its `owns:` globs against the actual code; then distil the plan's trail — if the memory inbox (`docs/memory/inbox/`) holds entries, run `distiller facts` (inbox→fact-cards), then `distiller docs` for the just-completed feature's doc drafts any pending deltas for approval (presented, never auto-written). The `boundary` skill gates every approved plan before coding — it reads the source the plan touches and reports what would break (see **Boundaries** below); a brainstorm session is written to a **kept** record at `docs/brainstorm/{topic}/` (committed, one subfolder per topic), and on close harvest distils its conclusions by scope — doctrine, glossary, non-goals, and information-architecture changes → `docs/architecture/`, decisions → `docs/architecture/adr/`, backlog → `docs/history/backlog.md` — leaving the `docs/brainstorm/{topic}/` record in place as the provenance. Open questions block close.
40
40
 
41
41
  ---
42
42
 
@@ -44,11 +44,10 @@ On **Completion**: freeze the plan (`Status: Complete`) and flip the feature spe
44
44
 
45
45
  Before modifying code in an unfamiliar area:
46
46
 
47
- 1. Read **[`docs/routing.md`](docs/routing.md)** — the single map of file-pattern/keyword → canonical doc + module. Match your path or topic to find the owning feature doc and its module; read that doc — and, if its row names a declared module, that module's `CLAUDE.md` + `pillars/` — before changes. (If `routing.md` doesn't exist yet, the repo isn't reconciled — see Bootstrap.)
48
- 2. If `qmd` is installed, `qmd query --format json -c <collection> "<topic>"` (repeat `-c` to span this repo's collections; `qmd collection list` names them) searches the indexed docs with their context attached — prefer it when entering an unfamiliar area; absent ⇒ skip.
47
+ 1. Consult the **injected ownership index** — the generated `glob → doc · module · keywords · status` map, surfaced into context at session start (the union of every feature doc's `owns:` frontmatter). Match your path or topic (its `keywords:`) to the owning feature doc and read it before changes. (If no ownership index appears in context, the repo isn't reconciled — see Bootstrap.)
48
+ 2. If `qmd` is installed, run `qmd query --format json -c <collection> "<topic>"` (repeat `-c` to span this repo's collections; `qmd collection list` names them) for semantic recall over the indexed docs — prefer it when entering an unfamiliar area; absent ⇒ skip.
49
49
  3. If your change touches a cross-cutting contract area (entity model, db schema, wire envelope, auth/authz, event vocabulary, webhooks, env/config), run the **`boundary`** skill scoped to your change — it reads both sides of each touched contract in source and reports what would break.
50
- 4. If a `docs/memory/` file exists for the domain you're working in, read it for domain knowledge and failure modes
51
- 5. When you author a declared module's docs, its `docs/modules/{m}/CLAUDE.md` auto-loads (the pillar bootstrap) — follow it. For code work it's surfaced via step 1.
50
+ 4. If a `docs/memory/` file exists for the domain you're working in, read it for domain knowledge and failure modes.
52
51
 
53
52
  For the protocol on _writing_ to memory (which file, what belongs there, what doesn't), see **Project Memory** below.
54
53
 
@@ -82,9 +81,9 @@ When implementing a plan, if you discover work that is important but outside the
82
81
 
83
82
  ## Doc Ownership
84
83
 
85
- Which doc is canonical for which code paths — and which module each path belongs to — is recorded in **[`docs/routing.md`](docs/routing.md)** (File-Pattern Routes), the single hand-maintained map. Feature docs (in `docs/modules/{m}/features/`, or flat `docs/features/` if the module isn't declared) carry **no** ownership frontmatter; their code paths are their routing row(s). A module is tied to code by its routing patterns (the Module column), not by aggregated globs. Architecture docs describe cross-cutting patterns and don't own specific files; operations docs describe procedures. The only frontmatter a living doc may carry is an optional `anchors:` block (a qmd drift tripwire, not ownership).
84
+ Which doc is canonical for which code paths is the **feature doc's own frontmatter**. A feature doc (flat in `docs/features/`) carries `owns:` (code-path globs — the only ownership key), `module:` (a bounded-context label, omitted when cross-cutting), `keywords:` (discovery), and `status:`. Code → doc ownership is the union of every feature doc's `owns:` globs, surfaced as the generated ownership index at session start. A module is tied to code by the `owns:` globs of the docs carrying its `module:` label — not a folder, not a separate map. Architecture docs describe cross-cutting patterns and don't own specific files; operations docs describe procedures. A living doc may additionally carry an optional `anchors:` block (a qmd drift tripwire, not ownership).
86
85
 
87
- The spec-mode agent checks `routing.md` for ownership conflicts during research (overlapping patterns). If conflicts are found, address them in the spec before proceeding.
86
+ The spec-mode agent checks for ownership conflicts during research — feature docs whose `owns:` globs overlap at equal specificity. If conflicts are found, address them in the spec before proceeding.
88
87
 
89
88
  ---
90
89
 
@@ -120,4 +119,4 @@ Unless explicitly requested:
120
119
  Maintenance triggers (act on these without re-reading `structure.md`):
121
120
 
122
121
  - After plan completion: add a `docs/history/changelog/` entry + update `docs/history/CHANGELOG.md` (no confirmation; include `Commits:` if multi-commit). Non-plan changes (refactors, fixes, API changes): prompt first.
123
- - When you add, move, or delete a doc: update `docs/routing.md` to match. When you move or rename source files: update the matching File-Pattern Route(s) in `docs/routing.md`; a new doc that owns code gets its row(s) there (no frontmatter).
122
+ - When you move or rename source files: update the `owns:` globs of the feature doc that owns them so the generated ownership index stays accurate. A new doc that owns code declares its paths in its own `owns:` frontmatter — there is no separate map to update.
@@ -14,7 +14,7 @@ You are a **thin orchestrator.** Every mechanic — the constant loop, the four
14
14
  ## When to offer a session
15
15
 
16
16
  - An explicit ask to think through a design at a strategic level (not "fix this bug" / "add this button"). This is the user invoking the work; hand it to `/brainstorm start`.
17
- - A user utterance **challenges a loaded pillar headline.** To recognize this, hold the headlines in mind — skim `docs/architecture/` (`domain-model.md`, `glossary.md`, `non-goals.md`, `open-questions.md`) and any `docs/modules/*/pillars/`. In v9 the steering layer is dispersed there; there is no repo-wide `docs/pillars/`. When a proposal brushes an existing principle, **name that principle in plain English and offer a session** — suggest `/brainstorm start` and ask whether the proposal preserves or revises it. Detection is yours; entry is the user's. **Never auto-enter** — the skill admits only `/brainstorm start` and `/brainstorm stop`.
17
+ - A user utterance **challenges a loaded pillar headline.** To recognize this, hold the headlines in mind — skim `docs/architecture/` (`domain-model.md`, `glossary.md`, `non-goals.md`, `open-questions.md`) and its `adr/` decision titles. The steering layer lives there; there are no `docs/modules/` or `docs/pillars/` folders. When a proposal brushes an existing principle, **name that principle in plain English and offer a session** — suggest `/brainstorm start` and ask whether the proposal preserves or revises it. Detection is yours; entry is the user's. **Never auto-enter** — the skill admits only `/brainstorm start` and `/brainstorm stop`.
18
18
 
19
19
  If none of those steering files exist yet (a freshly-baselined repo), a session still runs from the skill's templates, and the basis gate seeds it from a reference doc or a one-shot brain dump.
20
20
 
@@ -28,8 +28,8 @@ Four modes exist — **dump / interview / probe / converge** — and they change
28
28
  - **Suggest, never seize.** Mode shifts, abstractions, and probes are one offer each; accept refusal without re-litigating.
29
29
  - **Never write production code** while a session is open — load-bearing snippets are illustration only, inside the session folder.
30
30
 
31
- You don't perform the harvest yourself, and you don't presume a destination. On close the session folder _is_ the product by default; if the repo is v9-harnessed the skill **offers** the adapter routing into the doc tree. The skill's `## stop` section is the canonical harvest map — don't duplicate it.
31
+ You don't perform the harvest yourself, and you don't presume a destination. On close the skill **offers** the harvest, distilling the pillars' conclusions into wherever the harness routes them. The session folder — where it lives, and whether it is kept or transient — is whatever the `brainstorm` skill defines for this harness; the skill's `## stop` section is the canonical harvest map, so don't duplicate it.
32
32
 
33
33
  ## What you may write
34
34
 
35
- The transient session folder only (its pillars and `state.md`). Never edit the live docs directly — the harvest does that.
35
+ The session folder only (its pillars and `state.md`), wherever the `brainstorm` skill places it for this harness. Never edit the live docs directly — the harvest does that.
@@ -33,7 +33,7 @@ The heatmap needs rolling 1w / 1m / 3m windows, so default `since` to 3 months e
33
33
 
34
34
  1. If `./docs/memory/change-review.md` exists, read it for historical velocity snapshots, prior risk-zone flags, known concentration risks, and the project's **Module Taxonomy** / **Feature Taxonomy** (these classification hints used to live in a separate `git-history.md` memory file — they now live here).
35
35
  2. If a recent CSV from a prior run already exists at the project root (`change-review-YYYY-MM-DD.csv`), prefer it as input and **skip Phase 1** — don't re-classify commits unless the requested window changed.
36
- 3. Read `./docs/routing.md` File-Pattern Routes to map churn to owning feature docs (and their modules).
36
+ 3. Build the ownership map from feature `owns:` frontmatter — consult the injected ownership index (`glob → doc · module · keywords · status`), or glob `docs/features/**/*.md` and read each doc's `owns:` globs — to map churn to owning feature docs (and their `module:` labels).
37
37
 
38
38
  ---
39
39
 
@@ -207,8 +207,8 @@ Trend column: ↑ rising, ↓ falling, → steady, ↑↑ sharply rising, ↓↓
207
207
  For each module with high churn (top quartile in 1m window), check how contract-heavy and how covered it is:
208
208
 
209
209
  - Does its code own cross-cutting contract surfaces (schema/data access, wire handlers, auth/authz, event dispatch, env/config readers)? Skim the module's files to judge — contract-heavy churn is where silent breakage lives.
210
- - Is the module's `owns` doc up to date? (cross-reference with the maintenance agent's last drift check if available)
211
- - Does the module appear in `docs/routing.md`?
210
+ - Is the module's owning feature doc up to date? (cross-reference with the maintenance agent's last drift check if available)
211
+ - Do the module's code paths appear under any feature doc's `owns:` globs?
212
212
 
213
213
  Flag risk zones: high churn × contract-heavy × low doc coverage. These are where silent breakage is most likely.
214
214
 
@@ -231,7 +231,7 @@ Per module, list which authors made the most commits in the 3-month window. Surf
231
231
  - **Risk zones**: top 5 high-churn modules that own contract-heavy surfaces, with the specific contracts at risk named
232
232
  - **Stabilization signals**: modules where review overhead can decrease
233
233
  - **Concentration risks**: bus-factor and review-coverage flags
234
- - **Recommendations**: prioritized list — typically "run the `boundary` skill on changes touching X", "update routing.md to cover Y", "spread reviews of Z across more authors"
234
+ - **Recommendations**: prioritized list — typically "run the `boundary` skill on changes touching X", "add `owns:` coverage for Y to a feature doc", "spread reviews of Z across more authors"
235
235
 
236
236
  ### Update tracking
237
237