@nurix/etna 0.16.0 → 0.17.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.
Files changed (38) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/code/CLAUDE.md +5 -8
  3. package/data/harnesses/code/agents/change-review.md +13 -14
  4. package/data/harnesses/code/agents/harness-manager.md +14 -26
  5. package/data/harnesses/code/agents/maintenance.md +10 -18
  6. package/data/harnesses/code/harness.json +3 -3
  7. package/data/harnesses/code/hooks/hooks.json +2 -2
  8. package/data/harnesses/code/hooks/lib/{redact.js → redact.mjs} +2 -4
  9. package/data/harnesses/{code-fable/hooks/prompt-recall.js → code/hooks/prompt-recall.mjs} +5 -7
  10. package/data/harnesses/{code-fable/hooks/session-reflect.js → code/hooks/session-reflect.mjs} +9 -7
  11. package/data/harnesses/code/rules/general.md +23 -40
  12. package/data/harnesses/code/rules/nomenclature.md +0 -4
  13. package/data/harnesses/code/rules/typescript.md +19 -0
  14. package/data/harnesses/code/skills/boundary/SKILL.md +53 -239
  15. package/data/harnesses/code/skills/brainstorm/harvest.md +2 -2
  16. package/data/harnesses/code/skills/documentation/SKILL.md +2 -4
  17. package/data/harnesses/code/skills/documentation/references/templates.md +12 -89
  18. package/data/harnesses/code-fable/CLAUDE.md +5 -8
  19. package/data/harnesses/code-fable/agents/change-review.md +13 -14
  20. package/data/harnesses/code-fable/agents/harness-manager.md +14 -26
  21. package/data/harnesses/code-fable/agents/maintenance.md +10 -18
  22. package/data/harnesses/code-fable/harness.json +3 -3
  23. package/data/harnesses/code-fable/hooks/hooks.json +2 -2
  24. package/data/harnesses/code-fable/hooks/lib/{redact.js → redact.mjs} +2 -4
  25. package/data/harnesses/{code/hooks/prompt-recall.js → code-fable/hooks/prompt-recall.mjs} +5 -7
  26. package/data/harnesses/{code/hooks/session-reflect.js → code-fable/hooks/session-reflect.mjs} +9 -7
  27. package/data/harnesses/code-fable/rules/general.md +23 -40
  28. package/data/harnesses/code-fable/rules/nomenclature.md +0 -4
  29. package/data/harnesses/code-fable/rules/typescript.md +19 -0
  30. package/data/harnesses/code-fable/skills/boundary/SKILL.md +53 -239
  31. package/data/harnesses/code-fable/skills/brainstorm/harvest.md +2 -2
  32. package/data/harnesses/code-fable/skills/documentation/SKILL.md +2 -4
  33. package/data/harnesses/code-fable/skills/documentation/references/templates.md +12 -89
  34. package/data/harnesses/discover/harness.json +1 -1
  35. package/data/harnesses/discover/rules/evaluation.md +13 -1
  36. package/data/harnesses/discover/rules/ingestion.md +15 -0
  37. package/data/harnesses/discover/rules/tradecraft.md +13 -0
  38. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "19ff4c6bce0e",
2
+ "fingerprint": "b51d4ebd2a1e",
3
3
  "harnesses": {
4
4
  "code": "code-fable",
5
5
  "code-fable": "code-fable",
@@ -9,8 +9,7 @@ This file defines how AI agents (Claude, GPT, etc.) should work on this project.
9
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:
10
10
  >
11
11
  > 1. Invoke **`harness-manager`** (`"baseline this repo"` / `"reconcile the harness"`). It reconciles `docs/`, stamps the version, then hands back.
12
- > 2. If it hands back asking for boundaries (a fresh repo where `docs/boundaries/` is empty), run the **`boundary`** skill in `generate` mode (`/boundary generate`) to populate them.
13
- > 3. Re-invoke **`harness-manager`** so it proposes modules from those boundaries.
12
+ > 2. If it hands back with a follow-up (typically the module proposal), re-invoke it to finish.
14
13
  >
15
14
  > Then continue. Each component's internals live in the component, not here.
16
15
 
@@ -37,7 +36,7 @@ Three peer modes plus a Completion step — enter wherever the user's thinking a
37
36
  | **Spec** | new feature work | `spec-mode` agent + `documentation` skill | Plan |
38
37
  | **Plan** | a spec is approved | `documentation` skill → `docs/history/plans/YYYY-MM-DD-{slug}.md` | Completion |
39
38
 
40
- 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 (`check` mode) checks a plan's Proposed Changes against `docs/boundaries/` before coding; on brainstorm close, harvest by scope — module pillars → `docs/modules/{m}/pillars/`, cross-module doctrine → `docs/architecture/` / ADRs, new contracts → `docs/boundaries/`, 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; 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 → `docs/architecture/` / ADRs, backlog → `docs/history/`. Open questions block close.
41
40
 
42
41
  ---
43
42
 
@@ -48,7 +47,7 @@ Before modifying code in an unfamiliar area:
48
47
  1. If **[`docs/routing.md`](docs/routing.md)** exists, read it for file-pattern → module/doc/agent mapping. If it doesn't exist yet, skip.
49
48
  2. Glob `docs/{features,modules/*/features}/**/*.md` and check `owns` frontmatter to find the owning feature doc (rolled up to its module); read it — and, if it rolled up to a declared module, that module's `CLAUDE.md` + `pillars/` — before changes.
50
49
  3. 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.
51
- 4. **Check [`docs/boundaries/`](docs/boundaries/)** — if your change touches a documented boundary (entity model, schema, API, auth, channels, …), read that boundary file first. A `CRITICAL`/`HIGH` boundary warrants the `boundary` skill (`check` mode) before you start.
50
+ 4. 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.
52
51
  5. If a `docs/memory/` file exists for the domain you're working in, read it for domain knowledge and failure modes
53
52
  6. 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 2.
54
53
 
@@ -92,11 +91,9 @@ The spec-mode agent checks for ownership conflicts during research. If conflicts
92
91
 
93
92
  ## Boundaries
94
93
 
95
- `docs/boundaries/` holds the repo's **typed application boundaries** — the horizontal cross-cutting contracts (the *edges* between modules) where editing one module silently breaks another: e.g. the entity model, tenancy, auth, db-schema, wire-contracts, api, env-parity. Each is one file carrying `[BOUNDARY: type · severity]`, the modules it bounds, its shape (`transcribe`d inline for synthesized contracts, or a `file:line` `point`er for self-locating ones), invariants, blast radius, and a safe-change checklist.
94
+ A boundary is a horizontal cross-cutting contract — entity model, db schema, wire envelope, auth/authz, event vocabulary, webhooks, env/config — where editing one side silently breaks the other. Boundaries are **diagnosed, not documented**: the `boundary` skill reads them fresh from source whenever a check runs, so they are never persisted as docs and can never go stale.
96
95
 
97
- One component owns this surface — the **`boundary` skill** — `generate` at baseline, `create`/`check`/`init` as you add contracts, plan changes, or reconcile. Its frontmatter is the canonical mode catalog over one shared knowledge root (`references/boundary-taxonomy.md`, the exhaustive catalog of boundary types).
98
-
99
- Without `docs/boundaries/` populated (`generate`), the `check` and `init` modes have nothing to check against.
96
+ **Invoke the `boundary` skill after a plan is approved and before its first implementation step.** It parses the plan's Proposed Changes, reads the touched source files, identifies the contracts they participate in (its `references/boundary-taxonomy.md` is the catalog), traces the consumers on the other side, and reports severity-ranked violations with suggested plan amendments — in chat, read-only. Fold the amendments into the plan before coding. For non-plan edits in contract-heavy code, run the same diagnostic scoped to the diff.
100
97
 
101
98
  > Agents and skills live under `.claude/agents/` and `.claude/skills/`. Their triggers are model-invoked — refer to each component's frontmatter, not a registry table here.
102
99
 
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: change-review
3
- description: Velocity + change-risk analysis. First classifies recent commits into a pipe-delimited velocity/severity CSV by dispatching parallel haiku sub-agents (module, feature, impact, severity, churn), then derives a commit heatmap, risk zones (high churn + low boundary coverage), stabilization signals, and team/bus-factor distribution. Self-contained — produces its own CSV, no separate git-history step. Use when planning where to invest in better boundaries or rules.
3
+ description: Velocity + change-risk analysis. First classifies recent commits into a pipe-delimited velocity/severity CSV by dispatching parallel haiku sub-agents (module, feature, impact, severity, churn), then derives a commit heatmap, risk zones (high churn in contract-heavy code), stabilization signals, and team/bus-factor distribution. Self-contained — produces its own CSV, no separate git-history step. Use when planning where to invest in review focus or rules.
4
4
  tools: Bash, Read, Write, Glob, Grep, Task
5
5
  model: inherit
6
6
  ---
7
7
 
8
8
  # Change-Review Agent
9
9
 
10
- You analyze code-change velocity over time to find risk zones — where change is accelerating or decelerating, and whether boundary coverage matches the risk. You answer: "where should the tech lead invest in better boundaries or rules next?"
10
+ You analyze code-change velocity over time to find risk zones — where change is accelerating or decelerating, and whether review attention matches the risk. You answer: "where should the tech lead invest review focus or rules next?"
11
11
 
12
12
  You work in two phases:
13
13
 
@@ -33,8 +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 every file in `./docs/boundaries/` if the folder exists. Risk-zone scoring is "high churn + low boundary coverage" — without boundaries you can only produce a heatmap, not risk zones.
37
- 4. Glob `./docs/{features,modules/*/features}/**/*.md` and read `owns` frontmatter to map churn to owning feature docs.
36
+ 3. Glob `./docs/{features,modules/*/features}/**/*.md` and read `owns` frontmatter to map churn to owning feature docs.
38
37
 
39
38
  ---
40
39
 
@@ -183,7 +182,7 @@ When a commit cannot be classified by a sub-agent, use these defaults:
183
182
 
184
183
  # Phase 2 — Velocity analysis
185
184
 
186
- Where Phase 1 classifies *what* changed, Phase 2 asks *where is change accelerating or decelerating* — and whether boundary coverage matches the risk. Read the CSV from Phase 1 (or the recent one found in Before Starting).
185
+ Where Phase 1 classifies *what* changed, Phase 2 asks *where is change accelerating or decelerating* — and whether review attention matches the risk. Read the CSV from Phase 1 (or the recent one found in Before Starting).
187
186
 
188
187
  ## Step 6: Velocity Heatmap
189
188
 
@@ -202,40 +201,40 @@ Trend column: ↑ rising, ↓ falling, → steady, ↑↑ sharply rising, ↓↓
202
201
 
203
202
  ## Step 7: Risk Zones
204
203
 
205
- For each module with high churn (top quartile in 1m window), check boundary coverage:
204
+ For each module with high churn (top quartile in 1m window), check how contract-heavy and how covered it is:
206
205
 
207
- - Does any `docs/boundaries/` file **Bound** this module (name it in its **Bounds** line)?
206
+ - 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.
208
207
  - Is the module's `owns` doc up to date? (cross-reference with the maintenance agent's last drift check if available)
209
208
  - Does the module appear in `docs/routing.md`?
210
209
 
211
- Flag risk zones: high churn × low coverage. These are where silent breakage is most likely.
210
+ Flag risk zones: high churn × contract-heavy × low doc coverage. These are where silent breakage is most likely.
212
211
 
213
212
  ## Step 8: Stabilization Signals
214
213
 
215
- Identify modules where 1-week and 1-month velocity are both decreasing. Candidates for reducing review overhead — fewer boundaries needed where churn is dropping.
214
+ Identify modules where 1-week and 1-month velocity are both decreasing. Candidates for reducing review overhead — lighter review needed where churn is dropping.
216
215
 
217
216
  ## Step 9: Team Distribution
218
217
 
219
218
  Per module, list which authors made the most commits in the 3-month window. Surface concentration risks:
220
219
 
221
220
  - One author > 70% of commits in a critical module → bus-factor flag
222
- - One author owns all changes touching a boundary → review-coverage flag
221
+ - One author owns all changes touching a contract-heavy surface → review-coverage flag
223
222
 
224
223
  ## Step 10: Report & Track
225
224
 
226
225
  ### Report format
227
226
 
228
227
  - **Velocity heatmap** (table above)
229
- - **Risk zones**: top 5 high-churn / low-coverage modules with specific boundaries to consider adding (via the `boundary` skill, `create` mode)
228
+ - **Risk zones**: top 5 high-churn modules that own contract-heavy surfaces, with the specific contracts at risk named
230
229
  - **Stabilization signals**: modules where review overhead can decrease
231
230
  - **Concentration risks**: bus-factor and review-coverage flags
232
- - **Recommendations**: prioritized list — typically "add a boundary for X (run the `boundary` skill, `create` mode)", "update routing.md to cover Y", "spread reviews of Z across more authors"
231
+ - **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"
233
232
 
234
233
  ### Update tracking
235
234
 
236
235
  1. Write a snapshot to `docs/memory/change-review.md` with date and all four analysis sections above. Preserve any **Module Taxonomy** / **Feature Taxonomy** sections that improve future classification.
237
236
  2. Append items to `docs/history/backlog.md`:
238
- - `- **[P1]** No boundary coverage for high-churn directory \`{dir}/\` — discovered by change-review`
237
+ - `- **[P1]** High churn in contract-heavy directory \`{dir}/\` with no doc coverage — discovered by change-review`
239
238
  3. Report summary to the user
240
239
 
241
240
  ## Rules
@@ -245,5 +244,5 @@ Per module, list which authors made the most commits in the 3-month window. Surf
245
244
  - Always report progress: "Dispatching batch 1-5 of 12..." etc.
246
245
  - If git commands fail (bad branch, bad date range), stop and report the error clearly
247
246
  - Pipe characters in commit messages must be replaced with dashes before writing to CSV
248
- - Risk-zone identification requires boundaries — if `docs/boundaries/` is missing or empty, produce the heatmap only and tell the user that risk-zone scoring needs typed boundaries (run the `boundary` skill, `generate` mode)
247
+ - Risk-zone identification judges contract-heaviness from the code itself (Step 7) — no persisted boundary docs exist or are needed
249
248
  - A clean report (no risk zones) is valid for a low-churn, well-covered project
@@ -20,10 +20,6 @@ Reconcile is **declarative, not a migration ladder.** You converge to the *curre
20
20
 
21
21
  The upgrade story is the two run back-to-back: install refreshes the engine → you reconcile the docs to it.
22
22
 
23
- ## You hand back — the boundary work is a main-session skill
24
-
25
- Generating the typed boundaries is the **`boundary` skill** (`generate` mode), and a skill runs in the *main session* — you are a sub-agent without the Skill tool, so you do **not** run it yourself. When reconcile reaches the boundary step (Step 6) you **return to the main agent with a next-step handoff** — *your final message is your return value*, and the main agent reads it, runs `/boundary generate`, then re-invokes you to propose modules. The chain lives in the caller, because only the main session can run the skill. (Same shape as before — only the target changed from a `boundary-mapper` sub-agent to the `boundary` skill.)
26
-
27
23
  ## Modes
28
24
 
29
25
  - **Reconcile** (incl. **baseline**) — read the repo's `harness-version`; if absent or behind the installed version, converge `docs/` to the installed shape and stamp the new version. The Bootstrap invokes this.
@@ -33,8 +29,8 @@ Generating the typed boundaries is the **`boundary` skill** (`generate` mode), a
33
29
 
34
30
  These are different axes — keep them clean:
35
31
 
36
- - **`maintenance` audits docs-vs-code *fidelity*** — is the documented behavior *true* of the code? (stale docs, broken `owns` globs, routing drift, a boundary file drifted from its source). It edits docs for content accuracy.
37
- - **You audit repo-vs-spec *conformance*** — is the governance *structure* shaped to the installed harness version? (version marker present and current, mandated scaffolds present, no lingering dissolved-version artifacts, modules declared where the boundary graph implies them).
32
+ - **`maintenance` audits docs-vs-code *fidelity*** — is the documented behavior *true* of the code? (stale docs, broken `owns` globs, routing drift). It edits docs for content accuracy.
33
+ - **You audit repo-vs-spec *conformance*** — is the governance *structure* shaped to the installed harness version? (version marker present and current, mandated scaffolds present, no lingering dissolved-version artifacts, modules declared where the code's bounded contexts imply them).
38
34
 
39
35
  You never edit a doc for content fidelity (that is `maintenance`); `maintenance` never reshapes the structure to a new version (that is you). Surfacing a statically-unresolved doc claim as a *question* in your hand-back (Step 1/Step 6) does **not** cross this seam — detection may cross, mutation never does. You observe and ask; you never assert falsity or fix the doc.
40
36
 
@@ -42,7 +38,7 @@ You never edit a doc for content fidelity (that is `maintenance`); `maintenance`
42
38
 
43
39
  1. Verify a **root `CLAUDE.md` exists** before any reconcile. If absent, **refuse** and instruct the user to install/copy the harness `CLAUDE.md` first (the CLI ships it; you never write it) — reconcile against a repo with no root instructions produces a half-installed system. Detect-and-instruct, not a gate.
44
40
  2. Resolve the **installed harness epoch** — read it from `.claude/harness.json`, shipped by the CLI at install. Never a number baked into this file. If `.claude/harness.json` is absent, the install predates the marker ⇒ instruct the user to re-run `npx @nurix/etna code`, then retry. The resolved epoch is the target.
45
- 3. Read the repo's **current version** — the `harness-version` field in `docs/structure.md` frontmatter. Absent ⇒ the repo is unharnessed ⇒ baseline (reconcile from nothing). Equal to installed ⇒ report and stop, **except** when re-invoked to propose modules after `/boundary generate` populated `docs/boundaries/`: the version is already current from your first pass, so skip the stop and go straight to Step 6's populated branch. (Health asked ⇒ run Health.) Behind ⇒ reconcile forward.
41
+ 3. Read the repo's **current version** — the `harness-version` field in `docs/structure.md` frontmatter. Absent ⇒ the repo is unharnessed ⇒ baseline (reconcile from nothing). Equal to installed ⇒ report and stop, **except** when re-invoked for the Step 6 module proposal: the version is already current from your first pass, so skip the stop and go straight to Step 6. (Health asked ⇒ run Health.) Behind ⇒ reconcile forward.
46
42
  4. If `docs/memory/harness-manager.md` exists, read it for project-specific reconcile exceptions and prior decisions.
47
43
 
48
44
  ---
@@ -65,7 +61,6 @@ docs/
65
61
  │ └── {feature}/ # subfolder for deep features
66
62
  ├── modules/ # Declared bounded contexts — NOT scaffolded empty; appear by declaration
67
63
  │ └── {module}/ # CLAUDE.md + features/ + pillars/ (module-local doctrine, lazy)
68
- ├── boundaries/ # Typed application boundaries — generated by the boundary skill
69
64
  ├── operations/ # Setup, development, deployment, CI/CD
70
65
  ├── history/
71
66
  │ ├── CHANGELOG.md # Master changelog index
@@ -88,7 +83,8 @@ This is what makes reconcile more than a fresh scaffold. Detect old-shape artifa
88
83
 
89
84
  | If you find (old shape) | Fold to (current shape) |
90
85
  |---|---|
91
- | `docs/operations/guardrails.md` | one file per boundary under `docs/boundaries/` (then run `/boundary generate`) |
86
+ | `docs/operations/guardrails.md` | fold durable contract notes into `docs/architecture/` |
87
+ | `docs/boundaries/` (legacy persisted boundaries) | delete — boundary analysis is a plan-time diagnostic (the `boundary` skill reads contracts fresh from source); fold any human-authored knowledge (external consumers, intent, accepted exceptions) into `docs/architecture/` |
92
88
  | repo-wide `docs/pillars/` | module-local `docs/modules/{m}/pillars/`; cross-module doctrine → `docs/architecture/` |
93
89
  | `docs/architecture/overview.md` | split into `domain-model.md` / `glossary.md` / `non-goals.md` / `references.md` / `open-questions.md` |
94
90
  | flat feature docs that belong to a declared module | `docs/modules/{m}/features/` |
@@ -120,35 +116,28 @@ If the binary exists, register the docs subtrees once the tree is scaffolded. **
120
116
 
121
117
  1. **Per-subtree collections** — one `qmd collection add` per subtree **that exists** (skip absent ones), `{repo}` = the repo's directory name. Re-run-safe: an existing name/path prints "already exists" and no-ops — treat that as success, not a failure. **Never** `qmd collection add docs/memory` — that re-introduces the inbox; register only its in-scope child `docs/memory/facts`.
122
118
  - `qmd collection add docs/features --name {repo}-features`
123
- - `qmd collection add docs/boundaries --name {repo}-boundaries`
124
119
  - `qmd collection add docs/architecture --name {repo}-architecture`
125
120
  - `qmd collection add docs/operations --name {repo}-operations`
126
121
  - `qmd collection add docs/memory/facts --name {repo}-facts`
127
122
  - `qmd collection add docs/modules --name {repo}-modules`
128
123
  2. **Context tree** — one `qmd context add` per registered collection root **that exists** (skip absent ones); re-add upserts, so it's safe to re-run:
129
124
  - `qmd context add qmd://{repo}-features/ "Feature abstractions — how each works + why it was built"`
130
- - `qmd context add qmd://{repo}-boundaries/ "Typed cross-cutting contracts — severity-ranked seams"`
131
125
  - `qmd context add qmd://{repo}-facts/ "Distilled recent decisions/observations, provenance-linked"`
132
126
  - `qmd context add qmd://{repo}-modules/ "Module-local features + pillars (the module's why)"`
133
127
  3. `qmd embed -c <name>` once per collection just registered — generate the vectors so the lens is queryable. Always scope with `-c` (repeat per collection): the index is global, and a bare `qmd embed` re-embeds every repo's collections on the machine.
134
128
 
135
129
  This augments routing; it never supersedes the Step 6 ownership resolution.
136
130
 
137
- ### Step 6 — Boundaries, then modules — hand back to the main session
138
-
139
- Generating the typed boundaries is the **`boundary` skill** (`generate` mode), which runs in the *main session* — you're a sub-agent without the Skill tool. So you **hand back**, you do not generate boundaries yourself. Your final message *is* your return value to the caller; end it with an explicit next step.
131
+ ### Step 6 — Module proposal
140
132
 
141
- If Step 5b skipped because `qmd` was absent, carry its one advisory line into this hand-back — *"qmd not installed — semantic retrieval unavailable; glob routing active."* — advisory, never an error, never a gate.
133
+ Modules are *declared*, never inferred from physical layout. Derive the repo's candidate bounded contexts directly from the code and docs: distinct wire surfaces (who owns routes/handlers), schema/data-access ownership, entry points and process units, plus any contexts `docs/architecture/` or feature `owns` globs already name.
142
134
 
143
- Branch on whether `docs/boundaries/` is already populated:
135
+ - Propose the derived contexts as candidate modules. For each, partition existing flat feature docs by `owns`-glob overlap.
136
+ - **Propose — don't force.** Declaration is opt-in: a single-context app stays flat (so does a monolith whose contexts all share one kernel); declare `docs/modules/{m}/` only when the author accepts a context as a module. A module is tied to code by its `owns` globs, **layout-blind** — a workspace is not a module (one workspace may hold several contexts; one context may span workspaces).
144
137
 
145
- - **Empty** (typical fresh baseline) → finish here and **hand back**: report what you reconciled (structure + `harness-version` stamped) and end with — *"NEXT (main session): run `/boundary generate` to populate `docs/boundaries/`, then re-invoke me to propose modules (boundaries are now populated)."* Do **not** transcribe the boundary-generation process inline; that blurs the seam and rots. Stop.
146
- - **Populated** (an upgrade reconcile where boundaries already exist, or your second pass after the skill ran) → **propose modules from the boundaries** — modules are *declared*, never inferred from physical layout:
147
- - Read the distinct vertices named across every `docs/boundaries/*` **Bounds** line (e.g. `apps/api`, `@acme/contracts`). These are the repo's bounded contexts, already enumerated.
148
- - Propose them as candidate modules. For each, partition existing flat feature docs by `owns`-glob overlap.
149
- - **Propose — don't force.** Declaration is opt-in: a single-context app stays flat; declare `docs/modules/{m}/` only when the author accepts a context as a module. A module is tied to code by its `owns` globs, **layout-blind** — a workspace is not a module (one workspace may hold several contexts; one context may span workspaces).
138
+ If Step 5b skipped because `qmd` was absent, carry its one advisory line into the hand-back — *"qmd not installed — semantic retrieval unavailable; glob routing active."* — advisory, never an error, never a gate.
150
139
 
151
- Re-running you after the skill is safe — the structure work is already done (idempotent), so the second pass is just the module proposal.
140
+ Re-running you is safe — the structure work is already done (idempotent), so a second pass is just the module proposal.
152
141
 
153
142
  **Observed doc-fidelity questions (advisory, not a gate).** If your Step 1 inventory noted any statically-unresolved doc claims, append them to the hand-back as an **optional** block — each entry phrased **as a question**, never an assertion of falsity:
154
143
 
@@ -172,17 +161,16 @@ Conformance, not fidelity. Report a table; fix nothing destructively without ask
172
161
  - **Published-version currency** *(advisory, network)* — the installed `.claude/harness.json` records the kit's `version`; the published kit may have moved past it. Attempt `npm view @nurix/etna version` (the kit is a restricted package — needs npm auth + network). **Guard:** on *any* failure — offline, no auth, npm absent, timeout — skip and report one line: *"couldn't check the published harness version — re-run `npx @nurix/etna code` to refresh to the latest."* On success, compare the published version against `.claude/harness.json`'s `version`; if published is ahead, recommend re-running the CLI to pull the newer kit. Never a gate, never blocks.
173
162
  - **Kit build fingerprint (digest)** *(informational)* — `.claude/harness.json` carries a `digest`: a deterministic fingerprint of the exact kit **build** the consumer installed (`build-data` computes it over the shipped bundle). Two installs share a digest iff they are byte-identical builds; a hotfix that changes kit bytes without bumping `version` still moves the digest — so it answers *which build am I on*, finer than `version`+`epoch` alone. **Don't recompute it over `.claude/` to self-check:** the installed layout is a superset of the build (the project `CLAUDE.md` sits at the repo root, `.claude/` adds `settings.json`/`harness.json`/local rule files), so paths and file sets differ **by design** — a recompute would never match. The actionable upgrade signals are the two checks above (epoch reconcile + published-version); the digest is provenance, and the seed for any future published-digest drift check.
174
163
  - **Scaffold completeness** — every mandated file present.
175
- - **Dissolved-version residue** — any `operations/guardrails.md`, repo-wide `docs/pillars/`, `architecture/overview.md`, or other old-shape artifact lingering.
176
- - **Module declaration coverage** — do the boundary `Bounds` vertices have declared module homes where the author intended them? (Surface gaps; never auto-declare.)
164
+ - **Dissolved-version residue** — any `operations/guardrails.md`, repo-wide `docs/pillars/`, `architecture/overview.md`, a persisted `docs/boundaries/` tree, or other old-shape artifact lingering.
165
+ - **Module declaration coverage** — do the repo's bounded contexts have declared module homes where the author intended them? (Surface gaps; never auto-declare.)
177
166
  - **`docs/tests/` ownership** — present-with-content, or absent. An empty/orphan `docs/tests/` is a finding (it is author-maintained; no scaffold owns it).
178
167
 
179
168
  ## Rules
180
169
 
181
170
  - **Declarative, idempotent.** Re-running on a current repo is a no-op. Converge to current shape; never replay a version ladder; never reconstruct a past shape.
182
171
  - **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker. Do not reintroduce a `docs/memory/index.md` "is-baselined" check.
183
- - **Modules are declared, layout-blind.** Seed from boundary vertices + `owns` globs; never from `pnpm-workspace.yaml`/workspace walls. Propose, don't force.
172
+ - **Modules are declared, layout-blind.** Seed from the code's bounded contexts + `owns` globs; never from `pnpm-workspace.yaml`/workspace walls. Propose, don't force.
184
173
  - **You orchestrate docs; the `documentation` skill supplies templates.** It is a library — you never expect it to baseline.
185
- - **Hand back for boundaries.** Generating boundaries is the main-session `boundary` skill — you're a sub-agent without the Skill tool, so return a next-step handoff (`run /boundary generate`) and let the main session run it, then re-invoke you. Never transcribe the boundary-generation process inline.
186
174
  - **Never overwrite an existing root `README.md`.** It is human-authored.
187
175
  - **Stay in `docs/` (+ root `README.md` scaffold) and `docs/memory/harness-manager.md`.** You do not edit `CLAUDE.md` (the CLI ships it) or production code.
188
176
  - **Health reports; it does not remediate content.** Content fidelity is `maintenance`'s job.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: maintenance
3
- description: Docs-vs-code coherence audit. Detects and fixes docs drifting from code — stale docs, broken ownership, routing table drift, unowned source paths. Run weekly or after major changes. Contract violations (code drifting from docs) are handled by the `boundary` skill (`init` mode); pre-implementation impact checks by its `check` mode.
3
+ description: Docs-vs-code coherence audit. Detects and fixes docs drifting from code — stale docs, broken ownership, routing table drift, unowned source paths. Run weekly or after major changes. Cross-cutting contract analysis is the `boundary` skill (`check` for plans, `scan` for diffs) — it derives contracts dynamically from source; there are no persisted boundary docs to audit.
4
4
  tools: Read, Glob, Grep, Edit, Write, Bash
5
5
  model: inherit
6
6
  ---
@@ -9,14 +9,14 @@ model: inherit
9
9
 
10
10
  You maintain codebase coherence by detecting drift between docs and code, and fixing it. Scope: stale feature docs, broken ownership, routing table drift, architecture drift, unowned source paths, backlog health.
11
11
 
12
- Out of scope (handled by the `boundary` skill):
13
- - **Code drifted from docs** (boundary violations in live code) → `boundary` skill, `init` mode
14
- - **Pre-implementation impact analysis** (checking a plan against the typed boundaries before coding) → `boundary` skill, `check` mode
12
+ Out of scope (handled by the `boundary` skill, which derives contracts dynamically from source):
13
+ - **Pre-implementation impact analysis** (checking a plan against cross-cutting contracts before coding) → `boundary` skill, `check` mode
14
+ - **Diff-scoped contract analysis** (what could a change break across module edges) → `boundary` skill, `scan` mode
15
15
 
16
16
  ## Before Starting
17
17
 
18
18
  1. If `./docs/memory/maintenance.md` exists, read it for last review state, ownership snapshots, high-churn paths, and known failure modes.
19
- 2. If `./docs/boundaries/` exists, read its files for context on the typed cross-module contracts the docs should reflect.
19
+ 2. If `./docs/memory/boundary.md` exists, read it for durable contract knowledge (external consumers, known gaps, accepted exceptions) relevant to the docs you audit.
20
20
  3. If `./docs/routing.md` exists, read it for the current file-pattern-to-doc mapping.
21
21
 
22
22
  ## Step 1: Build Ownership Map
@@ -25,7 +25,7 @@ Out of scope (handled by the `boundary` skill):
25
25
  2. Glob `docs/{features,modules/*/features}/**/*.md` and extract YAML frontmatter (`owns`, `touches`, `depends_on`)
26
26
  3. Build a map: glob pattern → owning doc
27
27
 
28
- **Boundary-first fallback.** If that glob yields **no `owns` frontmatter at all** (a real possibility — a boundary-first repo can carry thousands of LOC, a populated `docs/boundaries/`, and zero feature docs) **but `docs/boundaries/**` exists**, drive this pass's ownership/drift surface off the boundaries instead: each boundary's `Bounds`/`Shape` referents (the modules/paths it names) plus `docs/architecture/**` file-references become the **primary** ownership map for Steps 2–5. Feature-`owns` stays primary the moment any appears — this is a fallback, not a replacement. Don't re-mechanize the named-referent / path checks here; Step 2 already resolves boundary referents and Step 5 already greps architecture paths — this clause just promotes them to primary when feature-owns is empty. **Exempt the pre-code markers:** a referent a boundary marks `planned`/`point*`/`transcribe*` is intentionally not-yet-landed — never flag it absent (that is the greenfield contract, not drift); only a referent whose target *has* landed fires, via Step 2's planned-landed / transcribe-landed checks.
28
+ **Architecture-first fallback.** If that glob yields **no `owns` frontmatter at all** (a fresh-baseline repo can carry thousands of LOC and zero feature docs), drive this pass's ownership/drift surface off `docs/architecture/**` file-references instead — they become the **primary** ownership map for Steps 2–5. Feature-`owns` stays primary the moment any appears — this is a fallback, not a replacement.
29
29
 
30
30
  ## Step 2: Validate Ownership
31
31
 
@@ -38,17 +38,9 @@ For each code symbol or path a doc explicitly **names** (function/export/route/t
38
38
  - Flag unresolved named referents as drift, phrased as a question (e.g. `docs/x.md:NN names fn() — no static definition found; confirm it is not generated/re-exported before treating as stale`)
39
39
  - On codegen/reflection/DI/barrel stacks where static resolution is unreliable, skip — yielding nothing is correct
40
40
 
41
- Also resolve **`point`-mode boundary pointers** in `docs/boundaries/**/*.md` — a boundary whose `Bounds`/`Shape` carries a `file:line` pointer (e.g. `self-locating in lib/db.js:14`):
42
- - Verify the named path still exists; a rename (e.g. `lib/db.js`→`lib/store.js`) leaves a stale pointer that **distill② can never repair — boundary docs are write-protected** — so this pass is where it surfaces, as a question
43
- - If the boundary carries a literal **`planned`** marker (or "pointer lands at implementation") on a named target **and that target now resolves to real code**, the pointer has gone stale the other way — the code landed but the doc still says planned. Raise it as a question (e.g. `db-schema.md is marked planned but packages/api/src/db/schema.ts now exists — confirm and convert the pointer to file:line`). A barrel/re-export at the named path counts as landed.
44
- - Same skip rule on unreliable-resolution stacks
45
-
46
- Also handle **`transcribe`-mode boundaries** — a boundary whose `Shape` transcribes a contract (an event/wire/config shape copied from doctrine) **until** the owning module lands, typically with a checklist line like *"replace this transcription when X lands"*:
47
- - If **X now exists**, the transcribed shape can have silently diverged from the real one — and a transcription names fields, so the divergence is field-level, not path-level (e.g. an event transcribed as `{ entity, event_kind, … }` against a landed module that uses `eventKind`). Raise it as a question that the transcribed shape be reconciled against the real one — or handed to a proposed `boundary init` run for that file (e.g. `outbox-events.md transcribes event_kind but the landed outbox module uses eventKind — confirm the transcription should be reconciled to the real shape`). Question-phrased, never asserted; never rewrite the boundary doc yourself (write-protected).
48
-
49
- Also check **`env-var-contract` boundaries** — a boundary whose job is to assert the env contract (typically *"every variable the code reads appears in `.env.example`"*). The named-referent check above covers code symbols and paths but not env vars, which live in a separate canonical file:
50
- - Extract the `UPPER_SNAKE` tokens the boundary names in its `Shape` (allow a trailing `*` glob, e.g. `MASTER_KEK*` matching `MASTER_KEK`, `MASTER_KEK_ID`). Grep each against the declared canonical `.env`/`.env.example` (the boundary names which file is canonical).
51
- - Raise any absence as a question (e.g. `env-vars.md names MASTER_KEK* but no MASTER_KEK* appears in .env.example — confirm the contract still holds`). Same skip rule when the canonical file isn't declared or doesn't exist.
41
+ Also check the **env contract** when the repo declares a canonical `.env.example` (or equivalent). The named-referent check above covers code symbols and paths but not env vars, which live in a separate canonical file:
42
+ - Extract the `UPPER_SNAKE` env keys the code reads (`process.env.X` and the deploy scripts' generated env). Grep each against the canonical `.env.example`.
43
+ - Raise any absence as a question (e.g. `server reads MASTER_KEK but no MASTER_KEK appears in .env.example — confirm the contract still holds`). Skip when no canonical file exists.
52
44
 
53
45
  ## Step 3: Detect Doc Drift
54
46
 
@@ -108,7 +100,7 @@ If `qmd` is absent (`command -v qmd` finds nothing), **skip this whole step sile
108
100
 
109
101
  This catches **doc-area drift** — the subject the doc abstracts moving or vanishing from the indexed corpus. It does **not** catch a pure code rename that leaves the doc's prose unchanged: the anchor query semantically matches the doc's own text, so the result set doesn't shift. Code-symbol drift is Step 2's named-referent check, not this one — the two are complementary, not redundant.
110
102
 
111
- Glob `docs/{features,modules/*/features}/**/*.md`, `docs/boundaries/**/*.md`, `docs/architecture/**/*.md`, and `docs/operations/**/*.md` for docs carrying `anchors:` frontmatter. For each anchor query on such a doc, resolve it with `qmd query --format json -c <collection> "<query>"` — repeat `-c` per relevant `{repo}-*` collection (no comma lists; the collection set is what `qmd collection list` shows). If a query resolves to **nothing**, or to a result set that has **radically shifted** away from the area the doc describes, raise it as a drift finding **phrased as a question** — e.g. `docs/x.md anchors "<query>" — resolves to nothing; confirm the area moved before treating the doc as stale` — and ask the user. On **yes**, dispatch the remediation sub-agent (the same yes-branch as Step 6). On **decline or no action**, append it to `docs/history/backlog.md` at the finding's own P0–P3 severity per the **Declined realignment** branch in Step 6 — same scale, deduped, never a gate.
103
+ Glob `docs/{features,modules/*/features}/**/*.md`, `docs/architecture/**/*.md`, and `docs/operations/**/*.md` for docs carrying `anchors:` frontmatter. For each anchor query on such a doc, resolve it with `qmd query --format json -c <collection> "<query>"` — repeat `-c` per relevant `{repo}-*` collection (no comma lists; the collection set is what `qmd collection list` shows). If a query resolves to **nothing**, or to a result set that has **radically shifted** away from the area the doc describes, raise it as a drift finding **phrased as a question** — e.g. `docs/x.md anchors "<query>" — resolves to nothing; confirm the area moved before treating the doc as stale` — and ask the user. On **yes**, dispatch the remediation sub-agent (the same yes-branch as Step 6). On **decline or no action**, append it to `docs/history/backlog.md` at the finding's own P0–P3 severity per the **Declined realignment** branch in Step 6 — same scale, deduped, never a gate.
112
104
 
113
105
  ---
114
106
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "harness": "code",
3
3
  "name": "code-fable",
4
- "version": "0.15.3",
5
- "epoch": 13,
6
- "digest": "c7bce77bd71f"
4
+ "version": "0.17.0",
5
+ "epoch": 14,
6
+ "digest": "adc67e13b079"
7
7
  }
@@ -6,7 +6,7 @@
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/session-reflect.js\"",
9
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/session-reflect.mjs\"",
10
10
  "async": true
11
11
  }
12
12
  ]
@@ -18,7 +18,7 @@
18
18
  "hooks": [
19
19
  {
20
20
  "type": "command",
21
- "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/prompt-recall.js\""
21
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/prompt-recall.mjs\""
22
22
  }
23
23
  ]
24
24
  }
@@ -1,6 +1,4 @@
1
- // harness/code/hooks/lib/redact.js — shared privacy filter: redacts secret shapes before ledger append.
2
-
3
- "use strict";
1
+ // harness/code/hooks/lib/redact.mjs — shared privacy filter: redacts secret shapes before ledger append.
4
2
 
5
3
  // Patterns ordered most-specific first; each replaces a match with [redacted:{kind}].
6
4
  const RULES = [
@@ -34,4 +32,4 @@ function redact(text) {
34
32
  return out;
35
33
  }
36
34
 
37
- module.exports = { redact };
35
+ export { redact };
@@ -1,11 +1,9 @@
1
- // plugins/code/hooks/prompt-recall.js — UserPromptSubmit hook: surface fact-cards relevant to the prompt via qmd BM25; stdout is injected as context.
1
+ // plugins/code/hooks/prompt-recall.mjs — UserPromptSubmit hook: surface fact-cards relevant to the prompt via qmd BM25; stdout is injected as context.
2
2
 
3
- "use strict";
4
-
5
- const fs = require("fs");
6
- const os = require("os");
7
- const path = require("path");
8
- const { execFileSync } = require("child_process");
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { execFileSync } from "node:child_process";
9
7
 
10
8
  const MIN_PROMPT_CHARS = 24;
11
9
  const MIN_SCORE = 0.45;
@@ -1,12 +1,14 @@
1
- // plugins/code/hooks/session-reflect.js — SessionEnd hook: reflect the session into durable lessons (headless haiku pass) appended to the actor's memory inbox.
1
+ // plugins/code/hooks/session-reflect.mjs — SessionEnd hook: reflect the session into durable lessons (headless haiku pass) appended to the actor's memory inbox.
2
2
 
3
- "use strict";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { execFileSync, spawn } from "node:child_process";
7
+ import { fileURLToPath } from "node:url";
8
+ import { redact } from "./lib/redact.mjs";
4
9
 
5
- const fs = require("fs");
6
- const os = require("os");
7
- const path = require("path");
8
- const { execFileSync, spawn } = require("child_process");
9
- const { redact } = require("./lib/redact.js");
10
+ // ESM has no __filename; derive it from this module's URL for the detached worker re-spawn.
11
+ const __filename = fileURLToPath(import.meta.url);
10
12
 
11
13
  // A session below all three thresholds carries no lesson worth a model call.
12
14
  const MIN_TURNS = 8;
@@ -1,23 +1,14 @@
1
- ---
2
- applyTo: "**"
3
- ---
1
+ # General Standards
4
2
 
5
- # Technology Choices & Standards
6
-
7
- Opinionated technology stack and implementation standards.
8
-
9
- ## Environment & Versions
10
-
11
- ### Runtime Versions
3
+ ## Runtime Versions
12
4
 
13
5
  - **Node.js:** 22 LTS (latest)
14
- - **Package manager:** project-determined — detect from lockfile (`pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `package-lock.json` → npm). Use the matching command in scripts; don't hardcode a specific manager.
15
- - **PostgreSQL:** 17
16
- - **Redis:** 7.x (latest)
6
+ - **Package manager:** detect from lockfile (`pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `package-lock.json` → npm). Don't hardcode one.
7
+ - **PostgreSQL:** 17 · **Redis:** 7.x (latest)
17
8
 
18
- ### Recommended Packages
9
+ ## Recommended Packages
19
10
 
20
- No alternatives. No explanations for obvious choices. Just use these.
11
+ No alternatives. Just use these.
21
12
 
22
13
  | Package | Version | Use | Don't use |
23
14
  | ------------------------ | --------- | ---------------------- | ----------------------- |
@@ -36,8 +27,8 @@ No alternatives. No explanations for obvious choices. Just use these.
36
27
  | react-window | ^2.2.3 | List virtualization | react-virtualized |
37
28
  | nanoid | ^5.1.6 | ID generation | uuid |
38
29
  | express | ^5.2.1 | HTTP server | fastify, koa |
39
- | prisma | ^7.2.0 | Database ORM | sequelize, typeorm |
40
- | @prisma/client | ^7.2.0 | Database queries | - |
30
+ | drizzle-orm | latest | Database ORM | prisma, sequelize, typeorm |
31
+ | drizzle-kit | latest | Schema tooling | - |
41
32
  | zod | ^4.2.1 | Schema validation | yup, joi |
42
33
  | jose | ^6.1.3 | JWT handling | jsonwebtoken |
43
34
  | microdiff | ^1.5.0 | JSON object diffing | deep-diff, just-diff |
@@ -49,15 +40,24 @@ No alternatives. No explanations for obvious choices. Just use these.
49
40
  | cmdk | ^1.1.1 | Command palette | kbar, ninja-keys |
50
41
  | @monaco-editor/react | ^4.7.0 | Code editor | codemirror, ace |
51
42
  | localforage | ^1.10.0 | Client-side storage | idb, dexie |
52
- | socket.io-client | ^4.7.0 | WebSocket client | native WebSocket, ws |
53
43
  | react-markdown | ^10.1.0 | Markdown rendering | marked, markdown-it |
54
44
  | fast-deep-equal | ^3.1.3 | Deep equality checks | lodash.isEqual |
55
45
  | @ngneat/falso | latest | Fake data generation | @faker-js/faker, chance |
56
46
  | pino | ^10.1.0 | Logging | winston |
57
47
 
58
- ---
48
+ ## Frontend
49
+
50
+ Tailwind v4 + shadcn-based UI; conventions below.
51
+
52
+ - **@nurix/components** — the UI component library (linked, pre-built); import by subpath, e.g. `@nurix/components/button`.
53
+ - No components.json / shadcn CLI scaffold (.tsx, not .jsx) — consume the prebuilt library; never `npx shadcn add`.
54
+ - Vite: `@tailwindcss/vite` + `@vitejs/plugin-react-swc`. Pin react / react-dom / react/jsx-runtime / react/jsx-dev-runtime to the app's single copy via `resolve.alias` (linked @nurix/* ship nested react — keep one hook dispatcher).
55
+ - Tailwind v4, CSS-only (no tailwind.config.js, no PostCSS): styling runs through the `@tailwindcss/vite` plugin.
56
+ - CSS entry `globals.css`, imports in order — `@import "./personality.css"` (token source) → `@import "tailwindcss"` → the library's `styles.css` — then `@theme inline {…}` mapping vars to tokens.
57
+ - Tokens: CSS vars in `:root, :root[data-theme="light"]` + the archetype selector `[data-style="…"]` (personality.css), consumed as semantic Tailwind tokens (bg-card, text-foreground). Honor the archetype's radius/theme decisions (e.g. re-assert `--radius-*` to 0 for a flat archetype; add `@custom-variant dark` only if the project supports dark mode). The library bundles class-variance-authority, clsx, tailwind-merge.
58
+ - Plus general styling rules (spacing in 2/4/6/8, object-cover, truncate, motion, color tokens — never hardcoded hex in components).
59
59
 
60
- ## Express 5.x Setup
60
+ ## Express 5.x
61
61
 
62
62
  ```javascript
63
63
  app.use(cors({ origin: process.env.FRONTEND_URL }));
@@ -66,31 +66,14 @@ app.use(express.json({ limit: "10mb" }));
66
66
  app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
67
67
  ```
68
68
 
69
- - Middleware order: body parsers, custom middleware, routes, error handlers
70
- - Use Express Router for modular routes
71
- - Centralized error handler as last middleware
72
- - Use middleware for auth
73
-
74
- ---
69
+ - Middleware order: body parsers → custom middleware → routes → error handlers (centralized, last). Auth via middleware. Use Express Router for modular routes.
75
70
 
76
71
  ## API Response Format
77
72
 
78
73
  ```json
79
- {
80
- "status": 1,
81
- "message": "Message sent successfully",
82
- "data": { "delivered": [{ "user@example.com": 2 }] }
83
- }
74
+ { "status": 1, "message": "Message sent successfully", "data": { "delivered": [{ "user@example.com": 2 }] } }
84
75
  ```
85
76
 
86
- **Error:**
87
-
88
- ```json
89
- {
90
- "status": 0,
91
- "message": "Error description",
92
- "data": null
93
- }
94
- ```
77
+ Error: `{ "status": 0, "message": "Error description", "data": null }`
95
78
 
96
79
  HTTP codes: `200`, `201` (created), `400`, `401` (not authenticated), `403` (not authorized), `404`, `500`
@@ -1,7 +1,3 @@
1
- ---
2
- applyTo: "**"
3
- ---
4
-
5
1
  # Nomenclature Guidelines
6
2
 
7
3
  ## Naming Guidelines
@@ -0,0 +1,19 @@
1
+ # TypeScript
2
+
3
+ TypeScript conventions. Compiles under `strict: true` and `noUncheckedIndexedAccess: true`.
4
+
5
+ ## Type Safety
6
+
7
+ - Never `any` to silence the checker. Unknown value → type `unknown`, then narrow (type guard / `zod` parse).
8
+ - Never weaken strictness. No `// @ts-nocheck`; `// @ts-expect-error` only with a same-line reason.
9
+ - Infer locals & return types; annotate at boundaries (exports, props, contracts).
10
+
11
+ ## Generics
12
+
13
+ Shared libraries (`@nurix/components`, etc.) are generic on purpose — that's what types `cell(row)`, checks `slug` against `keyof TData`, and ties `data`/`columns` together. Keep the safety; never widen to `any` to dodge it. State the row type **once per file**, then let inference carry it:
14
+
15
+ - **Bind a repeated factory once** (preferred): `const col = defineColumn<BriefRow>;` → `col({...})`. No `<T>` per call; `row` stays typed. Canonical: `modules/briefs/BriefsListPage.tsx`.
16
+ - **Infer JSX type args from props:** `<Table data={rows} columns={columns} />`, not `<Table<BriefRow> …>`.
17
+ - **Anchor with a collection annotation** when nothing else can: `const columns: ColumnDefinition<BriefRow>[] = [...]`.
18
+
19
+ Don't repeat `fn<Type>(…)` / `<Comp<Type>>` at every call site — cosmetic only (same safety, same emitted JS).