@nurix/etna 0.18.10 → 0.18.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -13
- package/bin/etna.js +98 -2
- package/data/harness-index.json +9 -1
- package/data/harnesses/code/CLAUDE.md +9 -10
- package/data/harnesses/code/agents/brainstorm.md +3 -3
- package/data/harnesses/code/agents/change-review.md +4 -4
- package/data/harnesses/code/agents/maintenance.md +177 -59
- package/data/harnesses/code/agents/spec-mode.md +3 -3
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/hooks/generate-ownership-index.mjs +148 -0
- package/data/harnesses/code/hooks/hooks.json +12 -0
- package/data/harnesses/code/skills/boundary/references/boundary-taxonomy.md +3 -3
- package/data/harnesses/code/skills/brainstorm/README.md +11 -9
- package/data/harnesses/code/skills/brainstorm/SKILL.md +2 -2
- package/data/harnesses/code/skills/brainstorm/harvest.md +5 -6
- package/data/harnesses/code/skills/distiller/SKILL.md +3 -3
- package/data/harnesses/code/skills/distiller/references/docs-mode.md +7 -7
- package/data/harnesses/code/skills/documentation/SKILL.md +23 -23
- package/data/harnesses/code/skills/documentation/references/templates.md +26 -64
- package/data/harnesses/etna/.prettierignore +12 -0
- package/data/harnesses/etna/.prettierrc.json +3 -0
- package/data/harnesses/etna/.vscode/settings.json +10 -0
- package/data/harnesses/etna/CLAUDE.md +151 -0
- package/data/harnesses/etna/agents/brainstorm.md +35 -0
- package/data/harnesses/etna/agents/change-review.md +251 -0
- package/data/harnesses/etna/agents/maintenance.md +240 -0
- package/data/harnesses/etna/agents/performance-review.md +223 -0
- package/data/harnesses/etna/agents/spec-mode.md +56 -0
- package/data/harnesses/etna/harness.json +11 -0
- package/data/harnesses/etna/hooks/generate-ownership-index.mjs +148 -0
- package/data/harnesses/etna/hooks/hooks.json +39 -0
- package/data/harnesses/etna/hooks/lib/redact.mjs +35 -0
- package/data/harnesses/etna/hooks/prompt-recall.mjs +155 -0
- package/data/harnesses/etna/hooks/session-reflect.mjs +285 -0
- package/data/harnesses/etna/rules/general.md +86 -0
- package/data/harnesses/etna/rules/kb.md +13 -0
- package/data/harnesses/etna/rules/nomenclature.md +41 -0
- package/data/harnesses/etna/rules/npm-cli.md +88 -0
- package/data/harnesses/etna/skills/boundary/SKILL.md +49 -0
- package/data/harnesses/etna/skills/boundary/references/boundary-taxonomy.md +796 -0
- package/data/harnesses/etna/skills/brainstorm/README.md +138 -0
- package/data/harnesses/etna/skills/brainstorm/SKILL.md +135 -0
- package/data/harnesses/etna/skills/brainstorm/harvest.md +25 -0
- package/data/harnesses/etna/skills/brainstorm/templates/backlog.md +39 -0
- package/data/harnesses/etna/skills/brainstorm/templates/build.md +37 -0
- package/data/harnesses/etna/skills/brainstorm/templates/decisions.md +29 -0
- package/data/harnesses/etna/skills/brainstorm/templates/doctrine.md +31 -0
- package/data/harnesses/etna/skills/brainstorm/templates/domain-model.md +25 -0
- package/data/harnesses/etna/skills/brainstorm/templates/glossary.md +20 -0
- package/data/harnesses/etna/skills/brainstorm/templates/milestones.md +43 -0
- package/data/harnesses/etna/skills/brainstorm/templates/non-goals.md +17 -0
- package/data/harnesses/etna/skills/brainstorm/templates/plan-doc.md +61 -0
- package/data/harnesses/etna/skills/brainstorm/templates/questions.md +36 -0
- package/data/harnesses/etna/skills/brainstorm/templates/references.md +28 -0
- package/data/harnesses/etna/skills/brainstorm/templates/rejected.md +29 -0
- package/data/harnesses/etna/skills/brainstorm/templates/state.md +1 -0
- package/data/harnesses/etna/skills/brainstorm/templates/tech.md +23 -0
- package/data/harnesses/etna/skills/brainstorm/templates/thesis.md +21 -0
- package/data/harnesses/etna/skills/distiller/SKILL.md +90 -0
- package/data/harnesses/etna/skills/distiller/references/docs-mode.md +299 -0
- package/data/harnesses/etna/skills/distiller/references/method.md +94 -0
- package/data/harnesses/etna/skills/documentation/SKILL.md +124 -0
- package/data/harnesses/etna/skills/documentation/references/examples.md +162 -0
- package/data/harnesses/etna/skills/documentation/references/style-guide.md +308 -0
- package/data/harnesses/etna/skills/documentation/references/templates.md +853 -0
- package/data/harnesses/etna/skills/workflow-mapper/SKILL.md +451 -0
- package/data/harnesses/etna/skills/workflow-mapper/references/patterns.md +214 -0
- package/data/harnesses/hr/harness.json +1 -1
- package/data/harnesses/hr/skills/evaluator/criteria/testing.md +4 -4
- package/data/harnesses/mobile/.prettierignore +12 -0
- package/data/harnesses/mobile/.prettierrc.json +3 -0
- package/data/harnesses/mobile/.vscode/settings.json +10 -0
- package/data/harnesses/mobile/CLAUDE.md +128 -0
- package/data/harnesses/mobile/agents/brainstorm.md +35 -0
- package/data/harnesses/mobile/agents/change-review.md +251 -0
- package/data/harnesses/mobile/agents/maintenance.md +240 -0
- package/data/harnesses/mobile/agents/performance-review.md +223 -0
- package/data/harnesses/mobile/agents/spec-mode.md +56 -0
- package/data/harnesses/mobile/harness.json +11 -0
- package/data/harnesses/mobile/hooks/generate-ownership-index.mjs +148 -0
- package/data/harnesses/mobile/hooks/hooks.json +39 -0
- package/data/harnesses/mobile/hooks/lib/redact.mjs +35 -0
- package/data/harnesses/mobile/hooks/prompt-recall.mjs +155 -0
- package/data/harnesses/mobile/hooks/session-reflect.mjs +285 -0
- package/data/harnesses/mobile/rules/general.md +86 -0
- package/data/harnesses/mobile/rules/nomenclature.md +41 -0
- package/data/harnesses/mobile/rules/react-native.md +132 -0
- package/data/harnesses/mobile/rules/typescript.md +40 -0
- package/data/harnesses/mobile/skills/boundary/SKILL.md +49 -0
- package/data/harnesses/mobile/skills/boundary/references/boundary-taxonomy.md +796 -0
- package/data/harnesses/mobile/skills/brainstorm/README.md +138 -0
- package/data/harnesses/mobile/skills/brainstorm/SKILL.md +135 -0
- package/data/harnesses/mobile/skills/brainstorm/harvest.md +25 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/backlog.md +39 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/build.md +37 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/decisions.md +29 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/doctrine.md +31 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/domain-model.md +25 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/glossary.md +20 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/milestones.md +43 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/non-goals.md +17 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/plan-doc.md +61 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/questions.md +36 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/references.md +28 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/rejected.md +29 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/state.md +1 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/tech.md +23 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/thesis.md +21 -0
- package/data/harnesses/mobile/skills/distiller/SKILL.md +90 -0
- package/data/harnesses/mobile/skills/distiller/references/docs-mode.md +299 -0
- package/data/harnesses/mobile/skills/distiller/references/method.md +94 -0
- package/data/harnesses/mobile/skills/documentation/SKILL.md +124 -0
- package/data/harnesses/mobile/skills/documentation/references/examples.md +162 -0
- package/data/harnesses/mobile/skills/documentation/references/style-guide.md +308 -0
- package/data/harnesses/mobile/skills/documentation/references/templates.md +853 -0
- package/data/harnesses/mobile/skills/workflow-mapper/SKILL.md +451 -0
- package/data/harnesses/mobile/skills/workflow-mapper/references/patterns.md +214 -0
- package/package.json +1 -1
- package/data/harnesses/code/agents/harness-manager.md +0 -184
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Distillation Method — the algorithm spec
|
|
2
|
+
|
|
3
|
+
The shared knowledge root for the `distiller` skill. Every mode reads this file. It carries the four mechanisms the distiller runs, the fact-card format, and the inbox-consumption protocol.
|
|
4
|
+
|
|
5
|
+
**These methods are stolen, not invented.** Each is sourced to its primary paper with an arXiv id — provenance matters here of all places. Embed them faithfully; do not paraphrase the retention signal away.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The four methods
|
|
10
|
+
|
|
11
|
+
### 1. Surprisal filter — _what to keep_ (Nemori, arXiv:2508.03341)
|
|
12
|
+
|
|
13
|
+
Present the LLM with **(a)** a summary of the _current_ fact-set, and **(b)** the new undigested inbox entries. Keep only what is **surprising** relative to (a) — what the existing knowledge would **not** have predicted. Predictable ⇒ dropped.
|
|
14
|
+
|
|
15
|
+
No importance scores. No emotional tags. No templates. **Prediction error is the only retention signal.**
|
|
16
|
+
|
|
17
|
+
> **First run, empty fact-set.** With nothing to predict against, "predictable" = mechanical routine. Keep decisions, reversals, discovered constraints, and failures with a cause worth remembering. Drop the rote. (Inbox entries arrive semi-distilled — the `session-reflect` hook already dropped routine work — so most survive this filter; what it still catches is repetition of what the fact-set already knows.)
|
|
18
|
+
|
|
19
|
+
**Surprisal sources are not only inbox entries.** The inbox is the _default_ stream, but the retention signal is prediction error wherever it lives. On a project whose inbox is thin or empty, the decision record carries the surprise instead: `docs/architecture/adr/**` (each accepted ADR is, by construction, a decision the prior knowledge would not have predicted) and `docs/memory/brainstorm.md` (reversals, owner pronouncements, discovered constraints). Treat these as input (b) alongside any inbox entries; the filter (keep the surprising, drop the predictable) is unchanged. Provenance then points at the ADR file or brainstorm section rather than a session id.
|
|
20
|
+
|
|
21
|
+
(Independently corroborated by Honcho's "Dream" — same prediction-error retention, arrived at separately.)
|
|
22
|
+
|
|
23
|
+
### 2. Fact-card representation — _non-lossy EDUs_ (EMem, arXiv:2511.17208)
|
|
24
|
+
|
|
25
|
+
Each survivor becomes **ONE atomic, self-contained statement** — an Elementary Discourse Unit (EDU). Entity names normalized; the minimal context needed to stand alone baked into the sentence itself. Each card carries **provenance**: the session ids and/or commits it derives from.
|
|
26
|
+
|
|
27
|
+
This is **decomposition, not summarization.** No information is destroyed; one survivor may decompose into several cards; everything stays auditable back to the session and commits that produced it.
|
|
28
|
+
|
|
29
|
+
### 3. Reconciliation — _consistency_ (Mem0, arXiv:2504.19413)
|
|
30
|
+
|
|
31
|
+
For each candidate card, retrieve the existing facts' **semantic neighbors**, then decide one of:
|
|
32
|
+
|
|
33
|
+
- **ADD** — genuinely new fact; write a new card.
|
|
34
|
+
- **UPDATE** — refines/extends a known fact; edit the existing card in place, extend its provenance.
|
|
35
|
+
- **SUPERSEDE** — contradicts/replaces a known fact; invalidate the old, write the new (see §4).
|
|
36
|
+
- **NOOP** — already known; write nothing.
|
|
37
|
+
|
|
38
|
+
Neighbor retrieval: `qmd query --format json -c {repo}-facts "<statement>"` (scope with `-c`, one collection) — **only when the `{repo}-facts` collection exists** (`qmd collection list` shows it). The gate is the collection, not the binary: a present qmd whose facts collection has never been built (first run) returns nothing useful. **Fallback when the collection is missing** — qmd absent, _or_ present but `{repo}-facts` not yet built: filename / grep similarity over `docs/memory/facts/*.md` (slug overlap + entity-name grep), and note in the report that reconciliation ran without semantic retrieval.
|
|
39
|
+
|
|
40
|
+
### 4. Bi-temporal supersession — _never delete_ (Zep/Graphiti, arXiv:2501.13956)
|
|
41
|
+
|
|
42
|
+
Superseding **never deletes.** On the **old** card, set `invalid_from:` (the date it stopped being true) and `superseded_by:` (the new fact's id), and **leave the file in place.** Write the **new** card with today's `valid_from:`. The old fact stays queryable as history; nothing vanishes.
|
|
43
|
+
|
|
44
|
+
This is the _valid-time_ axis of a bi-temporal model — a fact is true within `[valid_from, invalid_from)`; transaction time is the git history of the file.
|
|
45
|
+
|
|
46
|
+
#### Self-contained reversal — _both cards in one pass_
|
|
47
|
+
|
|
48
|
+
`SUPERSEDE` (§3) assumes the old fact already lives as a card. But a single input can state a reversal whole — "X was decided, then reversed to Y" in one sentence (e.g. brainstorm.md: _single-tenant → multi-tenant, same session_; or an ADR whose **Options Considered** (the `documentation` §10 ADR template's rejected-alternatives section) names a path "proposed and reversed within the brainstorm"). Here there is no pre-existing X card to invalidate — both X and Y arrive together.
|
|
49
|
+
|
|
50
|
+
Emit **two cards in one pass**:
|
|
51
|
+
|
|
52
|
+
1. A **born-invalid historical card for X** — the superseded decision. Write it with `valid_from:` (when X was decided, if known, else the input date), `invalid_from:` (when it was reversed — the same date, for an in-session reversal), and `superseded_by:` pointing at Y's fact-id. It is created already carrying its own death so the reversal stays auditable.
|
|
53
|
+
2. A **live card for Y** — the decision that won. `valid_from:` the reversal date, `invalid_from: null`, `superseded_by: null`.
|
|
54
|
+
|
|
55
|
+
Both share the input's provenance (the one ADR / brainstorm line). This is the ADD-side mirror of SUPERSEDE: SUPERSEDE invalidates a card that already exists; the self-contained reversal _manufactures_ the invalidated card so the abandoned-X history is recorded rather than silently dropped.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Fact-card format (`docs/memory/facts/{kebab-slug}.md`)
|
|
60
|
+
|
|
61
|
+
```markdown
|
|
62
|
+
---
|
|
63
|
+
id: fact-{slug}
|
|
64
|
+
valid_from: YYYY-MM-DD
|
|
65
|
+
invalid_from: null # set on supersession — never delete the file
|
|
66
|
+
superseded_by: null # fact-id
|
|
67
|
+
entities: [qmd, anchors, maintenance]
|
|
68
|
+
provenance: [session 28b2cd5e, commit abc123]
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
One atomic, self-contained statement of the fact, entities normalized.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- `id` — `fact-{slug}`, the slug matching the filename.
|
|
75
|
+
- `valid_from` — the date the fact became true (the entry/commit date, or the distill date if no better signal).
|
|
76
|
+
- `invalid_from` — `null` until superseded; then the date it stopped being true. **Never delete the file** to express invalidity — set this field.
|
|
77
|
+
- `superseded_by` — `null`, or the `fact-id` of the card that replaced it.
|
|
78
|
+
- `entities` — normalized names the fact concerns (used by the grep fallback and by retrieval).
|
|
79
|
+
- `provenance` — the session ids (`session <id>`, as stamped on the inbox entry) and commits this card decomposes from. Inbox entries are consumed after digestion, so the session id + commit hashes ARE the audit trail — commits resolve in git; session ids resolve to transcripts while retained. ADR / brainstorm inputs cite their file or section instead.
|
|
80
|
+
- The body — exactly one atomic, self-contained statement. Entities normalized, context baked in, so the card stands alone.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Inbox-consumption protocol (`docs/memory/inbox/`)
|
|
85
|
+
|
|
86
|
+
Consumption is what makes the distiller idempotent. The inbox (`docs/memory/inbox/{actor}.md`, one file per actor) is a queue: every entry block present is undigested, by definition. There is no separate high-water mark and no `.digest-state.md`.
|
|
87
|
+
|
|
88
|
+
**Protocol:**
|
|
89
|
+
|
|
90
|
+
1. **Collect first.** Read every entry block across `docs/memory/inbox/*.md`. Empty inbox ⇒ fall through to the ADR/brainstorm surprisal sources (§1).
|
|
91
|
+
2. Digest the collected entries (filter → decompose → reconcile → write).
|
|
92
|
+
3. **Consume last** — only after every card is written, delete exactly the entry blocks this run digested (keep each file's header; never touch blocks that arrived mid-run). Last, so a crash mid-run leaves entries queued and the re-run re-digests them — reconciliation NOOPs the already-written cards — rather than silently dropping them.
|
|
93
|
+
|
|
94
|
+
A second run immediately after a successful one finds an empty inbox and is a clean NOOP. ADR/brainstorm inputs are never consumed — reconciliation alone keeps re-runs over them idempotent.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: documentation
|
|
3
|
+
description: Template & generator library for technical docs — the skill agents call to produce a doc from a template. Use to (1) document a feature or module, (2) create or update a changelog entry, (3) document data flows or Redux state, (4) add to protected files, (5) record an architecture decision (ADR), (6) create or update the project root README, (7) create or update a plan, (8) derive a feature doc's `owns:` frontmatter (the code-path globs it owns) from code, (9) scaffold a standard doc (README, structure.md, CHANGELOG, backlog, memory) from its template, or (10) co-author any technical doc. Baselining / reconciling a repo's docs to the installed harness version is the **`maintenance` agent (baseline mode)** (which calls this skill for each template) — this skill does not orchestrate baseline. Triggers on "document this", "create docs", "update changelog", "add to protected files", "ADR", "architecture decision", "root README", "plan", "feature doc".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Technical Documentation Skill
|
|
7
|
+
|
|
8
|
+
**This skill is a template & generator library, not an orchestrator.** It supplies the templates, the frontmatter-derivation generator, and the co-authoring workflow that _agents_ call to produce individual docs. It does **not** baseline, audit, or reconcile a repo's doc tree — that is the **`maintenance` agent (baseline mode)**, which calls this skill for each template it scaffolds. Reach here to generate _one_ doc from a template; reach for the `maintenance` agent (baseline mode) to bring a whole repo into shape.
|
|
9
|
+
|
|
10
|
+
Document contracts and architecture, not implementation details. Show function signatures and API shapes — never paste full implementations (they rot fast). Use ASCII diagrams over prose for flows. Only document state at persistence boundaries (Redux persistence, DB schemas, API shapes), not component-level or transient state. Mark deprecated fields with `// UNUSED:` comments. Breaking changes belong in changelogs only, not module docs.
|
|
11
|
+
|
|
12
|
+
**No redirect docs.** When moving a doc to a new location, delete the old file entirely. Update all references (cross-doc links, memory files) to point to the new path. Never leave a stub file that says "Moved to X" — redirect docs rot, clutter the repo, and create false search hits.
|
|
13
|
+
|
|
14
|
+
**Present tense, current state only.** Active docs (everything outside `docs/history/`) describe the system _as it is now_ — what exists and how it works today. They never narrate how it got there: no migration/fold history, no dated "shipped/verified/built on YYYY-MM-DD" markers, no "ex-`@nurix/X`, folded 2026-06-12" provenance, no "was X → now Y" change journeys, no "removed/deleted in the <date> fold". The historical record — when and how things changed — lives **only** in `docs/history/` (changelog, plans, ADRs); `docs/memory/` is the agent's dated log and is likewise exempt. A doc may cite an ADR for the _why_ (the decision rationale), but must not narrate the _when/how it changed_. Routing/index docs point only to current authority docs — never to a historical plan or changelog as the "read first" source. When you find historical narration in an active doc, rewrite it to the present-tense fact and let `docs/history/` carry the story.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Decision Tree
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
User request
|
|
22
|
+
│
|
|
23
|
+
├─ "Baseline/reconcile docs" ──────▶ maintenance agent (baseline mode) (it calls this skill per template)
|
|
24
|
+
│
|
|
25
|
+
├─ "Document feature/module" ──────▶ Module Template
|
|
26
|
+
│
|
|
27
|
+
├─ "Create/update changelog" ──────▶ Changelog Template
|
|
28
|
+
│
|
|
29
|
+
├─ "Document data flow" ───────────▶ Module Template (Architecture section)
|
|
30
|
+
│
|
|
31
|
+
├─ "Document Redux/state" ─────────▶ Module Template (State section)
|
|
32
|
+
│
|
|
33
|
+
├─ "Add to protected files" ───────▶ Protected Files Template
|
|
34
|
+
│
|
|
35
|
+
├─ "Record architecture decision" ─▶ ADR Template
|
|
36
|
+
│
|
|
37
|
+
├─ "Create/update root README" ────▶ Project Root README Template
|
|
38
|
+
│
|
|
39
|
+
├─ "Create/update plan" ───────────▶ Plan Template
|
|
40
|
+
│
|
|
41
|
+
├─ "Update existing doc" ──────────▶ Preserve existing structure
|
|
42
|
+
│
|
|
43
|
+
└─ No template matches ────────────▶ Co-Authoring Workflow (below)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Naming & Lifecycle
|
|
49
|
+
|
|
50
|
+
- Features: `kebab-case.md` — living reference, status `Active`
|
|
51
|
+
- Plans: `YYYY-MM-DD-kebab-case.md` — frozen after `Complete` or `Abandoned`
|
|
52
|
+
- Changelogs: `YYYY-MM-DD-kebab-case.md` — append-only
|
|
53
|
+
- Memory: `{agent-name}.md` — agent-maintained
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Frontmatter Derivation
|
|
58
|
+
|
|
59
|
+
When creating or updating a feature doc, derive its **`owns:` frontmatter** — the code-path globs it is canonical for — from the source the doc describes. Code ownership lives in each feature doc's `owns:` frontmatter (the SessionStart hook unions them into the injected ownership index); there is no hand-maintained ownership map.
|
|
60
|
+
|
|
61
|
+
### When to run
|
|
62
|
+
|
|
63
|
+
- **Baseline / reconcile** — for every feature doc whose code paths aren't yet declared in its `owns:` frontmatter (the `maintenance` agent (baseline mode) calls this)
|
|
64
|
+
- **New feature doc** — when creating a doc via the Feature/Module template, project its `owns:` globs
|
|
65
|
+
- **Doc update** — when the documented scope changes, update the doc's `owns:` globs
|
|
66
|
+
|
|
67
|
+
### How to derive the frontmatter
|
|
68
|
+
|
|
69
|
+
A feature doc's launch-map frontmatter is `owns:` (required), `module:` (optional), `keywords:` (required), and `status:` (required).
|
|
70
|
+
|
|
71
|
+
**1. `owns:`** (the path scope)
|
|
72
|
+
|
|
73
|
+
Read the doc's content. Extract every source file path it references (file listings, function locations, component paths). Group them into the narrowest glob patterns that cover all referenced files without overlapping another doc's `owns:` globs at equal specificity. A doc may own several globs.
|
|
74
|
+
|
|
75
|
+
| Doc references | Glob |
|
|
76
|
+
| ------------------------------------ | ------------------------- |
|
|
77
|
+
| Multiple files under one directory | `src/feature/**` |
|
|
78
|
+
| Specific files in a shared directory | List each file explicitly |
|
|
79
|
+
| A single entry-point file | The exact file path |
|
|
80
|
+
|
|
81
|
+
Glob each pattern against the codebase; drop any that match nothing.
|
|
82
|
+
|
|
83
|
+
**2. `module:`**
|
|
84
|
+
|
|
85
|
+
The single bounded-context label this feature belongs to, or omit it for a cross-cutting feature that belongs to no single context. A module is a label, not a folder — features sharing a `module:` value are what ties that module to code (a filter over the generated ownership index).
|
|
86
|
+
|
|
87
|
+
**3. `keywords:` & `status:`**
|
|
88
|
+
|
|
89
|
+
`keywords:` are the discovery terms topic→doc lookup rides. `status:` is `active`, `draft`, or `deprecated` — it steers the model toward live docs and away from draft/deprecated ones.
|
|
90
|
+
|
|
91
|
+
A doc's dependencies on other docs are expressed inline in its prose (links); cross-cutting contracts are diagnosed by the `boundary` skill from source, not persisted.
|
|
92
|
+
|
|
93
|
+
### Rules
|
|
94
|
+
|
|
95
|
+
- One canonical doc per path. A doc's `owns:` globs must not overlap another doc's at equal specificity — the narrower glob wins; equal-specificity overlap is an ownership conflict to resolve.
|
|
96
|
+
- Use glob patterns for directories, explicit paths for individual files. Don't list paths that don't exist in the codebase.
|
|
97
|
+
- When a doc covers a deep feature with sub-specs (e.g., `editor/`), each sub-spec owns its own globs — don't duplicate a path across siblings.
|
|
98
|
+
- For baseline/reconcile with many docs, use parallel sub-agents to read source and propose `owns:` globs.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Co-Authoring Workflow
|
|
103
|
+
|
|
104
|
+
For docs that don't match templates:
|
|
105
|
+
|
|
106
|
+
**Stage 1: Context Gathering**
|
|
107
|
+
|
|
108
|
+
- Ask: Audience? Purpose? Existing format?
|
|
109
|
+
- Have user dump all context, then ask 5-10 clarifying questions
|
|
110
|
+
|
|
111
|
+
**Stage 2: Structure & Draft**
|
|
112
|
+
|
|
113
|
+
- Propose section structure, draft section by section
|
|
114
|
+
- User indicates changes (don't edit directly — learn their style)
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Resources
|
|
119
|
+
|
|
120
|
+
| File | Use For |
|
|
121
|
+
| --- | --- |
|
|
122
|
+
| `references/templates.md` | docs/README.md, structure.md, the feature-frontmatter contract, scaffolds (CHANGELOG, backlog, memory), feature, changelog, plan, protected files, ADR, project root README templates |
|
|
123
|
+
| `references/style-guide.md` | Writing rules, formatting conventions |
|
|
124
|
+
| `references/examples.md` | Good vs bad documentation examples |
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Documentation Examples
|
|
2
|
+
|
|
3
|
+
Good vs bad examples showing the key differences.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Example 1: Function Documentation
|
|
8
|
+
|
|
9
|
+
### ❌ Bad: Full Implementation
|
|
10
|
+
|
|
11
|
+
```markdown
|
|
12
|
+
### mergeData
|
|
13
|
+
|
|
14
|
+
function mergeData(server, local, changes) { const result = {}; const serverMap = new Map(server.map((i) => [i.id, i])); // ... 30 more lines return result; }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Problems:** Will become obsolete, focuses on HOW not WHAT.
|
|
18
|
+
|
|
19
|
+
### ✅ Good: Contract Only
|
|
20
|
+
|
|
21
|
+
```markdown
|
|
22
|
+
### `mergeData(serverData, localData, changes)`
|
|
23
|
+
|
|
24
|
+
**Goal:** Merge server data with local changes **Input:**
|
|
25
|
+
|
|
26
|
+
- `serverData` (array) - Fresh from API
|
|
27
|
+
- `localData` (array) - Current state
|
|
28
|
+
- `changes` (object) - `{ added, updated, removed }` **Output:** `{ merged: array, conflicts: array }`
|
|
29
|
+
|
|
30
|
+
**Merge Rules:**
|
|
31
|
+
|
|
32
|
+
- Server wins for conflicts
|
|
33
|
+
- Local additions preserved
|
|
34
|
+
- Local removals marked as intent
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Example 2: State Documentation
|
|
40
|
+
|
|
41
|
+
### ❌ Bad: State Everywhere
|
|
42
|
+
|
|
43
|
+
```markdown
|
|
44
|
+
## Component State
|
|
45
|
+
|
|
46
|
+
const [items, setItems] = useState([]);
|
|
47
|
+
|
|
48
|
+
## Hook State
|
|
49
|
+
|
|
50
|
+
{ data: items, isLoading: loading, error: null }
|
|
51
|
+
|
|
52
|
+
## Redux State
|
|
53
|
+
|
|
54
|
+
{ items: [], loading: false, error: null }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Problems:** Documents transient state, repeats shapes.
|
|
58
|
+
|
|
59
|
+
### ✅ Good: Persistence Points Only
|
|
60
|
+
|
|
61
|
+
```markdown
|
|
62
|
+
## State
|
|
63
|
+
|
|
64
|
+
**Frontend (at persistence):** { "data": [], "changes": { "added": [], "updated": [], "removed": [] } // "cache": {} // UNUSED: Deprecated }
|
|
65
|
+
|
|
66
|
+
**Storage:** localStorage `app_state`
|
|
67
|
+
|
|
68
|
+
**Backend:** model Item { id String @id data Json }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Example 3: Changelog
|
|
74
|
+
|
|
75
|
+
### ❌ Bad: Vague
|
|
76
|
+
|
|
77
|
+
```markdown
|
|
78
|
+
# 2025-01-05 - Updates
|
|
79
|
+
|
|
80
|
+
## Changes
|
|
81
|
+
|
|
82
|
+
- Updated editor
|
|
83
|
+
- Fixed bugs
|
|
84
|
+
- Improved performance
|
|
85
|
+
|
|
86
|
+
## Files
|
|
87
|
+
|
|
88
|
+
- Various files in src/
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### ✅ Good: Function-Level Detail
|
|
92
|
+
|
|
93
|
+
```markdown
|
|
94
|
+
# 2025-01-05 - Version-Based Merge
|
|
95
|
+
|
|
96
|
+
## Summary
|
|
97
|
+
|
|
98
|
+
Replaced change-tracking merge with version-based conflict resolution.
|
|
99
|
+
|
|
100
|
+
## Changes
|
|
101
|
+
|
|
102
|
+
### Added
|
|
103
|
+
|
|
104
|
+
- `mergeAndDerive(server, local, versionsMatch, type)` in `src/utils/merge.js`
|
|
105
|
+
- Purpose: Single-pass merge with change detection
|
|
106
|
+
- Returns: `{ merged, changes }`
|
|
107
|
+
|
|
108
|
+
### Modified
|
|
109
|
+
|
|
110
|
+
- `useDataSync()` in `src/hooks/useDataSync.js`
|
|
111
|
+
- Changed: Now compares versions before merge
|
|
112
|
+
|
|
113
|
+
### Removed
|
|
114
|
+
|
|
115
|
+
- `deriveChanges()` from `src/utils/derive.js`
|
|
116
|
+
- Replaced by: Logic in `mergeAndDerive()`
|
|
117
|
+
|
|
118
|
+
## Breaking Changes
|
|
119
|
+
|
|
120
|
+
⚠️ **Merge behavior changed**
|
|
121
|
+
|
|
122
|
+
- Old: Local changes always preserved
|
|
123
|
+
- New: Local preserved only if versions match
|
|
124
|
+
|
|
125
|
+
## Files Changed
|
|
126
|
+
|
|
127
|
+
- `src/hooks/useDataSync.js`
|
|
128
|
+
- `src/utils/merge.js`
|
|
129
|
+
- `src/utils/derive.js` (deleted)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Example 4: Data Flow
|
|
135
|
+
|
|
136
|
+
### ❌ Bad: Prose Description
|
|
137
|
+
|
|
138
|
+
```markdown
|
|
139
|
+
When the page loads, the useAppInit hook calls the syncData function. This function first fetches data from the server using the API. Then it gets the local data from Redux. After that, it compares versions...
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### ✅ Good: Diagram + Key Points
|
|
143
|
+
|
|
144
|
+
```markdown
|
|
145
|
+
## Data Flow
|
|
146
|
+
|
|
147
|
+
┌─────────────────────────────────────────┐ │ DATA SYNC │ ├─────────────────────────────────────────┤ │ │ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │ │Server│────▶│Merge │────▶│Redux │ │ │ │ API │ │ │ │Store │ │ │ └──────┘ └──────┘ └──────┘ │ │ │ │ │ ▼ │ │ Version Check │ │ │ └─────────────────────────────────────────┘
|
|
148
|
+
|
|
149
|
+
**Trigger:** `useAppInit()` on page load **Version Rule:** Match → local wins, Mismatch → server wins
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Quick Comparison
|
|
155
|
+
|
|
156
|
+
| Aspect | Bad | Good |
|
|
157
|
+
| ---------- | -------------------- | --------------------------- |
|
|
158
|
+
| Code | Full implementations | Signatures + contracts |
|
|
159
|
+
| State | Every occurrence | Persistence points only |
|
|
160
|
+
| Flows | Prose paragraphs | ASCII diagrams |
|
|
161
|
+
| Changelogs | "Updated X" | Function names + migrations |
|
|
162
|
+
| Length | 100+ lines | 20-40 lines |
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Documentation Style Guide
|
|
2
|
+
|
|
3
|
+
Writing rules for clear, maintainable documentation.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Function Documentation
|
|
8
|
+
|
|
9
|
+
### Signature Format
|
|
10
|
+
|
|
11
|
+
```markdown
|
|
12
|
+
### `functionName(param1, param2, options)`
|
|
13
|
+
|
|
14
|
+
**Goal:** One-line purpose **Input:**
|
|
15
|
+
|
|
16
|
+
- `param1` (type) - Description
|
|
17
|
+
- `param2` (type, optional) - Description **Output:** `{ field1, field2 }` **Side Effects:** State updates, API calls, etc.
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Parameter Rules
|
|
21
|
+
|
|
22
|
+
- Name + type + one-line purpose
|
|
23
|
+
- Mark optional params with `(type, optional)`
|
|
24
|
+
- Nest object properties:
|
|
25
|
+
```markdown
|
|
26
|
+
- `options` (object) - Configuration
|
|
27
|
+
- `options.retry` (boolean) - Enable retries
|
|
28
|
+
- `options.timeout` (number) - Timeout in ms
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Return Values
|
|
32
|
+
|
|
33
|
+
Always specify:
|
|
34
|
+
|
|
35
|
+
- Type: `Array<Object>`, `boolean`, `{ merged, changes }`
|
|
36
|
+
- Shape for objects/arrays
|
|
37
|
+
- Meaning: "True if sync successful"
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## State Documentation
|
|
42
|
+
|
|
43
|
+
### When to Document State
|
|
44
|
+
|
|
45
|
+
✅ Do:
|
|
46
|
+
|
|
47
|
+
- Redux persistence (localStorage, IndexedDB)
|
|
48
|
+
- Database schemas
|
|
49
|
+
- API request/response shapes
|
|
50
|
+
|
|
51
|
+
❌ Don't:
|
|
52
|
+
|
|
53
|
+
- Component-level state
|
|
54
|
+
- Derived/computed state
|
|
55
|
+
- Temporary UI state
|
|
56
|
+
|
|
57
|
+
### Format
|
|
58
|
+
|
|
59
|
+
````markdown
|
|
60
|
+
**Frontend (at persistence):**
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"activeField": "value"
|
|
65
|
+
// "deprecated": null // UNUSED: Remove in v3
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
````
|
|
69
|
+
|
|
70
|
+
**Storage:** localStorage key `state_key`
|
|
71
|
+
|
|
72
|
+
**Backend:**
|
|
73
|
+
|
|
74
|
+
```sql
|
|
75
|
+
model Table {
|
|
76
|
+
id String @id
|
|
77
|
+
data Json
|
|
78
|
+
// old String? // UNUSED: Legacy
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
````
|
|
83
|
+
|
|
84
|
+
### Mark Unused Keys
|
|
85
|
+
|
|
86
|
+
Always comment deprecated/unused fields:
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"active": [],
|
|
90
|
+
// "legacy": {} // UNUSED: Migrated to newField
|
|
91
|
+
}
|
|
92
|
+
````
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## ASCII Diagrams
|
|
97
|
+
|
|
98
|
+
### When to Use
|
|
99
|
+
|
|
100
|
+
- Data flows
|
|
101
|
+
- System architecture
|
|
102
|
+
- Component interactions
|
|
103
|
+
- Process flows
|
|
104
|
+
|
|
105
|
+
### Pattern
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
┌─────────────────────────────────────────┐
|
|
109
|
+
│ TITLE │
|
|
110
|
+
├─────────────────────────────────────────┤
|
|
111
|
+
│ │
|
|
112
|
+
│ ┌──────┐ ┌──────┐ ┌──────┐ │
|
|
113
|
+
│ │ A │────▶│ B │────▶│ C │ │
|
|
114
|
+
│ └──────┘ └──────┘ └──────┘ │
|
|
115
|
+
│ │ │ │
|
|
116
|
+
│ ▼ ▼ │
|
|
117
|
+
│ Detail Detail │
|
|
118
|
+
│ │
|
|
119
|
+
└─────────────────────────────────────────┘
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Characters
|
|
123
|
+
|
|
124
|
+
- Boxes: `┌─┐│└┘├┤┬┴┼`
|
|
125
|
+
- Arrows: `───▶` `◀───` `│▼` `│▲`
|
|
126
|
+
- Width: ~70 chars max
|
|
127
|
+
|
|
128
|
+
### UI Wireframes
|
|
129
|
+
|
|
130
|
+
For screen layouts (not data flows), use these conventions:
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
**Route:** `path/:id`
|
|
134
|
+
**Tab:** Tab Name
|
|
135
|
+
|
|
136
|
+
┌────────────────────────────────────┐
|
|
137
|
+
│ Title [i]3 [Button]│
|
|
138
|
+
│ [i]Label [Tag1][Tag2][+Add] │
|
|
139
|
+
└────────────────────────────────────┘
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- `[text]` = clickable button/badge
|
|
143
|
+
- `[i]` = icon (followed by label or count)
|
|
144
|
+
- `v` / `^` = expand/collapse indicator
|
|
145
|
+
- Show each UI state (collapsed/expanded) as separate diagrams
|
|
146
|
+
- Include Route/Tab context above wireframe
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Code Examples
|
|
151
|
+
|
|
152
|
+
### Rules
|
|
153
|
+
|
|
154
|
+
- Under 15 lines
|
|
155
|
+
- Show contracts, not implementations
|
|
156
|
+
- Use pseudocode for algorithms
|
|
157
|
+
|
|
158
|
+
✅ Good:
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
// Critical: Balanced brace matching
|
|
162
|
+
function extract(json) {
|
|
163
|
+
// Track brace depth
|
|
164
|
+
// Ignore braces inside strings
|
|
165
|
+
// Return complete objects only
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
❌ Bad: Full 50-line implementation
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Writing Style
|
|
174
|
+
|
|
175
|
+
### Voice
|
|
176
|
+
|
|
177
|
+
Use imperative/active:
|
|
178
|
+
|
|
179
|
+
- ✅ "Fetches data from server"
|
|
180
|
+
- ✅ "Returns array of objects"
|
|
181
|
+
- ❌ "This function is used to fetch"
|
|
182
|
+
- ❌ "An array is returned"
|
|
183
|
+
|
|
184
|
+
### When Prose Adds Value
|
|
185
|
+
|
|
186
|
+
Prose is valuable for context that contracts can't capture:
|
|
187
|
+
|
|
188
|
+
| Use Prose For | Example |
|
|
189
|
+
| --- | --- |
|
|
190
|
+
| Section intros | "When the editor mounts, `useAppInit` is called with the `appId` from URL." |
|
|
191
|
+
| Non-obvious behavior | "The hook always fetches fresh data. There is no caching or version checking." |
|
|
192
|
+
| Design rationale | "Why parallel fetches? Each entity type is independent, reducing load time." |
|
|
193
|
+
| Edge cases | "If created then deleted before save, it's removed from `added[]` without adding to `removed[]`." |
|
|
194
|
+
| Current limitations | "This hook is not currently integrated into the main flow." |
|
|
195
|
+
| Usage context | "Used to show 'Unsaved' badge, warn before navigation, enable save buttons." |
|
|
196
|
+
|
|
197
|
+
### When to Avoid Prose
|
|
198
|
+
|
|
199
|
+
- Describing WHAT code does (use signatures instead)
|
|
200
|
+
- Step-by-step flows (use diagrams instead)
|
|
201
|
+
- Structured comparisons (use tables instead)
|
|
202
|
+
|
|
203
|
+
### Conciseness
|
|
204
|
+
|
|
205
|
+
One line when possible:
|
|
206
|
+
|
|
207
|
+
- ✅ "Merge server data with local changes using version-based conflict resolution"
|
|
208
|
+
- ❌ "This function takes the data from the server and also takes the local data..."
|
|
209
|
+
|
|
210
|
+
### Tables
|
|
211
|
+
|
|
212
|
+
Use for structured info:
|
|
213
|
+
|
|
214
|
+
```markdown
|
|
215
|
+
| Parameter | Type | Description |
|
|
216
|
+
| --------- | ------ | -------------- |
|
|
217
|
+
| `data` | object | Fresh from API |
|
|
218
|
+
| `local` | object | Current state |
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Tense & History
|
|
224
|
+
|
|
225
|
+
**Active docs describe the present, not the past.** Everything outside `docs/history/` states what the system _is_ and how it works _today_. It must not narrate how it got there. The historical record — the journey, the dates, the migrations — lives **only** in `docs/history/` (changelog, plans, ADRs). (`docs/memory/` is the agent's own dated log and is likewise exempt from this rule.)
|
|
226
|
+
|
|
227
|
+
Strip this language from active docs:
|
|
228
|
+
|
|
229
|
+
| ❌ Historical narration (belongs in `docs/history/`) | ✅ Present-tense fact (belongs in the active doc) |
|
|
230
|
+
| --- | --- |
|
|
231
|
+
| "Folded in from the `NuStack-X` repo (2026-06-12)." | "Vendor-connector catalogue; one subpath per vendor." |
|
|
232
|
+
| "Built 2026-06-14; shipped + verified 2026-06-13." | "`agentSessionWorkflow` runs an outer turn loop over `runAgentLoop`." |
|
|
233
|
+
| "The legacy worker was deleted in the 2026-06-14 fold." | "One worker interprets `WorkflowDefinition`." |
|
|
234
|
+
| "ex-`@nurix/mcp-runtime`, M9 Phase C; was X, now Y." | "MCP client runtime, wired into `agentTriggerWorkflow`." |
|
|
235
|
+
| "Read first: `docs/history/plans/2026-…-fold.md`" (routing) | "Read first: `docs/architecture/<current-SOT>.md`" |
|
|
236
|
+
|
|
237
|
+
Rules:
|
|
238
|
+
|
|
239
|
+
- **No dates in active docs** for when something shipped, was verified, folded, or was removed. A bare status marker (`✅ shipped`, `⏳ pending`) is fine; the _date_ it shipped is not.
|
|
240
|
+
- **Cite the ADR for the _why_, never the _when_.** `Provenance: ADR-002` is good (it points to the decision rationale). "Decided in ADR-002 and shipped 2026-06-13" is not.
|
|
241
|
+
- **Routing/index docs point only to current authority docs.** A row whose only "read first" target is a historical plan or changelog is a redirect-for-history — repoint it to the current SOT doc, or drop the row.
|
|
242
|
+
- **When a doc changes because the system changed, the change-story goes in `docs/history/` (a changelog entry), and the active doc simply becomes correct in present tense.** Never leave the diff narrated in place.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Structure
|
|
247
|
+
|
|
248
|
+
### Headers
|
|
249
|
+
|
|
250
|
+
```markdown
|
|
251
|
+
# Document Title (H1 - once)
|
|
252
|
+
|
|
253
|
+
## Major Section (H2)
|
|
254
|
+
|
|
255
|
+
### Subsection (H3)
|
|
256
|
+
|
|
257
|
+
#### Detail (H4 - sparingly)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Standard Layout
|
|
261
|
+
|
|
262
|
+
```markdown
|
|
263
|
+
# [Title]
|
|
264
|
+
|
|
265
|
+
**Goal:** One-line purpose
|
|
266
|
+
|
|
267
|
+
## Architecture
|
|
268
|
+
|
|
269
|
+
[Diagram + explanation]
|
|
270
|
+
|
|
271
|
+
## Key Functions
|
|
272
|
+
|
|
273
|
+
[Signatures and contracts]
|
|
274
|
+
|
|
275
|
+
## State
|
|
276
|
+
|
|
277
|
+
[Persistence shapes]
|
|
278
|
+
|
|
279
|
+
## Files
|
|
280
|
+
|
|
281
|
+
[Source file list]
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### File References
|
|
285
|
+
|
|
286
|
+
Always end with:
|
|
287
|
+
|
|
288
|
+
```markdown
|
|
289
|
+
## Files
|
|
290
|
+
|
|
291
|
+
- `src/path/main.js` - Core logic
|
|
292
|
+
- `src/path/hooks.js` - React hooks
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Summary
|
|
298
|
+
|
|
299
|
+
| Aspect | Rule |
|
|
300
|
+
| ---------- | ------------------------------- |
|
|
301
|
+
| Functions | Always include signatures |
|
|
302
|
+
| Parameters | Type + purpose |
|
|
303
|
+
| Returns | Type + shape |
|
|
304
|
+
| State | Persistence points only |
|
|
305
|
+
| Diagrams | ASCII for all flows |
|
|
306
|
+
| Code | Under 15 lines, contracts only |
|
|
307
|
+
| Voice | Imperative/active |
|
|
308
|
+
| Length | Concise, one line when possible |
|