@nurix/etna 0.20.25 → 0.20.27

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 (75) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/code/CLAUDE.md +4 -4
  3. package/data/harnesses/code/agents/bookkeeper.md +1 -1
  4. package/data/harnesses/code/agents/change-review.md +1 -1
  5. package/data/harnesses/code/agents/lld-mode.md +1 -1
  6. package/data/harnesses/code/agents/maintenance.md +7 -9
  7. package/data/harnesses/code/docs/structure.md +133 -71
  8. package/data/harnesses/code/harness.json +4 -4
  9. package/data/harnesses/code/hooks/awareness.mjs +0 -10
  10. package/data/harnesses/code/hooks/lib/ownership.mjs +4 -2
  11. package/data/harnesses/code/hooks/lib/sweep.mjs +4 -8
  12. package/data/harnesses/code/skills/documentation/SKILL.md +22 -11
  13. package/data/harnesses/code/skills/documentation/references/examples.md +29 -25
  14. package/data/harnesses/code/skills/documentation/references/frontmatter.md +3 -3
  15. package/data/harnesses/code/skills/documentation/references/style-guide.md +211 -292
  16. package/data/harnesses/code/skills/documentation/references/untemplated.md +4 -2
  17. package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +104 -2
  18. package/data/harnesses/code/skills/documentation/templates/Readme.md +4 -3
  19. package/data/harnesses/code/skills/documentation/templates/bookkeeping.md +1 -1
  20. package/data/harnesses/code/skills/documentation/templates/docs-readme.md +15 -36
  21. package/data/harnesses/code/skills/documentation/templates/doctrine.md +81 -0
  22. package/data/harnesses/code/skills/documentation/templates/feature.md +63 -119
  23. package/data/harnesses/code/skills/documentation/templates/handover.md +174 -0
  24. package/data/harnesses/code/skills/documentation/templates/operations-procedure.md +1 -1
  25. package/data/harnesses/code/skills/documentation/templates/package.md +49 -92
  26. package/data/harnesses/code/skills/documentation/templates/root-readme.md +103 -65
  27. package/data/harnesses/code/skills/documentation/templates/setup.md +138 -0
  28. package/data/harnesses/code/skills/documentation/templates/system.md +45 -107
  29. package/data/harnesses/delivery/agents/lld-mode.md +1 -1
  30. package/data/harnesses/delivery/agents/maintenance.md +7 -9
  31. package/data/harnesses/delivery/harness.json +2 -2
  32. package/data/harnesses/delivery/skills/documentation/SKILL.md +22 -11
  33. package/data/harnesses/delivery/skills/documentation/references/examples.md +29 -25
  34. package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +3 -3
  35. package/data/harnesses/delivery/skills/documentation/references/style-guide.md +211 -292
  36. package/data/harnesses/delivery/skills/documentation/references/untemplated.md +4 -2
  37. package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +104 -2
  38. package/data/harnesses/delivery/skills/documentation/templates/Readme.md +4 -3
  39. package/data/harnesses/delivery/skills/documentation/templates/bookkeeping.md +1 -1
  40. package/data/harnesses/delivery/skills/documentation/templates/docs-readme.md +15 -36
  41. package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +81 -0
  42. package/data/harnesses/delivery/skills/documentation/templates/feature.md +63 -119
  43. package/data/harnesses/delivery/skills/documentation/templates/handover.md +174 -0
  44. package/data/harnesses/delivery/skills/documentation/templates/operations-procedure.md +1 -1
  45. package/data/harnesses/delivery/skills/documentation/templates/package.md +49 -92
  46. package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +103 -65
  47. package/data/harnesses/delivery/skills/documentation/templates/setup.md +138 -0
  48. package/data/harnesses/delivery/skills/documentation/templates/system.md +45 -107
  49. package/data/harnesses/etna/agents/change-review.md +1 -1
  50. package/data/harnesses/etna/agents/lld-mode.md +1 -1
  51. package/data/harnesses/etna/agents/maintenance.md +7 -9
  52. package/data/harnesses/etna/harness.json +2 -2
  53. package/data/harnesses/etna/skills/documentation/SKILL.md +22 -11
  54. package/data/harnesses/etna/skills/documentation/references/examples.md +29 -25
  55. package/data/harnesses/etna/skills/documentation/references/frontmatter.md +3 -3
  56. package/data/harnesses/etna/skills/documentation/references/style-guide.md +211 -292
  57. package/data/harnesses/etna/skills/documentation/references/untemplated.md +4 -2
  58. package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +104 -2
  59. package/data/harnesses/etna/skills/documentation/templates/Readme.md +4 -3
  60. package/data/harnesses/etna/skills/documentation/templates/bookkeeping.md +1 -1
  61. package/data/harnesses/etna/skills/documentation/templates/docs-readme.md +15 -36
  62. package/data/harnesses/etna/skills/documentation/templates/doctrine.md +81 -0
  63. package/data/harnesses/etna/skills/documentation/templates/feature.md +63 -119
  64. package/data/harnesses/etna/skills/documentation/templates/handover.md +174 -0
  65. package/data/harnesses/etna/skills/documentation/templates/operations-procedure.md +1 -1
  66. package/data/harnesses/etna/skills/documentation/templates/package.md +49 -92
  67. package/data/harnesses/etna/skills/documentation/templates/root-readme.md +103 -65
  68. package/data/harnesses/etna/skills/documentation/templates/setup.md +138 -0
  69. package/data/harnesses/etna/skills/documentation/templates/system.md +45 -107
  70. package/lib/install/materialize.mjs +4 -12
  71. package/lib/install/plan.mjs +4 -11
  72. package/package.json +3 -2
  73. package/data/harnesses/code/skills/documentation/templates/structure.md +0 -71
  74. package/data/harnesses/delivery/skills/documentation/templates/structure.md +0 -71
  75. package/data/harnesses/etna/skills/documentation/templates/structure.md +0 -71
@@ -0,0 +1,138 @@
1
+ # Setup (docs/operations/setup.md)
2
+
3
+ Truth document, operations genre (`type: operations`). Use for: **the one-time path from a fresh machine to a first verified run.** It covers what the repo is built on, prerequisites, install, env files, local services, the first commands, proof that it works, and the failures a fresh clone hits. There is **one per repo**, always named `setup.md`, and it is a mandated scaffold. The root README's only setup content is a Destinations row linking it.
4
+
5
+ It is distinct from `local-development.md`, the daily loop: watch modes, resetting state, per-package traps, the inner test cycle. Setup runs once per machine. Local development runs every session. Setup ends by handing off to it, and neither copies the other. Deploying is `deployment.md`.
6
+
7
+ Required: **Goal**, **Stack**, **Prerequisites**, **Install**, **First run**, **Verify**. Optional, included only with real content: the audience fork, **Before cloning**, **Environment files**, **Local services**, **Reset**, **Common failures**.
8
+
9
+ ### Writing rules
10
+
11
+ - **Never write a version a file already pins.** Each row names the pinning file (`.nvmrc`, `package.json` `engines` / `packageManager`, `rust-toolchain.toml`, `go.mod`) and the command that checks it. A typed number is a second source that drifts on the next bump.
12
+ - **Stack is one row per layer.** Give the technology, what it is for in this repo, and where its version is pinned. Why it was chosen belongs to `docs/architecture/`, linked once. Don't repeat the dependency list: the manifests are the roster.
13
+ - **One path, from the lockfile.** `pnpm-lock.yaml` gives pnpm, `yarn.lock` gives yarn, otherwise npm. Say how it is activated (`corepack enable`). Never write "or npm / yarn". Give a per-OS variant only where the commands really differ.
14
+ - **Traps before commands.** Anything a fresh clone hits before the first command goes in Before cloning, not halfway down the steps: LFS, submodules, a required stub file, an access grant, a credential that has to be requested.
15
+ - **Copy-paste runnable, one action per step, each with its expected outcome.** Run non-interactively where the tool allows it, so an agent can execute the step unchanged. "It should work now" is never a step.
16
+ - **Script first, then document.** If a bootstrap script or task exists, it is the step, and the doc carries only the judgment around it. A setup sequence run often with no script gets a script.
17
+ - **Env files as a table, never a variable dump.** One row per file: where it is copied from, what must be filled, where the values come from, whether it is required to boot. The variable contract is the example file and the code's env type, linked and never copied. Secret values never appear.
18
+ - **Destructive commands state their blast radius where they appear:** what is deleted or truncated, whether it prompts, and the flag that skips the prompt.
19
+ - **Verification is observable:** a health probe and its expected status, a URL and what it shows, a seeded login, a doctor command and its output, or the test command passing from a cold shell.
20
+ - **Common failures are keyed by the exact error text,** followed by the cause and the fix, where the fix is a command or a file edit. Append a failure only once it has been root-caused, never as speculation.
21
+ - **Per-package divergence is a subsection of this file.** A unit whose setup differs gets a `### {unit}` block under First run, or a row linking its own procedure. It never gets a second setup doc.
22
+
23
+ ### Template
24
+
25
+ ```markdown
26
+ ---
27
+ type: operations
28
+ ---
29
+
30
+ # Setup
31
+
32
+ **Goal:** take a fresh machine from clone to a verified first run of {what runs: e.g. "the product Worker on :{port} and the web shell on :{port}, signed in as the dev fixture"}. Done once per machine; the daily loop is [`local-development.md`]({local-development}.md).
33
+
34
+ {Optional audience fork: "Only running {the CLI / one package}? Stop after Install and see [`{procedure}`]({path})."}
35
+
36
+ ## Stack
37
+
38
+ | Layer | Technology | For | Version pinned by |
39
+ | --- | --- | --- | --- |
40
+ | {Runtime} | {Node} | {what runs on it} | [`.nvmrc`](../../.nvmrc) |
41
+ | {Server} | {framework · data layer} | {what it serves} | [`{package.json}`](../../{path}/package.json) |
42
+ | {Client} | {framework · build tool · styling} | {which surfaces} | [`{package.json}`](../../{path}/package.json) |
43
+ | {Tests} | {runners} | {unit · e2e} | {manifest} |
44
+
45
+ Why these were chosen: [{system overview}](../architecture/{overview}.md).
46
+
47
+ ## Prerequisites
48
+
49
+ | Tool | Version from | Check |
50
+ | --- | --- | --- |
51
+ | {Node} | [`.nvmrc`](../../.nvmrc) | `node -v` |
52
+ | {pnpm} | `packageManager` in [`package.json`](../../package.json), via `corepack enable` | `pnpm -v` |
53
+ | {Docker / Rust / wrangler / …} | {pinning file, or "any current"} | `{command}` |
54
+
55
+ - **Access:** {repo, secrets store, cloud account, registry token, and who grants each}.
56
+
57
+ ## Before cloning ← delete if none
58
+
59
+ - **{Trap}:** {what a fresh clone hits and the one command that clears it, e.g. `git lfs install`, `git submodule update --init`}.
60
+
61
+ ## Install
62
+
63
+ \`\`\`bash
64
+ git clone {url} && cd {repo}
65
+ corepack enable
66
+ {pm} install # expect: {what a clean install ends with}
67
+ \`\`\`
68
+
69
+ ## Environment files ← delete if none
70
+
71
+ | File | Copy from | Fill | Values come from | Required to boot |
72
+ | --- | --- | --- | --- | --- |
73
+ | `{path/.dev.vars}` | `{path/.dev.vars.example}` | {keys, or "every blank"} | {vault, the owner, a generated local value} | {yes / no} |
74
+
75
+ The contract is [`{example file or typed Env}`](../../{path}). Read it before concluding a value is missing. {Which of these files are gitignored.}
76
+
77
+ ## Local services ← delete if none
78
+
79
+ | Service | Start | Port | Ready when |
80
+ | --- | --- | --- | --- |
81
+ | {local DB / emulator} | `{command}` | {port} | `{probe}` returns {expected} |
82
+
83
+ ## First run
84
+
85
+ 1. Prepare local state.
86
+
87
+ \`\`\`bash
88
+ {pm} --filter {unit} {migrate-and-seed} # expect: {output}
89
+ \`\`\`
90
+
91
+ 2. Start the {backend}.
92
+
93
+ \`\`\`bash
94
+ {pm} --filter {unit} {dev:server} # expect: listening on :{port}
95
+ \`\`\`
96
+
97
+ 3. Start the {frontend / CLI}.
98
+
99
+ \`\`\`bash
100
+ {pm} --filter {unit} {dev} # expect: {URL}
101
+ \`\`\`
102
+
103
+ 4. Open `{http://localhost:port}` and {sign in as `{seeded user}` / reach `{first screen}`}.
104
+
105
+ ## Verify
106
+
107
+ - `{curl -fsS http://localhost:{port}/{health}}` returns `200` {and `{body}`}.
108
+ - `{doctor or status command}` reports {expected}. ← keep whichever exists
109
+ - `{pm} {test}` passes from this cold shell ({expected tail}).
110
+
111
+ ## Reset ← delete if none
112
+
113
+ | Command | Deletes | Prompts? |
114
+ | --- | --- | --- |
115
+ | `{pm} {reset-script}` | {local state at `{path}`} | {yes; `{FORCE=1}` skips / no} |
116
+
117
+ ## Common failures
118
+
119
+ - **`{exact error text}`.** {Cause.} Fix: `{command or file edit}`.
120
+
121
+ ## Next
122
+
123
+ The daily loop and its per-package traps: [`local-development.md`]({local-development}.md). Deploying: [`deployment.md`](deployment.md). Standing rules: [`CLAUDE.md`](../../CLAUDE.md).
124
+ ```
125
+
126
+ ### Baseline scaffolding behavior
127
+
128
+ The baseline scaffolds `docs/operations/setup.md` when it is missing and the repo has a lockfile and at least one runnable root script. It fills each section from the repo:
129
+
130
+ - **Stack:** from the workspace manifests, one row per layer.
131
+ - **Prerequisites:** from the pinning files.
132
+ - **Install and First run:** from the root README's getting-started block (if one exists) and the root scripts.
133
+ - **Environment files:** from every `*.example` / `.dev.vars.example` in the workspace.
134
+ - **Verify:** from a health route, a doctor command or the test script.
135
+
136
+ It leaves Common failures empty until a failure is root-caused, and it drops every section it cannot fill concretely.
137
+
138
+ **It never overwrites an existing `setup.md`.** If the repo already has a first-run procedure under another name, the baseline proposes the rename with a `note:` row and does not create a second file.
@@ -1,143 +1,81 @@
1
1
  # System Documentation (docs/architecture/systems/{system}.md)
2
2
 
3
- Truth document. Use for: **one machine that spans packages** — exactly how it works, end to end, in one place. One file per machine, named for the machine (`docs/architecture/systems/update-engine.md`). It states the machine's model and its whole path: what enters it, every stage it passes through, what it writes, what re-drives it when it stalls, and what a reader sees at the far end.
3
+ Truth document. Use for: **one machine that spans packages**, which a person cannot point at — the walk, the egress, the ingest, the settlement, a gate, a sweep, a door an agent calls. One file per machine, named for the machine. A thing a person navigates to is a feature document, even when it owns tables; a unit of distribution is a package document.
4
4
 
5
- **A system document's globs win by specificity.** Its `owns:` names the subtrees and exact files the machine is made of — `packages/studio/src/server/execution/**`, `packages/ui/src/shared/harnessVocabulary.ts` — and those are narrower than the package document's `packages/studio/**`, so the system takes them and the package keeps the residue. That is the whole mechanism: **the package document is the residual owner and the system document is the specific one**, and nothing needs to be subtracted by hand. A machine confined to one package still gets a system document if the machine is the thing worth stating; it is the *narrower glob* that makes it a system, not the package count.
5
+ **A document is read by people, and its footer is for the agent** (`references/style-guide.md` § Owning documents — the body and the footer). A system document explains a machine to a person: what it is for, why it is split where it is split, how it behaves from the outside, what it guarantees at the far end, what re-drives it when it stalls. Its stages, tables, routes, frames, bindings and files are the code graph's (`docs/architecture/systems/knowledge-layer.md`), not a hand-typed tour. The body names code only at a cross-cutting seam another machine or feature would not find from its own files.
6
6
 
7
- **Two rules bind the globs.** Neither genre may claim a path another document claims at **equal specificity** — equal-specificity overlap is an ownership conflict to resolve before either document ships. And every glob **matches at least one file on disk** at `status: active`; projected globs are permitted only at `draft` and are confirmed when the document flips. Because a system's `owns:` list is long and hand-assembled, re-glob it whenever the machine's code moves — a stale entry here silently un-owns real code back to the package document, which does not describe it.
7
+ **A system document's deepest layer is the machine's behaviour across packages** (`references/style-guide.md` § Shape — the model first, the detail after): the order it runs in, the sequence and state diagrams at role level, the invariant that holds at each place where parts meet, and what re-drives a stall. That layer is earned because no single file shows a cross-package flow. It stops before per-function steps, tables, columns and routes.
8
8
 
9
- **How this differs from its neighbours — and the mistake this template exists to prevent.** A **feature** document covers one capability or one page a person names and owns that surface's globs. A **package** document covers one unit of distribution and owns what is left of its tree. A **system** document covers a *machine*: something with an entry, stages, state and an outcome, which a person does not open and cannot point at. **The failure mode is a system document written as a giant feature document** — a tour of screens and what each button does, at ten times a feature doc's length. The test is mechanical: if the subject can be named by an address a person navigates to, it is a feature; if it can be named only as a verb over the product's own nouns — the walk, the egress, the ingest, the settlement — it is a system. A system document says what a surface *renders from* and links to the feature document for what the surface looks like; it never describes the surface.
9
+ **A system document's globs win by specificity.** Its `owns:` names the subtrees and exact files the machine is made of, narrower than the package glob. Two documents never claim a path at equal specificity; every glob matches a file on disk at `status: active`.
10
10
 
11
- **Required vs optional.** Required in every system document: the **frontmatter**, the **opening statement** (what the machine is, then what this document states end to end), the **boundary paragraph** (what this document does not restate, and which document holds each part), the **machine diagram**, at least one **stage section**, **Files**, and **Related**. Everything else is optional. Do not add a section because it seems owed — a stage the machine does not have is a section that will be filled with something untrue.
11
+ **Sharp, bulleted, labelled with noun phrases** (`references/style-guide.md` § Labels). The opening paragraph defines the machine; everything after it is bullets under noun-phrase headings, each bullet a bold noun-phrase label followed by one or two sentences.
12
12
 
13
- System documents are long by nature, because the point is that the whole machine is in one place — roughly 300 to 1000 lines. Length is earned by stages, never by restating a neighbour: every paragraph that could have been a link to the document that owns it is the genre's characteristic waste.
13
+ **Sections:** the frontmatter and the opening paragraph (the machine defined in its first sentence, what enters, what it leaves behind) are required. Then:
14
+
15
+ | Section | When |
16
+ | --- | --- |
17
+ | `Scope` | required. What this document does not decide, and which document does — subjects with owners, never bare links |
18
+ | `Flow` | required |
19
+ | `Decisions` | once any choice was made that the code cannot explain, including why this is one machine and not two |
20
+ | `Promises` | required |
21
+ | `Gaps` | only when there is one |
22
+ | `For the agent` | required |
23
+
24
+ Nothing else. The lint rules of the feature template apply. Sixty to a hundred and sixty lines.
14
25
 
15
26
  ```yaml
16
27
  ---
17
- owns: # required — the machine's subtrees and exact files; narrower than the package glob
28
+ type: system # required tooling key
29
+ status: active # required — draft = the machine as a whole does not run
30
+ objects: [run, run ledger, settlement] # required — the objects this machine owns or moves
31
+ owns: # required until the graph computes ownership — narrower than the package glob
18
32
  - packages/{pkg}/src/{machine}/**
19
- - packages/{pkg}/src/routes/{machine}.ts
20
- - packages/{other}/src/shared/{machine}Vocabulary.ts
21
- keywords: [machine name, its nouns, its verbs] # required — discovery terms: the machine's own vocabulary, the table and route names
22
- status: active # required — active | draft | deprecated
23
- applies: # optional — the decisions and doctrine this machine is BOUND by (obligation, not a bibliography)
33
+ applies: # optional — decisions and doctrine this machine is BOUND by
24
34
  - docs/architecture/decisions/AD-0NN-{slug}.md
25
- - docs/architecture/common/{doctrine}.md
26
- type: system # required tooling key — genre stamp; preserve on edits, never narrate
27
35
  ---
28
36
  ```
29
37
 
30
- > A system document carries no `module:` — a machine that spans packages belongs to no single
31
- > bounded context, and labelling it with one asserts a boundary it crosses by definition.
32
- > `last-reviewed:` is optional tooling metadata: preserve it, never narrate it.
33
-
34
38
  ```
35
39
  # {The machine}
36
40
 
37
- {One paragraph that defines the machine in its own first sentence — bold the term being defined —
38
- then says what this document states, in the order the body states it. The enumeration is the
39
- contract: a reader who wants one stage finds it by reading this sentence. Where the machine's
40
- purpose is easier stated as an outcome, lead with `**Goal:**` and one sentence instead.}
41
-
42
- {One paragraph: the boundary. What this document does **not** restate, and which document holds
43
- each part — the neighbouring systems, the package documents whose residue this sits inside, the
44
- feature documents that render from it, the common-plane doctrine it obeys, the decision records
45
- behind its shape. Name each with a link and the subject it holds. This paragraph is what keeps the
46
- document from growing into its neighbours.}
47
-
48
- ```text
49
- {The machine diagram. One fenced block, drawn as the thing flows — entry at the top or left,
50
- each stage a box or a labelled arrow, the durable writes named, the re-drive path shown returning.
51
- Label the arrows with what crosses them, not with verbs. This is the picture a reader holds while
52
- reading the rest, so it carries the machine's real names — routes, tables, classes, files — and
53
- not generic boxes.}
54
- ```
55
-
56
- {Optional, and worth its line whenever the body names paths: "Every path below is relative to
57
- `packages/{pkg}/src/{dir}/` unless it names another package."}
41
+ {The machine defined in its first sentence — bold the term — then what it takes in, what it leaves behind, and what a reader sees at the far end. Plain words.}
58
42
 
59
- {Optional: a reading order for a long document — "§ X is the data; § Y is the code that reads it;
60
- § Z is what re-drives it" — where the section list is not self-evidently a sequence.}
43
+ ## Scope
61
44
 
62
- ## The shape
45
+ - **Covers:** {what this machine decides}
46
+ - **Not here:** {subject} — {owning document}; {subject} — {owning document}
63
47
 
64
- {Optional. Where the machine has parts a reader must hold at once before any stage makes sense,
65
- name them in one table before the stages begin.}
48
+ ## Flow
66
49
 
67
- | Part | Where | What it holds |
68
- | --- | --- | --- |
69
- | {Entry} | `routes/{x}.ts` | {thin, tenancy first} |
70
- | {Ledger} | `{machine}/ledger.ts` | {the durable row} |
50
+ ### {Stage as a noun phrase — e.g. "Intake", "Settlement", "Re-drive"}
71
51
 
72
- ## {Stage sections — one per stage, in the order the machine runs them}
52
+ - **{Noun-phrase label}:** {what starts it or what it does at this step, as a person would describe it; what it writes that outlives it; what it refuses.}
73
53
 
74
- {The body, and the only genre where the section order is decided for you: the machine's own order.
75
- Entry, then each stage, then what is written durably, then what re-drives a stalled one, then what
76
- reads the result. Name each section for its stage in the product's own vocabulary. Within a
77
- section, state the mechanism and its reason: what the code does, what it refuses, and why it
78
- refuses that rather than something else. Tables for rosters (routes, columns, frames, states,
79
- bindings); prose for a rule and the defect it prevents. Never paste an implementation — a
80
- signature, a state list, a wire shape, a table's columns.}
54
+ {A role-level sequence or state diagram where the stages cross packages.}
81
55
 
82
- ## Tests
56
+ ## Decisions
83
57
 
84
- {Optional. What proves this machine, and what each suite pins — a `Suite | Pins` table. Include it
85
- where the machine has a suite of its own; omit the heading where the coverage lives in the package
86
- documents' suites.}
58
+ - **{The decision as a noun phrase}:** {why; the alternative only where a reader would reach for it.}
87
59
 
88
- ## Files
60
+ ## Promises
89
61
 
90
- | Path | Role |
91
- | --- | --- |
92
- | `packages/{pkg}/src/{machine}/{file}.ts` | {what it holds, by name — the exports a reader is looking for} |
62
+ - **{Noun-phrase label}:** {a checkable guarantee or refusal; what holds at the far end; what a stalled run gets.}
93
63
 
94
- {One row per file this document owns — the roster is the `owns:` list, made readable. Close with
95
- the inverse: "Read here, owned elsewhere:" naming the paths the body describes but another document
96
- claims, each with the document that claims it. That closing line is what stops a system document
97
- from quietly annexing the code it reads.}
64
+ ## Gaps
98
65
 
99
- ## Related
66
+ - **{Noun-phrase label}:** {what is missing and what it would take.}
100
67
 
101
- - [AD-0NN — {the ruling}](../decisions/AD-0NN-{slug}.md) — {the decision behind this shape, the options weighed}
102
- - [`{neighbour}.md`]({neighbour}.md) — {the machine on the other side of this seam}
103
- - [`{feature}.md`](../../features/{feature}.md) — {what a person sees of this machine}
104
- - [`{doctrine}.md`](../common/{doctrine}.md) — {the cross-cutting contract this machine answers to}
105
- ```
68
+ ## For the agent
106
69
 
107
- ### The boundary paragraph is the genre's load-bearing section
108
-
109
- Systems overlap: they share tables, call each other, and render into the same surfaces. Without a
110
- paragraph that names the seams, two system documents describe the same stage from two angles and
111
- drift apart on the first change — and a reader has no way to tell which is authoritative. So the
112
- boundary paragraph is not a courtesy list of related reading; it is the statement of what this
113
- document is *not*, written specifically enough that a later editor can tell where to put a fact.
114
- Write it as a list of subjects with their owners — "the coordinator's tables, alarm and drive claim
115
- are `harness.md`; a run's ledger row and settlement are `generation-runs.md`" — never as bare
116
- links.
117
-
118
- ### Marking what is decided and unbuilt
119
-
120
- Where the machine has a stage that is decided and not built — a predicate that selects but never
121
- acts, a column that is written and never read, a door with no caller — wrap the prose in a marker
122
- so the gap is machine-findable and its evidence travels with it:
70
+ - **Objects:** {…}
71
+ - **Code roots:** {…} — directories, one per package the machine spans
72
+ - **Seams:** {…} by name
73
+ - **Checklist:** `tests/{system}.md`
74
+ - **See also:** {neighbour}: {why}
123
75
 
76
+ No tables, routes or symbol rosters — those are the graph's.
124
77
  ```
125
- <!-- UNBUILT:START — {what is decided, where it is decided (an AD § or an owner ruling), and the
126
- source evidence that it is not built: the function with no caller, the route that is not mounted,
127
- the value written and never read} -->
128
- {the prose describing the unbuilt stage, and what runs in its place}
129
- <!-- UNBUILT:END -->
130
- ```
131
-
132
- **State what runs instead.** A machine with a hole in it still works somehow, and the workaround is
133
- the fact a reader needs. **A design decided *against* carries no marker** — a marker means the work
134
- is owed and absent, so using one for a rejected design turns the register of debt into a register
135
- of opinions.
136
78
 
137
- ### `status: draft` on a system
79
+ ### Marking what is decided and unbuilt
138
80
 
139
- A system document is `draft` when the **machine as a whole** does not run — the code is on disk and
140
- nothing reaches it. Say so in the first section, in plain words, with the evidence: which halves
141
- exist, which do not, and what a reader who invokes it actually observes. A scoped gap in a working
142
- machine is not a draft: the document stays `active` and takes an UNBUILT marker at the stage that
143
- has the hole.
81
+ Where a stage is decided and not built, wrap its bullets in `<!-- UNBUILT:START — {what, where decided, the evidence it is not built} -->` … `<!-- UNBUILT:END -->` and say under Promises what runs instead. A design decided *against* carries no marker.
@@ -3,20 +3,12 @@
3
3
  // harness's files land — a bundle says `skills/design/SKILL.md`, a project says
4
4
  // `.claude/skills/design/SKILL.md`, and this module is the only place that mapping exists.
5
5
  //
6
- // TWO SHIPPERS, ONE MAPPING. `bin/etna.js` calls this against the user's cwd; the NuStack push
7
- // (`.github/scripts/push-harnesses.mjs`) calls it against a throwaway directory and ships the
8
- // result, so an App's export from NuStack extracts as the same tree `npx @nurix/etna` writes.
9
- // They diverged once — the push sent the BUNDLE layout, so a downloaded project had its
10
- // instruction tree at the archive root, no AGENTS.md, and no wired hooks, while the manifest
11
- // claimed otherwise. One function is what stops that recurring.
12
- //
13
- // ZERO DEPENDENCIES, BY NECESSITY. The push runs in CI without an `npm install` (that workflow
14
- // reaches `npm publish` → `prepack` and nothing else), so this module and everything it imports
15
- // may use only what Node ships. That rules out importing `bin/etna.js`, which pulls in
16
- // @clack/prompts for its UI — hence the extraction rather than a re-export.
6
+ // ONE MAPPING, COMPUTED ONCE. `bin/etna.js` calls this against the user's cwd; the placement
7
+ // itself comes from `planHarnessFiles`, so the installed tree and the compiler's array cannot
8
+ // describe different trees — the suite runs both and compares.
17
9
  //
18
10
  // PURE FILE OPS, NO UI. Every human-facing string is RETURNED (installed/notices/warnings) and
19
- // printed by the caller, so the push can discard what the CLI renders.
11
+ // printed by the caller, which is what leaves presentation to the CLI alone.
20
12
 
21
13
  import {
22
14
  existsSync,
@@ -2,17 +2,10 @@
2
2
  // THE HARNESS COMPILER: one bundled harness definition in, the exact file list a fresh install
3
3
  // produces out. Pure — it reads the bundle and returns data, and writes nothing.
4
4
  //
5
- // This is the single authority on WHERE a harness's files land and WHAT is in them. Both shippers
6
- // consume it and neither re-derives it:
7
- //
8
- // push-harnesses.mjs → publishes the array to NuStack verbatim
9
- // materializeHarness → writes the array to a project, applying each entry's policy
10
- //
11
- // They diverged once, and that is the whole reason this file exists. The NuStack push used to walk
12
- // the BUNDLE directory and send those paths, so a project downloaded from NuStack Studio extracted
13
- // with its instruction tree at the archive root where no runtime looks for it, no AGENTS.md, and no
14
- // hooks wired into settings.json — while the export manifest claimed the folder was ready to open.
15
- // Nothing failed: every file was present, only its location was wrong.
5
+ // This is the single authority on WHERE a harness's files land and WHAT is in them.
6
+ // `materializeHarness` writes the array this returns, applying each entry's policy, and re-derives
7
+ // nothing — so a bundle path (`skills/design/SKILL.md`) becomes an installed path
8
+ // (`.claude/skills/design/SKILL.md`) in exactly one place.
16
9
  //
17
10
  // PURE, AND THAT IS THE POINT. Deriving the payload by installing into a temp directory and reading
18
11
  // it back works, but it is disk I/O to compute a mapping — and it hides the mapping inside a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nurix/etna",
3
- "version": "0.20.25",
3
+ "version": "0.20.27",
4
4
  "description": "Bootstrap a project with a Nurix harness — copies the harness's CLAUDE.md, skills, agents, rules, and hooks directly into the project from a bundled payload (no marketplace fetch, no network).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,6 +21,7 @@
21
21
  "scripts": {
22
22
  "test": "node --test 'tests/**/*.test.mjs' '../../harness/code/hooks/tests/*.test.mjs'",
23
23
  "build:data": "node scripts/build-data.js",
24
+ "harness:cdn": "node scripts/build-data.js && node scripts/upload-harness-cdn.mjs code",
24
25
  "prepack": "node scripts/build-data.js",
25
26
  "validate:codex-agents": "node lib/codex/validate-codex-agents.mjs"
26
27
  },
@@ -42,5 +43,5 @@
42
43
  "agent",
43
44
  "plugin"
44
45
  ],
45
- "etnaFingerprint": "c24bc6f1af10"
46
+ "etnaFingerprint": "aa072fd57bad"
46
47
  }
@@ -1,71 +0,0 @@
1
- # docs/structure.md (Authority Map)
2
-
3
- Truth document. Use for: defining which folder owns which topic and how docs are maintained.
4
-
5
- ```
6
- ---
7
- harness-version: 1.0.0
8
- ---
9
-
10
- # Documentation Structure
11
-
12
- > This file is the entry point for understanding the docs folder.
13
- > `harness-version` above is the repo's single baseline/version sentinel — the `maintenance` agent (baseline mode) owns it and stamps the installed harness version (semver) on every reconcile.
14
-
15
- ## Authority Map
16
-
17
- Each topic has one canonical location. Read from here, not from plans or changelogs.
18
-
19
- | Topic | Authority | Key Files |
20
- | ----- | --------- | --------- |
21
- | Code-path ownership (path → doc + module) | `owns:` frontmatter on features, packages and systems | the generated ownership index |
22
- | System overview | `docs/architecture/` | system-design.md |
23
- | One workspace package | `docs/architecture/packages/` | {package-folder}.md |
24
- | One machine spanning packages | `docs/architecture/systems/` | {machine}.md |
25
- | Steering (domain model, glossary, non-goals) | `docs/architecture/` | domain-model.md, glossary.md, non-goals.md |
26
- | Architecture decisions (ADs) | `docs/architecture/decisions/` | AD-NNN-*.md |
27
- | API surface | `docs/architecture/` | api.md |
28
- | Security | `docs/architecture/` | security.md |
29
- | Feature behavior | `docs/features/` | {key files} |
30
- | Setup & development | `docs/operations/` | {key files} |
31
- | Environment / config surface | `docs/operations/` | environment.md |
32
- | Testing strategy | `docs/tests/` | strategy.md |
33
- | Historical plans | `docs/history/plans/` | YYYY-MM-DD-name.md |
34
- | Change records | `docs/history/changelog/` | `YYYY-MM-DD-{three-words}.md` — one per unit of work, written at commit time |
35
- | Migration runbooks | `docs/history/migrations/` | YYYY-MM-DD-name.md |
36
- | Deep-research artifacts | `docs/history/research/{topic}/` | README.md + findings.md + sources.md |
37
- | Brainstorm design records | `docs/research/{topic}-brainstorm/` (active; legacy `-brainstorming/`) → `docs/history/brainstorms/{topic}/` (harvested; user deletes or commits) | thesis.md + forks.md + ledger.md + state.md |
38
- | Backlog | `docs/history/` | backlog.md |
39
-
40
- ## The Two Natures
41
-
42
- Every doc is a **truth document** (states current absolutes, topic-named, updated in place) or a **record** (dated account of activity, frozen or append-only). `architecture/`, `features/`, `operations/`, `tests/` hold truth; `history/`, `research/`, `memory/` hold records.
43
-
44
- - Truth documents are rewritten in place when reality changes — the change-story goes to a changelog entry, never into the truth doc's body.
45
- - Records freeze: plans at `Complete`/`Abandoned`, changelog entries and migration runbooks once written/executed. A scope change is a new dated record that links back.
46
- - Feature docs are the living reference for implemented features; an AD is the living truth for one decision subject, with its dated journey confined to its Decision Changelog tail.
47
-
48
- ## Folder Rules
49
-
50
- - `docs/features/`: Living reference for implemented features. Each feature doc **carries** the `owns:` / `module:` / `keywords:` / `status:` frontmatter — `owns:` declares the code-path globs it owns (the only ownership key), `module:` is an optional bounded-context label, `keywords:` are discovery terms, `status:` is `active`/`draft`/`deprecated`. The SessionStart hook unions every owning doc's `owns:` globs into the injected ownership index.
51
- - `docs/architecture/`: The truth layer for system-wide shape: overview, domain model, glossary, non-goals, API surface, security, and `decisions/` (ADs — one per subject, updated in place, journey in each AD's Decision Changelog). Update when cross-cutting reality changes. The cross-cutting doctrine directly under `architecture/` (and under `architecture/common/` where a repo separates it) **owns no code** — it describes patterns every surface obeys, and `applies:` is how a surface declares it is bound.
52
- - `docs/architecture/packages/`: One doc per workspace package (`{package-folder}.md`), present in a workspace repo. Each is the **residual owner** of its tree — `owns: ["packages/{name}/**"]` — describing the manifest, build, entry, layout and every behavior no system or feature doc claims at higher specificity. Template: the `documentation` skill's `templates/package.md`.
53
- - `docs/architecture/systems/`: One doc per machine that spans packages (`{machine}.md`) — the walk, the egress, the ingest. Its `owns:` names the machine's own subtrees and files, narrower than the package glob, so it wins those paths by specificity and the package doc keeps the rest. Not a surface doc: what a person sees stays in `docs/features/`. Template: the `documentation` skill's `templates/system.md`.
54
-
55
- **Three genres carry `owns:`** — features, packages, systems — and no others. Their globs layer by specificity (package `**` residual, system and feature narrower), and two docs may never claim a path at **equal** specificity: that is an ownership conflict to resolve, not a duplication to live with. Every glob matches at least one file on disk at `status: active`.
56
- - `docs/operations/`: How-to procedures for setup, development, and deployment, plus the environment registry. Update when workflows change. One-shot migrations do NOT live here — they are records (`docs/history/migrations/`).
57
- - `docs/tests/`: Testing strategy and test docs. Present when the repo has a test posture worth documenting.
58
- - `docs/history/plans/`: Records. Must have `Status:` field. Never modify after completion.
59
- - `docs/history/changelog/`: Records. One entry per unit of work (`YYYY-MM-DD-{three-words}.md`), written by whoever does the work and frozen inside the commit it describes. Entries carry the refinement context a diff cannot show — the ask in the user's words, iterations and rejections, skill survived/overridden verdicts, discoveries, pins. Format is the `documentation` skill's `templates/changelog-entry.md`; trigger and lifecycle are the `changelog` rule; distillation is the `retro` agent. Immutability begins at commit — a draft in the working tree is mutable until then, never after. Every entry appends a row to `docs/history/CHANGELOG.md`.
60
- - `docs/history/migrations/`: Records. One-shot migration/upgrade runbooks — authored before execution, outcome-stamped and frozen after.
61
- - `docs/history/research/{topic}/`: Deep-research artifacts — the dumped output of a research pass, one folder per topic (conventionally `README.md` synthesis + `findings.md` verified claims & citations + `sources.md`). A point-in-time, cited record — **not** a living authority doc: it owns no code (no `owns:` frontmatter) and is never edited to "stay current." A spec/plan links to it for grounding; a new question gets a new topic folder.
62
- - `docs/research/{topic}-brainstorm/` → `docs/history/brainstorms/{topic}/`: Brainstorm design records — the Brainstorming-Mode session for a topic (working surface `thesis.md` + `forks.md` + `ledger.md` + `state.md` + `basis/` + `fragments/`, plus an untracked `ops/` capture layer deleted at stop), written by the `brainstorm` skill and its twin agent. An active session lives under `docs/research/` (legacy folders carry the older `-brainstorming/` suffix); on a **passed harvest** it **moves** to `docs/history/brainstorms/` — the completion marker — and the **user decides whether the moved folder is deleted or committed** as provenance. Each of the two folders carries a `Readme.md` index (the skill reads it at start instead of scanning). Author-created (never scaffolded empty), one folder per design conversation. Owns no code (no `owns:` frontmatter); the harvest routes its conclusions into `architecture/`/`features/`/`history/`. (Distinct from `docs/history/research/{topic}/` above — that is a frozen deep-research record, not a brainstorm session.)
63
- - `docs/history/backlog.md`: Tracked work items. Append new items under appropriate priority.
64
-
65
- ## Health Log
66
-
67
- <!-- Updated by maintenance agent — the sanctioned dated tail in this truth doc (SKILL.md § The Two Natures names the two bridges) -->
68
- | Date | Review Summary |
69
- | ---- | -------------- |
70
- | {today} | Initial baseline — v{harness-version} structure established |
71
- ```
@@ -1,71 +0,0 @@
1
- # docs/structure.md (Authority Map)
2
-
3
- Truth document. Use for: defining which folder owns which topic and how docs are maintained.
4
-
5
- ```
6
- ---
7
- harness-version: 1.0.0
8
- ---
9
-
10
- # Documentation Structure
11
-
12
- > This file is the entry point for understanding the docs folder.
13
- > `harness-version` above is the repo's single baseline/version sentinel — the `maintenance` agent (baseline mode) owns it and stamps the installed harness version (semver) on every reconcile.
14
-
15
- ## Authority Map
16
-
17
- Each topic has one canonical location. Read from here, not from plans or changelogs.
18
-
19
- | Topic | Authority | Key Files |
20
- | ----- | --------- | --------- |
21
- | Code-path ownership (path → doc + module) | `owns:` frontmatter on features, packages and systems | the generated ownership index |
22
- | System overview | `docs/architecture/` | system-design.md |
23
- | One workspace package | `docs/architecture/packages/` | {package-folder}.md |
24
- | One machine spanning packages | `docs/architecture/systems/` | {machine}.md |
25
- | Steering (domain model, glossary, non-goals) | `docs/architecture/` | domain-model.md, glossary.md, non-goals.md |
26
- | Architecture decisions (ADs) | `docs/architecture/decisions/` | AD-NNN-*.md |
27
- | API surface | `docs/architecture/` | api.md |
28
- | Security | `docs/architecture/` | security.md |
29
- | Feature behavior | `docs/features/` | {key files} |
30
- | Setup & development | `docs/operations/` | {key files} |
31
- | Environment / config surface | `docs/operations/` | environment.md |
32
- | Testing strategy | `docs/tests/` | strategy.md |
33
- | Historical plans | `docs/history/plans/` | YYYY-MM-DD-name.md |
34
- | Change records | `docs/history/changelog/` | `YYYY-MM-DD-{three-words}.md` — one per unit of work, written at commit time |
35
- | Migration runbooks | `docs/history/migrations/` | YYYY-MM-DD-name.md |
36
- | Deep-research artifacts | `docs/history/research/{topic}/` | README.md + findings.md + sources.md |
37
- | Brainstorm design records | `docs/research/{topic}-brainstorm/` (active; legacy `-brainstorming/`) → `docs/history/brainstorms/{topic}/` (harvested; user deletes or commits) | thesis.md + forks.md + ledger.md + state.md |
38
- | Backlog | `docs/history/` | backlog.md |
39
-
40
- ## The Two Natures
41
-
42
- Every doc is a **truth document** (states current absolutes, topic-named, updated in place) or a **record** (dated account of activity, frozen or append-only). `architecture/`, `features/`, `operations/`, `tests/` hold truth; `history/`, `research/`, `memory/` hold records.
43
-
44
- - Truth documents are rewritten in place when reality changes — the change-story goes to a changelog entry, never into the truth doc's body.
45
- - Records freeze: plans at `Complete`/`Abandoned`, changelog entries and migration runbooks once written/executed. A scope change is a new dated record that links back.
46
- - Feature docs are the living reference for implemented features; an AD is the living truth for one decision subject, with its dated journey confined to its Decision Changelog tail.
47
-
48
- ## Folder Rules
49
-
50
- - `docs/features/`: Living reference for implemented features. Each feature doc **carries** the `owns:` / `module:` / `keywords:` / `status:` frontmatter — `owns:` declares the code-path globs it owns (the only ownership key), `module:` is an optional bounded-context label, `keywords:` are discovery terms, `status:` is `active`/`draft`/`deprecated`. The SessionStart hook unions every owning doc's `owns:` globs into the injected ownership index.
51
- - `docs/architecture/`: The truth layer for system-wide shape: overview, domain model, glossary, non-goals, API surface, security, and `decisions/` (ADs — one per subject, updated in place, journey in each AD's Decision Changelog). Update when cross-cutting reality changes. The cross-cutting doctrine directly under `architecture/` (and under `architecture/common/` where a repo separates it) **owns no code** — it describes patterns every surface obeys, and `applies:` is how a surface declares it is bound.
52
- - `docs/architecture/packages/`: One doc per workspace package (`{package-folder}.md`), present in a workspace repo. Each is the **residual owner** of its tree — `owns: ["packages/{name}/**"]` — describing the manifest, build, entry, layout and every behavior no system or feature doc claims at higher specificity. Template: the `documentation` skill's `templates/package.md`.
53
- - `docs/architecture/systems/`: One doc per machine that spans packages (`{machine}.md`) — the walk, the egress, the ingest. Its `owns:` names the machine's own subtrees and files, narrower than the package glob, so it wins those paths by specificity and the package doc keeps the rest. Not a surface doc: what a person sees stays in `docs/features/`. Template: the `documentation` skill's `templates/system.md`.
54
-
55
- **Three genres carry `owns:`** — features, packages, systems — and no others. Their globs layer by specificity (package `**` residual, system and feature narrower), and two docs may never claim a path at **equal** specificity: that is an ownership conflict to resolve, not a duplication to live with. Every glob matches at least one file on disk at `status: active`.
56
- - `docs/operations/`: How-to procedures for setup, development, and deployment, plus the environment registry. Update when workflows change. One-shot migrations do NOT live here — they are records (`docs/history/migrations/`).
57
- - `docs/tests/`: Testing strategy and test docs. Present when the repo has a test posture worth documenting.
58
- - `docs/history/plans/`: Records. Must have `Status:` field. Never modify after completion.
59
- - `docs/history/changelog/`: Records. One entry per unit of work (`YYYY-MM-DD-{three-words}.md`), written by whoever does the work and frozen inside the commit it describes. Entries carry the refinement context a diff cannot show — the ask in the user's words, iterations and rejections, skill survived/overridden verdicts, discoveries, pins. Format is the `documentation` skill's `templates/changelog-entry.md`; trigger and lifecycle are the `changelog` rule; distillation is the `retro` agent. Immutability begins at commit — a draft in the working tree is mutable until then, never after. Every entry appends a row to `docs/history/CHANGELOG.md`.
60
- - `docs/history/migrations/`: Records. One-shot migration/upgrade runbooks — authored before execution, outcome-stamped and frozen after.
61
- - `docs/history/research/{topic}/`: Deep-research artifacts — the dumped output of a research pass, one folder per topic (conventionally `README.md` synthesis + `findings.md` verified claims & citations + `sources.md`). A point-in-time, cited record — **not** a living authority doc: it owns no code (no `owns:` frontmatter) and is never edited to "stay current." A spec/plan links to it for grounding; a new question gets a new topic folder.
62
- - `docs/research/{topic}-brainstorm/` → `docs/history/brainstorms/{topic}/`: Brainstorm design records — the Brainstorming-Mode session for a topic (working surface `thesis.md` + `forks.md` + `ledger.md` + `state.md` + `basis/` + `fragments/`, plus an untracked `ops/` capture layer deleted at stop), written by the `brainstorm` skill and its twin agent. An active session lives under `docs/research/` (legacy folders carry the older `-brainstorming/` suffix); on a **passed harvest** it **moves** to `docs/history/brainstorms/` — the completion marker — and the **user decides whether the moved folder is deleted or committed** as provenance. Each of the two folders carries a `Readme.md` index (the skill reads it at start instead of scanning). Author-created (never scaffolded empty), one folder per design conversation. Owns no code (no `owns:` frontmatter); the harvest routes its conclusions into `architecture/`/`features/`/`history/`. (Distinct from `docs/history/research/{topic}/` above — that is a frozen deep-research record, not a brainstorm session.)
63
- - `docs/history/backlog.md`: Tracked work items. Append new items under appropriate priority.
64
-
65
- ## Health Log
66
-
67
- <!-- Updated by maintenance agent — the sanctioned dated tail in this truth doc (SKILL.md § The Two Natures names the two bridges) -->
68
- | Date | Review Summary |
69
- | ---- | -------------- |
70
- | {today} | Initial baseline — v{harness-version} structure established |
71
- ```