@nurix/etna 0.20.34 → 0.20.36
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/data/catalog/rules/changelog.md +1 -1
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/CLAUDE.md +4 -4
- package/data/harnesses/code/agents/brainstorm.md +2 -2
- package/data/harnesses/code/agents/lld-mode.md +2 -2
- package/data/harnesses/code/agents/maintenance.md +17 -17
- package/data/harnesses/code/codex/agents/brainstorm.toml +6 -2
- package/data/harnesses/code/codex/agents/lld-mode.toml +2 -2
- package/data/harnesses/code/codex/agents/maintenance.toml +18 -17
- package/data/harnesses/code/docs/README.md +9 -17
- package/data/harnesses/code/docs/history/CHANGELOG.md +19 -18
- package/data/harnesses/code/docs/structure.md +60 -45
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/hooks/compliance.mjs +8 -2
- package/data/harnesses/code/hooks/lib/sweep.mjs +3 -2
- package/data/harnesses/code/rules/changelog.md +1 -1
- package/data/harnesses/code/skills/brainstorm/SKILL.md +4 -3
- package/data/harnesses/code/skills/brainstorm/references/harvest.md +1 -2
- package/data/harnesses/code/skills/design/SKILL.md +3 -2
- package/data/harnesses/code/skills/design/references/content.md +1 -1
- package/data/harnesses/code/skills/design/references/existing-apps.md +1 -1
- package/data/harnesses/code/skills/design/references/microcopy.md +126 -0
- package/data/harnesses/code/skills/documentation/SKILL.md +91 -142
- package/data/harnesses/code/skills/documentation/references/examples.md +35 -62
- package/data/harnesses/code/skills/documentation/references/frontmatter.md +7 -7
- package/data/harnesses/code/skills/documentation/references/source-comments.md +19 -0
- package/data/harnesses/code/skills/documentation/references/style-guide.md +21 -7
- package/data/harnesses/code/skills/documentation/references/untemplated.md +7 -6
- package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +178 -38
- package/data/harnesses/code/skills/documentation/templates/Readme.md +68 -41
- package/data/harnesses/code/skills/documentation/templates/acceptance-criteria.md +10 -18
- package/data/harnesses/code/skills/documentation/templates/api-reference.md +7 -2
- package/data/harnesses/code/skills/documentation/templates/architecture-decision.md +5 -5
- package/data/harnesses/code/skills/documentation/templates/backlog.md +2 -2
- package/data/harnesses/code/skills/documentation/templates/behavioral-checklist.md +9 -16
- package/data/harnesses/code/skills/documentation/templates/bookkeeping.md +2 -2
- package/data/harnesses/code/skills/documentation/templates/changelog-entry.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/changelog-index.md +21 -29
- package/data/harnesses/code/skills/documentation/templates/docs-readme.md +2 -2
- package/data/harnesses/code/skills/documentation/templates/doctrine.md +2 -2
- package/data/harnesses/code/skills/documentation/templates/domain-model.md +9 -4
- package/data/harnesses/code/skills/documentation/templates/environment-registry.md +6 -1
- package/data/harnesses/code/skills/documentation/templates/feature.md +4 -4
- package/data/harnesses/code/skills/documentation/templates/glossary.md +6 -1
- package/data/harnesses/code/skills/documentation/templates/handover.md +16 -16
- package/data/harnesses/code/skills/documentation/templates/implementation-map.md +9 -4
- package/data/harnesses/code/skills/documentation/templates/journal.md +2 -2
- package/data/harnesses/code/skills/documentation/templates/memory-main.md +2 -2
- package/data/harnesses/code/skills/documentation/templates/non-goals.md +7 -2
- package/data/harnesses/code/skills/documentation/templates/operations-procedure.md +6 -1
- package/data/harnesses/code/skills/documentation/templates/package.md +4 -8
- package/data/harnesses/code/skills/documentation/templates/plan.md +5 -11
- package/data/harnesses/code/skills/documentation/templates/protected-files.md +6 -1
- package/data/harnesses/code/skills/documentation/templates/root-readme.md +4 -4
- package/data/harnesses/code/skills/documentation/templates/security-overview.md +8 -3
- package/data/harnesses/code/skills/documentation/templates/setup.md +6 -6
- package/data/harnesses/code/skills/documentation/templates/system-overview.md +11 -6
- package/data/harnesses/code/skills/documentation/templates/system.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/testing-strategy.md +10 -5
- package/data/harnesses/code/skills/documentation/templates/ux-behavior.md +13 -2
- package/data/harnesses/code/skills/testing/SKILL.md +1 -1
- package/data/harnesses/delivery/CLAUDE.md +1 -1
- package/data/harnesses/delivery/agents/brainstorm.md +2 -2
- package/data/harnesses/delivery/agents/lld-mode.md +2 -2
- package/data/harnesses/delivery/agents/maintenance.md +17 -17
- package/data/harnesses/delivery/codex/agents/brainstorm.toml +6 -2
- package/data/harnesses/delivery/codex/agents/lld-mode.toml +2 -2
- package/data/harnesses/delivery/codex/agents/maintenance.toml +18 -17
- package/data/harnesses/delivery/harness.json +2 -2
- package/data/harnesses/delivery/rules/changelog.md +1 -1
- package/data/harnesses/delivery/skills/brainstorm/SKILL.md +4 -3
- package/data/harnesses/delivery/skills/brainstorm/references/harvest.md +1 -2
- package/data/harnesses/delivery/skills/documentation/SKILL.md +91 -142
- package/data/harnesses/delivery/skills/documentation/references/examples.md +35 -62
- package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +7 -7
- package/data/harnesses/delivery/skills/documentation/references/source-comments.md +19 -0
- package/data/harnesses/delivery/skills/documentation/references/style-guide.md +21 -7
- package/data/harnesses/delivery/skills/documentation/references/untemplated.md +7 -6
- package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +178 -38
- package/data/harnesses/delivery/skills/documentation/templates/Readme.md +68 -41
- package/data/harnesses/delivery/skills/documentation/templates/acceptance-criteria.md +10 -18
- package/data/harnesses/delivery/skills/documentation/templates/api-reference.md +7 -2
- package/data/harnesses/delivery/skills/documentation/templates/architecture-decision.md +5 -5
- package/data/harnesses/delivery/skills/documentation/templates/backlog.md +2 -2
- package/data/harnesses/delivery/skills/documentation/templates/behavioral-checklist.md +9 -16
- package/data/harnesses/delivery/skills/documentation/templates/bookkeeping.md +2 -2
- package/data/harnesses/delivery/skills/documentation/templates/changelog-entry.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/changelog-index.md +21 -29
- package/data/harnesses/delivery/skills/documentation/templates/docs-readme.md +2 -2
- package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +2 -2
- package/data/harnesses/delivery/skills/documentation/templates/domain-model.md +9 -4
- package/data/harnesses/delivery/skills/documentation/templates/environment-registry.md +6 -1
- package/data/harnesses/delivery/skills/documentation/templates/feature.md +4 -4
- package/data/harnesses/delivery/skills/documentation/templates/glossary.md +6 -1
- package/data/harnesses/delivery/skills/documentation/templates/handover.md +16 -16
- package/data/harnesses/delivery/skills/documentation/templates/implementation-map.md +9 -4
- package/data/harnesses/delivery/skills/documentation/templates/journal.md +2 -2
- package/data/harnesses/delivery/skills/documentation/templates/memory-main.md +2 -2
- package/data/harnesses/delivery/skills/documentation/templates/non-goals.md +7 -2
- package/data/harnesses/delivery/skills/documentation/templates/operations-procedure.md +6 -1
- package/data/harnesses/delivery/skills/documentation/templates/package.md +4 -8
- package/data/harnesses/delivery/skills/documentation/templates/plan.md +5 -11
- package/data/harnesses/delivery/skills/documentation/templates/protected-files.md +6 -1
- package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +4 -4
- package/data/harnesses/delivery/skills/documentation/templates/security-overview.md +8 -3
- package/data/harnesses/delivery/skills/documentation/templates/setup.md +6 -6
- package/data/harnesses/delivery/skills/documentation/templates/system-overview.md +11 -6
- package/data/harnesses/delivery/skills/documentation/templates/system.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/testing-strategy.md +10 -5
- package/data/harnesses/delivery/skills/documentation/templates/ux-behavior.md +13 -2
- package/data/harnesses/etna/CLAUDE.md +2 -2
- package/data/harnesses/etna/agents/brainstorm.md +2 -2
- package/data/harnesses/etna/agents/lld-mode.md +2 -2
- package/data/harnesses/etna/agents/maintenance.md +17 -17
- package/data/harnesses/etna/codex/agents/brainstorm.toml +6 -2
- package/data/harnesses/etna/codex/agents/lld-mode.toml +2 -2
- package/data/harnesses/etna/codex/agents/maintenance.toml +18 -17
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/rules/changelog.md +1 -1
- package/data/harnesses/etna/skills/brainstorm/SKILL.md +4 -3
- package/data/harnesses/etna/skills/brainstorm/references/harvest.md +1 -2
- package/data/harnesses/etna/skills/documentation/SKILL.md +91 -142
- package/data/harnesses/etna/skills/documentation/references/examples.md +35 -62
- package/data/harnesses/etna/skills/documentation/references/frontmatter.md +7 -7
- package/data/harnesses/etna/skills/documentation/references/source-comments.md +19 -0
- package/data/harnesses/etna/skills/documentation/references/style-guide.md +21 -7
- package/data/harnesses/etna/skills/documentation/references/untemplated.md +7 -6
- package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +178 -38
- package/data/harnesses/etna/skills/documentation/templates/Readme.md +68 -41
- package/data/harnesses/etna/skills/documentation/templates/acceptance-criteria.md +10 -18
- package/data/harnesses/etna/skills/documentation/templates/api-reference.md +7 -2
- package/data/harnesses/etna/skills/documentation/templates/architecture-decision.md +5 -5
- package/data/harnesses/etna/skills/documentation/templates/backlog.md +2 -2
- package/data/harnesses/etna/skills/documentation/templates/behavioral-checklist.md +9 -16
- package/data/harnesses/etna/skills/documentation/templates/bookkeeping.md +2 -2
- package/data/harnesses/etna/skills/documentation/templates/changelog-entry.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/changelog-index.md +21 -29
- package/data/harnesses/etna/skills/documentation/templates/docs-readme.md +2 -2
- package/data/harnesses/etna/skills/documentation/templates/doctrine.md +2 -2
- package/data/harnesses/etna/skills/documentation/templates/domain-model.md +9 -4
- package/data/harnesses/etna/skills/documentation/templates/environment-registry.md +6 -1
- package/data/harnesses/etna/skills/documentation/templates/feature.md +4 -4
- package/data/harnesses/etna/skills/documentation/templates/glossary.md +6 -1
- package/data/harnesses/etna/skills/documentation/templates/handover.md +16 -16
- package/data/harnesses/etna/skills/documentation/templates/implementation-map.md +9 -4
- package/data/harnesses/etna/skills/documentation/templates/journal.md +2 -2
- package/data/harnesses/etna/skills/documentation/templates/memory-main.md +2 -2
- package/data/harnesses/etna/skills/documentation/templates/non-goals.md +7 -2
- package/data/harnesses/etna/skills/documentation/templates/operations-procedure.md +6 -1
- package/data/harnesses/etna/skills/documentation/templates/package.md +4 -8
- package/data/harnesses/etna/skills/documentation/templates/plan.md +5 -11
- package/data/harnesses/etna/skills/documentation/templates/protected-files.md +6 -1
- package/data/harnesses/etna/skills/documentation/templates/root-readme.md +4 -4
- package/data/harnesses/etna/skills/documentation/templates/security-overview.md +8 -3
- package/data/harnesses/etna/skills/documentation/templates/setup.md +6 -6
- package/data/harnesses/etna/skills/documentation/templates/system-overview.md +11 -6
- package/data/harnesses/etna/skills/documentation/templates/system.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/testing-strategy.md +10 -5
- package/data/harnesses/etna/skills/documentation/templates/ux-behavior.md +13 -2
- package/package.json +2 -2
|
@@ -4,7 +4,7 @@ This file is the authority on **what belongs where** in `docs/`: the folder map,
|
|
|
4
4
|
|
|
5
5
|
**This file is the harness's, not the project's.** The installer writes it on every install and refresh, so nothing in it describes one repository: a folder a repo does not use is simply absent on disk, and a repo's own notes — legacy folders kept as provenance, retired genres, local exceptions — live in [`README.md`](README.md) § Notes for this repository, never here. Hand edits are overwritten on the next refresh. The one field written in place is `harness-version` in the frontmatter, stamped by the `maintenance` agent after its baseline reconcile; its absence is what tells a session the repo has not been baselined against the installed harness.
|
|
6
6
|
|
|
7
|
-
One canonical source per topic — link, don't copy. Only `CLAUDE.md`, `AGENTS.md`, and `README.md` live at the repo root.
|
|
7
|
+
One canonical source per topic — link, don't copy. Only `CLAUDE.md`, `AGENTS.md`, and `README.md` live at the repo root. Every per-genre fact this file does not need for placement — a genre's nature, its `type:` value, its required keys and sections — is the `documentation` skill's genre registry (`templates/Readme.md`), and `doc-lint` checks documents against it.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -23,8 +23,8 @@ docs/
|
|
|
23
23
|
│ ├── common/ # The enterprise plane — one `{concern}.md` per concern the platform handles
|
|
24
24
|
│ │ # the same way everywhere. Owns no code
|
|
25
25
|
│ └── decisions/ # ADs — `AD-NNN-{slug}.md`, one per subject, updated in place; the journey lives in
|
|
26
|
-
│ # each file's Decision Changelog tail.
|
|
27
|
-
│ #
|
|
26
|
+
│ # each file's Decision Changelog tail. Each AD's `description:` and `status:` say
|
|
27
|
+
│ # what it decides and whether it stands; Readme.md describes the folder, never a row per AD
|
|
28
28
|
├── features/ # Feature docs — `{feature}.md`, one per thing a person points at (an address, a command
|
|
29
29
|
│ # family, a named control), cut by its objects (flat, no subfolders). One of three owning genres, beside
|
|
30
30
|
│ # `architecture/packages/` and `architecture/systems/`; ownership is computed from `objects:` and source headers
|
|
@@ -32,7 +32,7 @@ docs/
|
|
|
32
32
|
├── operations/ # Procedures — `setup.md` (the one-time first run, incl. the stack), then development, deployment, signing, rotation, diagnostics;
|
|
33
33
|
│ │ # one topic-named `{procedure}.md` each. Also holds bookkeeping.md, the shared
|
|
34
34
|
│ │ # doc-sync work queue (hook-appended, bookkeeper-drained, a drained row deleted)
|
|
35
|
-
│ ├── release-notes/ # One operator-facing note per release (`YYYY-MM-DD-vX.Y.Z.md`);
|
|
35
|
+
│ ├── release-notes/ # One operator-facing note per release (`YYYY-MM-DD-vX.Y.Z.md`); listing the folder is the index
|
|
36
36
|
│ ├── issues/ # Local-tracker issue records (`type: issue`, `YYYY-MM-DD-{slug}.md`) — the
|
|
37
37
|
│ │ # `issue-bridge` skill's local pack; `status:` is the lifecycle
|
|
38
38
|
│ └── triage/ # Triage dossiers (`type: triage`, `YYYY-MM-DD-{slug}.md`) — one per investigated
|
|
@@ -40,41 +40,42 @@ docs/
|
|
|
40
40
|
├── tests/ # Behavioral test checklists (truth docs) — `{feature}.md`, step → **Assert**, named for
|
|
41
41
|
│ # the doc whose promises it proves. `ls docs/tests/` is the roster
|
|
42
42
|
├── research/ # Records — in-progress brainstorm sessions (`{topic}-brainstorm/`), standing-research
|
|
43
|
-
│ # folders (`{topic}/`) and loose standing-research notes (`{topic}.md`).
|
|
43
|
+
│ # folders (`{topic}/`) and loose standing-research notes (`{topic}.md`). The folder name is the topic
|
|
44
44
|
├── history/
|
|
45
|
-
│ ├── CHANGELOG.md #
|
|
45
|
+
│ ├── CHANGELOG.md # The changelog guide: how entries are named, owed and read. Never appended to
|
|
46
46
|
│ ├── changelog/ # Individual changelog entries, `YYYY-MM-DD-{three-words}.md` (frozen at commit)
|
|
47
47
|
│ ├── plans/ # Dated implementation plans, `YYYY-MM-DD-{slug}.md` (Status: field; Complete/Abandoned = frozen)
|
|
48
48
|
│ ├── migrations/ # One-shot migration runbooks, `YYYY-MM-DD-{slug}.md` — authored ahead, outcome-stamped, frozen
|
|
49
|
-
│ ├── brainstorms/ # Harvested brainstorm sessions (`{topic}/`), kept as provenance;
|
|
49
|
+
│ ├── brainstorms/ # Harvested brainstorm sessions (`{topic}/`), kept as provenance; the folder name is the topic
|
|
50
50
|
│ ├── research/ # Deep-research records (`{topic}/` — README.md synthesis + findings.md + sources.md).
|
|
51
51
|
│ │ # Frozen, cited, owns no code. Distinct from research/ at the docs root
|
|
52
52
|
│ ├── health-log.md # The maintenance agent's append-only pass record, one generated row per pass
|
|
53
|
-
│ ├── journal.md #
|
|
54
|
-
│ │ #
|
|
55
|
-
│ └── backlog.md #
|
|
56
|
-
└── memory/ #
|
|
53
|
+
│ ├── journal.md # Queue — mid-execution facts, one line each; a line resolves by landing in its owning
|
|
54
|
+
│ │ # doc (delete the row, cite it in the changelog entry)
|
|
55
|
+
│ └── backlog.md # Queue — open work by priority (P0–P3); a finished item is deleted
|
|
56
|
+
└── memory/ # Queues — project knowledge + per-agent strategy memory, compacted by their writers
|
|
57
57
|
├── main.md # Main-agent project memory
|
|
58
58
|
└── {agent}.md # One strategy-memory file per sub-agent that keeps one
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
## Doctrine every genre follows
|
|
62
62
|
|
|
63
|
+
- **Every document has one of three natures.** A **truth** document states what is true now and is rewritten in place, present tense, with no history in its body. A **record** states what happened, is dated, and is frozen at its terminal status. A **queue** holds work not done yet: rows are appended and deleted when resolved, and nothing else is edited — the backlog, the journal, the bookkeeping queue and `memory/`. Which genre has which nature is the genre registry's; the folders below follow it, with `history/` holding records and two queues.
|
|
64
|
+
- **No index keeps a row per file.** A folder's `Readme.md` describes what the folder holds and how its files are named; each file's `description:` is its own account, and listing the folder is the roster. Nothing appends to an index when a sibling file is added — not the changelog guide, not a decisions, research, brainstorms or release-notes folder.
|
|
63
65
|
- **`docs/architecture/`** is the design layer in four folders: **`packages/`** (one per project package — what it is and how it behaves), **`systems/`** (one per machine spanning packages), **`common/`** (the enterprise plane) and **`decisions/`** (the ADs, one per subject, updated in place, each journey confined to that file's Decision Changelog tail).
|
|
64
66
|
**`common/` and `decisions/` own no code; `packages/` and `systems/` do.** Ownership is computed, not positional and not typed: a document names the objects it designs in `objects:`, each source file's path header names the document that speaks for it, and the object closure links the two; the more specific claim wins — a feature's beats a system's, a system's beats a package's. Until the ownership scan switches to those edges it reads a transitional `owns:` region glob on each of the three owning genres (the `documentation` skill's `references/frontmatter.md`). **A package document is the residual owner of its tree**, so a package's exhaustive behavior spec is that document, not a feature doc.
|
|
65
67
|
**What earns which genre.** A project package earns a `packages/` document — one, always. A machine whose parts sit in several packages, which a reader asks about as one thing, earns a `systems/` document. A **feature** document exists for something a person points at — an address, a command family, a named control — and is cut by the objects it designs, never by the code's routers, tables, plans or packages; a machine nobody navigates to is a `systems/` document even when it owns tables, and a fragment whose central object is declared in a sibling merges into it. A concern handled the same way everywhere is `common/` and owns nothing — including the governing-decisions register (fixed product decisions `F-###`, baseline defaults `B-###`, external boundaries, out-of-scope), which is authored doctrine the `boundary` skill never persists to.
|
|
66
68
|
- **`history/research/` is not legacy — it is the installed deep-research genre**, one `{topic}/` folder per research pass in the three-file shape. A record is frozen and cited, owns no code, and is never edited to stay current; a new question gets a new topic folder. Entries that predate the three-file convention — a single file or a single-report folder — are kept as authored.
|
|
67
69
|
- **`docs/features/` is flat — every feature authority is a file, and no subfolder exists.** A subject too large for one file is two files, not a folder: `objects:` and the source headers already state authority, and a nested doc is one the ownership scan and the index rows reach last.
|
|
68
|
-
- **`docs/research/`** holds records, not authorities: its standing-research folders and loose notes ground plans and decisions
|
|
70
|
+
- **`docs/research/`** holds records, not authorities: its standing-research folders and loose notes ground plans and decisions. The `brainstorm` skill finds a session by its folder name.
|
|
69
71
|
- **`docs/tests/`** holds behavioral test checklists — one `{feature}.md` per surface, written as `- [ ] step` → `- [ ] **Assert**` (how to verify a feature's promised behavior). A checklist is written or updated **at the verification gate, before the driving** — it is the script the real surface is driven against and the menu the pinned suite tests are drawn from, so each behavior section closes with a `> Pinned:` line naming the test that guards it, `driven only` with the reason, or `none yet` with the test it owes. **No section carries a date** — the *event* of driving (its date, environment, evidence, a `FAIL` and the backlog item it raised) belongs to the changelog entry of the unit that drove it. A section a drive cannot reach says `not reachable — {what blocks it}` on its trace line until the blocker is gone. **The gate that drives a checklist maintains it** — retiring dead sections and repairing traces is part of the run, because a checklist owns no code and no ownership glob implicates it. The cross-system testing strategy is doctrine in `architecture/common/`. A checklist carries `type: checklist` plus `verifies:`, the doc(s) whose promises it proves; a target is legitimately a feature, a package or a system document, and several values are correct where one checklist proves promises two docs decide.
|
|
70
72
|
**`verifies:` is the load-bearing key, and the filename convention is not a substitute for it.** A same-named file is a coincidence no resolver can trust — it breaks the moment a checklist spans two docs or a feature is renamed. The inverse — which checklists cover a feature — is **generated, never listed in the feature doc**.
|
|
71
73
|
- **`docs/operations/bookkeeping.md`** is the shared doc-sync work queue — hooks append rows, the `bookkeeper` agent drains them, and the commit wall blocks while rows remain. It is **author-created, never scaffolded**, and its rows are **live work, never drift**: a drained row is deleted, so a fully drained file holds no rows at all. Read a waiver's referent before deleting it; deleting the record while the condition survives re-appends the finding as an `auto:` row that fails the wall the waiver passed.
|
|
72
|
-
- **`type:` is a required frontmatter key** on every doc that carries frontmatter — the genre stamp, its
|
|
73
|
-
**No genre is frontmatter-less by policy; the gaps are the templates.** `architecture/common/**` carries `type: doctrine` with `status:` and `objects:` and no `owns:`, from the documentation skill's doctrine template. `architecture/Readme.md` carries no block, because its template ships none and a block is never manufactured on a doc whose template has none. `architecture/packages/**` and `architecture/systems/**` carry `type: package` / `type: system` with `objects:` and `status:`, plus the transitional `owns:` region glob the ownership scan reads until it switches to source headers. The `operations/` procedures carry a hand-authored `type: operations` block; the bookkeeping queue carries none. Docs written by a skill that ships a block (`issue-bridge`'s `type: issue` / `type: triage`) carry it.
|
|
74
|
+
- **`type:` is a required frontmatter key** on every doc that carries frontmatter — the genre stamp, its values the genre registry's `type:` column (`feature`, `architecture-decision`, `project-memory`, `ux`, `acceptance-criteria`, …). It is tooling metadata like `last-reviewed:` and `status:`: external tooling reads it, sessions **preserve it on edits** and never narrate it in the body. The `maintenance` agent stamps it on docs that lack it. The owning genres (`type: feature`, `type: package`, `type: system`) carry the transitional `owns:` region glob the ownership scan reads until it switches to source headers; `type: doctrine` carries `objects:` and owns no code; the bookkeeping queue carries no block. Docs written by a skill that ships a block (`issue-bridge`'s `type: issue` / `type: triage`) carry it.
|
|
74
75
|
- **The docs tree is a graph, and nothing in it that can be computed is typed.** A document names the objects it designs (`objects:`); a source file names the document that speaks for it in its path header; the object closure computes the rest — which files a document speaks for, and which surfaces a doctrine governs. One doc → doc edge is authored, because nothing computes it: **`verifies:`** (checklist → the doc whose promises it proves). Its inverse is **generated** — `buildEdgeIndex()` in `.claude/hooks/lib/ownership.mjs`, injected at SessionStart beside the ownership index — and authoring an inverse by hand is a defect. `applies:` is retired; `owns:` is a transitional region glob (the `documentation` skill's `references/frontmatter.md`).
|
|
75
76
|
- **`docs/acceptance/` holds the acceptance-criteria genre** — one `kebab-case.md` per capability, written at specification time, before implementation, holding stable `AC-n` assert lines that verification surfaces parse as claims to grade the built product against; each file is keyed to the checklist sections that grade it. The folder is created on first use and never scaffolded. The `AC-n:` line grammar is load-bearing: the key sits at line start, exactly `AC-<number>:`, followed by the assert sentence — tables, emphasis-wrapped keys, and nested bullets break the parse.
|
|
76
|
-
- **The `ux` genre decides observable behavior; `docs/tests/` only verifies it.** A feature doc states what a feature is and which contracts it honours — all of which stay plausibly true through a rewrite of the surface — so a UX-behavior doc states what a person *observes*, and is written **before** the code.
|
|
77
|
-
- **`docs/history/journal.md`
|
|
77
|
+
- **The `ux` genre decides observable behavior; `docs/tests/` only verifies it.** A feature doc states what a feature is and which contracts it honours — all of which stay plausibly true through a rewrite of the surface — so a UX-behavior doc states what a person *observes*, and is written **before** the code. A surface needing the genre gets `features/{surface}-ux.md`, named in the headers of the component files no other document speaks for; where a feature document already speaks for them, the UX document is named in its For the agent **See also** line.
|
|
78
|
+
- **`docs/history/journal.md` drains into documents, and `docs/memory/` does not.** Both are queues. The journal holds mid-execution facts one line each, each resolved by landing in its owning doc; memory holds only per-agent strategy and project knowledge no single doc owns, compacted by its writer. A fact an owning doc will eventually carry goes to the journal, never to memory — nothing drains memory into a document, so what lands there stays until its writer retires it.
|
|
78
79
|
- **There is no `docs/history/sessions/`.** Per-session gate logs are machine-local, written by `.claude/hooks/lib/session-log.mjs` into `.claude/state/sessions/` (self-ignored), so they never enter `docs/` or git. A `docs/history/sessions/` folder is residue, not shape.
|
|
79
80
|
- **The repo-root `README.md` opens outward and turns inward.** What the product does, for whom and where it runs, in a user's terms; then, for the team and agents, how it works, a Map of top-level units with their owning doc, the rules that bite, where to go by intent, and at most four everyday commands. It carries no install, stack or tree — install and stack are `operations/setup.md`, the tree is this file's. Template: the `documentation` skill's `templates/root-readme.md`.
|
|
80
81
|
- **`docs/README.md` describes directories, never files.** One entry per folder: what it holds, who reads it, how its files are named — no per-file rows, no tree. It closes with the repository's own notes, the one place project-specific placement facts live.
|
|
@@ -84,12 +85,12 @@ docs/
|
|
|
84
85
|
|
|
85
86
|
## Lifecycle
|
|
86
87
|
|
|
87
|
-
- **Plans** (`history/plans/YYYY-MM-DD-{slug}.md`) carry a `Status:` field (`Draft` / `
|
|
88
|
+
- **Plans** (`history/plans/YYYY-MM-DD-{slug}.md`) carry a `Status:` field (`Draft` / `In Progress` / `Complete` / `Abandoned`). Once `Complete`/`Abandoned`, a plan is frozen — never edited; scope changes get a new dated plan that links back.
|
|
88
89
|
- **Migration runbooks** (`history/migrations/YYYY-MM-DD-{slug}.md`) are authored ahead of execution and record a one-shot infra/cutover procedure; once executed, the outcome is stamped into the file and it is frozen — a re-run gets a new dated runbook.
|
|
89
|
-
- **Changelog** entries land in `history/changelog
|
|
90
|
-
- **Backlog** items live in `history/backlog.md` under P0–P3 priorities
|
|
91
|
-
- **Brainstorm sessions** are author-created by the `brainstorm` skill: an active session at `docs/research/{topic}-brainstorm/` (older folders carry the legacy `-brainstorming/` suffix; both are canonical), moved to `docs/history/brainstorms/{topic}/` on a passed harvest — the move is the completion marker, and the moved folder's fate (delete or commit) is the author's call. Never scaffolded empty;
|
|
92
|
-
- **Source-of-truth audits** write nothing to `docs/`. The `polygraph`
|
|
90
|
+
- **Changelog** entries land in `history/changelog/`, one per unit of work, each opening on its one-line summary. `history/CHANGELOG.md` is the folder's guide and takes no row per entry; listing the folder is the index.
|
|
91
|
+
- **Backlog** items live in `history/backlog.md` under P0–P3 priorities — a queue: appended, and deleted when the work lands.
|
|
92
|
+
- **Brainstorm sessions** are author-created by the `brainstorm` skill: an active session at `docs/research/{topic}-brainstorm/` (older folders carry the legacy `-brainstorming/` suffix; both are canonical), moved to `docs/history/brainstorms/{topic}/` on a passed harvest — the move is the completion marker, and the moved folder's fate (delete or commit) is the author's call. Never scaffolded empty; no index keeps a row per session.
|
|
93
|
+
- **Source-of-truth audits** write nothing to `docs/`. The `polygraph` agent runs only when the user asks, on a named target (a doc, a feature, a folder, a code path or a plan), and keeps its rows under `.claude/state/polygraph/{run}/`, machine-local, never tracked, deleted in the same turn as the report. What survives a run is the corrected document itself and the backlog rows it registered; a run against a plan also leaves a `Polygraph:` segment on its `Gates:` line, which nothing reads.
|
|
93
94
|
- **Boundaries** are a plan-time diagnostic — the `boundary` skill reads contracts fresh from source; there is no persisted `boundaries/` tree.
|
|
94
95
|
- **Modules** are _declared labels_ (a `module:` key on a feature doc), never inferred from physical layout and never a folder. A feature always lives flat in `features/`.
|
|
95
96
|
|
|
@@ -97,31 +98,45 @@ docs/
|
|
|
97
98
|
|
|
98
99
|
## Add-a-doc decision table
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
The `type:` column is the value the document carries; its required keys and sections are the genre registry's row for that type.
|
|
102
|
+
|
|
103
|
+
| You are adding… | It goes in… | `type:` |
|
|
101
104
|
| --- | --- | --- |
|
|
102
|
-
| A feature document — something a person points at (an address, a command family, a named control), cut by the objects it designs | `features
|
|
103
|
-
|
|
|
104
|
-
| A
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
|
|
|
117
|
-
| A
|
|
118
|
-
|
|
|
119
|
-
|
|
|
120
|
-
| A
|
|
121
|
-
| A
|
|
122
|
-
| A
|
|
123
|
-
|
|
|
124
|
-
|
|
|
105
|
+
| A feature document — something a person points at (an address, a command family, a named control), cut by the objects it designs | `features/{feature}.md` (flat) | `type: feature` |
|
|
106
|
+
| What a person sees and can do on a surface (UX behavior) | `features/{surface}-ux.md`, named in the headers of the component files no other document speaks for; `architecture/common/` when it is cross-cutting | `type: ux` |
|
|
107
|
+
| A package's behavior document | `architecture/packages/{package}.md`, one per package | `type: package` |
|
|
108
|
+
| A system's behavior document | `architecture/systems/{system}.md`, one per machine | `type: system` |
|
|
109
|
+
| Cross-cutting design (doctrine) | `architecture/common/{concern}.md` | `type: doctrine` |
|
|
110
|
+
| The testing strategy | `architecture/common/testing.md` | `type: testing-strategy` |
|
|
111
|
+
| An Architecture Decision (AD) | `architecture/decisions/AD-NNN-{subject}.md` — one file per subject, updated in place; the journey lives in its Decision Changelog | `type: architecture-decision` |
|
|
112
|
+
| The system at a glance | `architecture/system-design.md` | `type: system-overview` |
|
|
113
|
+
| The domain model | `architecture/domain-model.md` | `type: domain-model` |
|
|
114
|
+
| The glossary | `architecture/glossary.md` | `type: glossary` |
|
|
115
|
+
| The non-goals | `architecture/non-goals.md` | `type: non-goals` |
|
|
116
|
+
| The security overview | `architecture/security.md` | `type: security-overview` |
|
|
117
|
+
| The API surface | `architecture/api.md` | `type: api-reference` |
|
|
118
|
+
| The environment variables | `operations/environment.md` | `type: environment-registry` |
|
|
119
|
+
| One-time machine setup, first run, stack, prerequisites, env files | `operations/setup.md` — fixed name, one per repo, linked from the root README; a diverging package gets a `### {unit}` subsection, never a second first-run doc | `type: operations` |
|
|
120
|
+
| A recurring procedure (develop, deploy, rotate, diagnose, CI) | `operations/{procedure}.md` | `type: operations` |
|
|
121
|
+
| The build order of a project built from its design | `operations/implementation-map.md` | `type: implementation-map` |
|
|
122
|
+
| The protected-files list | `operations/protected-files.md` | `type: protected-files` |
|
|
123
|
+
| A tracker issue held in the repo | `operations/issues/YYYY-MM-DD-{slug}.md` (via the `issue-bridge` skill's local pack) | `type: issue` |
|
|
124
|
+
| A triage dossier for an investigated issue | `operations/triage/YYYY-MM-DD-{slug}.md` (via the `issue-bridge` skill) — a dated working artifact that never claims `owns:` | `type: triage` |
|
|
125
|
+
| A behavioral test checklist | `tests/{feature}.md` — written at the verification gate before the driving, each section carrying a `Pinned:` trace; owns no code | `type: checklist` |
|
|
126
|
+
| Acceptance criteria for one capability | `acceptance/{capability}.md` — stable `AC-n` assert lines; keys are never renumbered or reused, a retired criterion is marked retired in place | `type: acceptance-criteria` |
|
|
127
|
+
| A folder's landing page | `{folder}/Readme.md` — describes the folder, never a row per file | `type: folder-index` |
|
|
128
|
+
| An in-progress brainstorm session | `research/{topic}-brainstorm/` (via the `brainstorm` skill) | none |
|
|
129
|
+
| A source-of-truth audit | Nowhere in `docs/` — the `polygraph` agent corrects the target doc in place | none |
|
|
130
|
+
| An implementation plan | `history/plans/YYYY-MM-DD-{slug}.md` (a `Status:` line is required) | none |
|
|
131
|
+
| A one-shot migration runbook | `history/migrations/YYYY-MM-DD-{slug}.md` (authored ahead; outcome-stamped and frozen once executed) | none |
|
|
132
|
+
| A hand-over at the end of an unattended or multi-session build | `history/handovers/YYYY-MM-DD-{slug}.md` | `type: handover` |
|
|
133
|
+
| A deep-research record | `history/research/{topic}/` — `README.md` synthesis + `findings.md` + `sources.md`; frozen and cited, a new question gets a new topic folder | none |
|
|
134
|
+
| A harvested brainstorm session | `history/brainstorms/{topic}/` (via the `brainstorm` skill's harvest) | none |
|
|
135
|
+
| A changelog entry | `history/changelog/YYYY-MM-DD-{three-words}.md`; `CHANGELOG.md` takes no row | none |
|
|
136
|
+
| A tracked work item | a row in `history/backlog.md` | none |
|
|
137
|
+
| A doc-sync debt row | a row in `operations/bookkeeping.md` (hook-appended; drained by the `bookkeeper` agent, deleted on drain) | none |
|
|
138
|
+
| A mid-execution fact worth keeping | a row in `history/journal.md` (resolves by landing in its owning doc) | none |
|
|
139
|
+
| Agent strategy / project memory | `memory/main.md`, `memory/{agent}.md` | `type: project-memory` on `main.md` |
|
|
125
140
|
|
|
126
141
|
---
|
|
127
142
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "code",
|
|
3
3
|
"name": "code",
|
|
4
|
-
"version": "3.20.
|
|
4
|
+
"version": "3.20.7",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
@@ -29,5 +29,5 @@
|
|
|
29
29
|
"origin": "https://cdn.nustack.io",
|
|
30
30
|
"track": "latest"
|
|
31
31
|
},
|
|
32
|
-
"digest": "
|
|
32
|
+
"digest": "8b47c959f89f"
|
|
33
33
|
}
|
|
@@ -145,13 +145,19 @@ function fileGate(projectDir, rel, sessionId) {
|
|
|
145
145
|
// The gate binds the plan's own paths, so disjoint plans run in parallel.
|
|
146
146
|
// A scopeless plan stays repo-wide — fail closed.
|
|
147
147
|
if (plan.scope.length && !inPlanScope(rel, plan.scope)) continue;
|
|
148
|
-
|
|
148
|
+
// Only a passed verdict opens the gate: `pending` has no verdict yet, and `blocked` is a verdict against coding.
|
|
149
|
+
const boundary = /Boundary:\s*(\w+)/i.exec(plan.gates);
|
|
150
|
+
if (boundary && !/^passed$/i.test(boundary[1])) {
|
|
149
151
|
return deny(
|
|
150
152
|
projectDir,
|
|
151
153
|
sessionId,
|
|
152
154
|
"plan-gate",
|
|
153
155
|
plan.file,
|
|
154
|
-
`BLOCKED — plan gate. \`${plan.file}\` is open but its Gates line reads 'Boundary:
|
|
156
|
+
`BLOCKED — plan gate. \`${plan.file}\` is open but its Gates line reads 'Boundary: ${boundary[1]}'. ${
|
|
157
|
+
/^blocked$/i.test(boundary[1])
|
|
158
|
+
? "Fold the `boundary` skill's amendments into the plan and re-run it until it records `passed`."
|
|
159
|
+
: "Run the `boundary` skill and record its verdict in the plan before implementation edits."
|
|
160
|
+
}`
|
|
155
161
|
);
|
|
156
162
|
}
|
|
157
163
|
if (!plan.hasLedger) {
|
|
@@ -24,13 +24,14 @@ import { readSafe, docsRoot } from "./repo.mjs";
|
|
|
24
24
|
import { resolveRows } from "./state.mjs";
|
|
25
25
|
import { rejectedPackages } from "./approved.mjs";
|
|
26
26
|
|
|
27
|
-
// Spawn the installed doc-lint over one file; returns finding lines (empty when absent/clean)
|
|
27
|
+
// Spawn the installed doc-lint over one file; returns its block-severity finding lines (empty when absent/clean),
|
|
28
|
+
// so a warning advises and only a blocking rule raises a row that walls the commit — as sourceLint() below.
|
|
28
29
|
export function docLint(projectDir, rel) {
|
|
29
30
|
const script = path.join(projectDir, ".claude", "skills", "documentation", "scripts", "doc-lint.mjs");
|
|
30
31
|
if (!fs.existsSync(script)) return [];
|
|
31
32
|
const res = spawnSync("node", [script, rel], { cwd: projectDir, encoding: "utf8", timeout: 5000 });
|
|
32
33
|
const out = `${res.stdout || ""}`;
|
|
33
|
-
return out.split("\n").filter((line) => /:\d+ \[
|
|
34
|
+
return out.split("\n").filter((line) => /:\d+ \[block\]/.test(line));
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
// True when the first path-shaped token in a source file's opening lines IS its repo-relative path.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
Every unit of work leaves one record — `docs/history/changelog/YYYY-MM-DD-{three-words}.md` (the three words name the work, not the commit)
|
|
3
|
+
Every unit of work leaves one record — `docs/history/changelog/YYYY-MM-DD-{three-words}.md` (the three words name the work, not the commit). `docs/history/CHANGELOG.md` is the folder's guide, never appended to: the entry's own first line is its summary, and listing the folder is the index. Entry format, field rules, and the closed exemption list are the `documentation` skill's `templates/changelog-entry.md`; this rule owns when an entry is owed and how it lives. An entry is never a commit summary — it carries the refinement context only the working session holds, which no diff reconstructs.
|
|
4
4
|
|
|
5
5
|
## When an entry is owed
|
|
6
6
|
|
|
@@ -38,8 +38,9 @@ folder plus ops is the session's whole memory.
|
|
|
38
38
|
|
|
39
39
|
## `start`
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
`docs/history/brainstorms
|
|
41
|
+
Find sessions by their folders — no index keeps a row per session: `docs/research/*-brainstorm/`
|
|
42
|
+
(active) and `docs/history/brainstorms/*/` (harvested), the folder name being the topic and each
|
|
43
|
+
`thesis.md` heading its subject. Topic matches an active session → resume it
|
|
43
44
|
(re-entry, below). Harvested or prior-generation match → offer it **as a basis** for a fresh
|
|
44
45
|
session. No match → new session.
|
|
45
46
|
|
|
@@ -52,7 +53,7 @@ session unless the user explicitly overrides. No basis, no session.
|
|
|
52
53
|
|
|
53
54
|
**2 · Bootstrap.** Folder `docs/research/{topic}-brainstorm/` (kebab slug, confirm in one line).
|
|
54
55
|
Create `ops/` with a `.gitignore` containing `*`, `ops/capture.md`, `ops/sync-log.md`; copy the
|
|
55
|
-
basis into `basis
|
|
56
|
+
basis into `basis/`. No index row: the folder is the session's entry. Then write the sync-log dispatch
|
|
56
57
|
line and dispatch the twin (gate: start) to write the initial surface — you don't scaffold
|
|
57
58
|
`state.md`/`thesis.md`/`forks.md`/`ledger.md` yourself.
|
|
58
59
|
|
|
@@ -76,8 +76,7 @@ The deletion-safety gate: after the apply, the post-harvest living docs alone mu
|
|
|
76
76
|
|
|
77
77
|
When the detector's move gate is clean: delete `ops/` entirely (transcript-grade residue never
|
|
78
78
|
enters git), `git mv` the folder to `docs/history/brainstorms/{topic}/`, set
|
|
79
|
-
`Status: harvested
|
|
80
|
-
`docs/history/brainstorms/Readme.md`). The move is the completion marker — a folder still under
|
|
79
|
+
and `Status: harvested`; no index is updated, because none keeps a row per session. The move is the completion marker — a folder still under
|
|
81
80
|
`docs/research/` is by definition unfinished, which is exactly what the maintenance census reads.
|
|
82
81
|
|
|
83
82
|
Then the offer, relayed by the facilitator: **delete the moved folder, or commit it.** The user
|
|
@@ -38,7 +38,7 @@ Steps 1–3 produce *inputs*; step 4 is one continuous whole-canvas act — neve
|
|
|
38
38
|
| --- | --- | --- |
|
|
39
39
|
| 1 Intake | Brief → recorded choices: one identity package, axis overrides, blueprints, domain corpus, the primitives switch; ends with the preview block | [references/intake.md](references/intake.md) |
|
|
40
40
|
| 2 Structure | The object pass: entities → surfaces → archetypes → states, via the UX-pattern layer | [references/object-pass.md](references/object-pass.md) |
|
|
41
|
-
| 3 Content | The believable book: demo data from the corpus, chart choices from the selection engine | [references/content.md](references/content.md) |
|
|
41
|
+
| 3 Content | The believable book: demo data from the corpus, chart choices from the selection engine, every authored string | [references/content.md](references/content.md) · [references/microcopy.md](references/microcopy.md) |
|
|
42
42
|
| 4 Compose | One mind, whole canvas: chrome, blueprints, the package's design.md in view throughout | [references/compose.md](references/compose.md) |
|
|
43
43
|
| 5 Ship gate | Tier-1 binary predicates fail closed; Tier-2 tells flag, never gate | [references/ship-gate.md](references/ship-gate.md) |
|
|
44
44
|
|
|
@@ -76,6 +76,7 @@ What enters context, when. Nothing loads whole except where this table says so.
|
|
|
76
76
|
| `references/ux-patterns/<pass>.md` (B2) | The one pass file (prose + its decision table) the current step-2 decision needs | all passes at once |
|
|
77
77
|
| Corpora | `search_catalog` (family `corpus`) → `get_entry` — body, invariants, people, companies in one payload, at step 3 | other domains |
|
|
78
78
|
| `data/voices/<id>.md` | The package-bound voice (the package's §9 names it), at step 3 | the voices folder |
|
|
79
|
+
| [references/microcopy.md](references/microcopy.md) | Whenever strings are authored or rewritten — step 3, and an improve run's copy pass | — |
|
|
79
80
|
| `data/chrome/<recipe>.md` | Recipes for surfaces in the structure doc, at step 4 | recipes for absent surfaces |
|
|
80
81
|
| [components/index.md](components/index.md) | Always available — the component dictionary, both switch positions and both provenances; a category's API reference on touch, `nurix` mode only | the folder whole; category references in `native` mode |
|
|
81
82
|
| `data/blueprints/<archetype>.md` | The chosen archetype's file at step 4 shape-choice; the chosen shape thereafter | all archetypes |
|
|
@@ -112,7 +113,7 @@ skills/design/
|
|
|
112
113
|
├── SKILL.md # this router
|
|
113
114
|
├── components/ # component dictionary: @nurix/components + hand-picked externals
|
|
114
115
|
├── scripts/ # validate-design-md.mjs · select-chart.mjs
|
|
115
|
-
├── references/ # the five steps + ship gate + existing apps + emission + foundations
|
|
116
|
+
├── references/ # the five steps + ship gate + existing apps + emission + foundations + microcopy
|
|
116
117
|
│ └── ux-patterns/ # B2 decision passes (one file per pass, prose + table)
|
|
117
118
|
└── data/ # the embedded families: voices/ chrome/ blueprints/ checklists/
|
|
118
119
|
# elevation/ motion/ iconography.md · tells.csv · charts/ (census)
|
|
@@ -14,7 +14,7 @@ Fetch the chosen domain's corpus — `search_catalog` (family `corpus`) to find
|
|
|
14
14
|
|
|
15
15
|
## Voice
|
|
16
16
|
|
|
17
|
-
Load the package-bound voice pack (`data/voices/<id>.md` — the package's §9 names it). All authored strings — buttons, empty states, errors, tooltips, confirmations — speak in that voice, with tone varying by situation per the pack's tone map.
|
|
17
|
+
Load the package-bound voice pack (`data/voices/<id>.md` — the package's §9 names it) and [microcopy.md](microcopy.md). All authored strings — buttons, empty states, errors, tooltips, confirmations, stat cards, server messages the interface shows — speak in that voice, with tone varying by situation per the pack's tone map, and take the form and mechanics `microcopy.md` sets for their element.
|
|
18
18
|
|
|
19
19
|
## Chart choice
|
|
20
20
|
|
|
@@ -14,7 +14,7 @@ Whole-canvas authority holds, under the **preservation contract**:
|
|
|
14
14
|
2. **Preserve/introduce declaration** precedes any change: what stays, what enters, in one block.
|
|
15
15
|
3. **The never-silently-change list** holds regardless of authority: routes and slugs, nav labels, form field names and IDs, brand marks, legal copy. The no-jails law is about *our* generated files; a user's existing brand and IA are theirs. Changing anything on this list requires the user's explicit ask.
|
|
16
16
|
|
|
17
|
-
Improve runs then proceed through the standard steps as scoped: intake (against the incumbent — the package choice may be "extract", below), structure only where surfaces change, content only where data is fake, compose with the finishing pass, and the ship gate on what was touched.
|
|
17
|
+
Improve runs then proceed through the standard steps as scoped: intake (against the incumbent — the package choice may be "extract", below), structure only where surfaces change, content only where data is fake or the ask is the wording (the copy pass, `microcopy.md` § The copy pass on an existing app), compose with the finishing pass, and the ship gate on what was touched.
|
|
18
18
|
|
|
19
19
|
## Extract — reading an identity package out of a foreign UI
|
|
20
20
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Microcopy — the words on the screen
|
|
2
|
+
|
|
3
|
+
Every string a person reads inside an application: labels, buttons, headings, stat cards, table headers, form help, empty, loading and error states, toasts, confirmations, tooltips, status chips, and the messages a server sends back for the interface to show. The package's voice pack (`data/voices/<id>.md`, named by the design.md's §9) sets the personality and tone map; this file sets the rules every voice obeys. **On a conflict, the voice wins on register and this file wins on mechanics** — a voice may be brisk or warm, but no voice puts a period on a button or an error code in a sentence.
|
|
4
|
+
|
|
5
|
+
Distilled from the Mailchimp Content Style Guide (styleguide.mailchimp.com, CC BY-NC 4.0: voice and tone, writing principles, grammar and mechanics, web elements, writing about people, accessibility, translation) and the documentation skill's style guide (noun-phrase labels, present tense, the stability test), adapted to operator interfaces.
|
|
6
|
+
|
|
7
|
+
## Principles
|
|
8
|
+
|
|
9
|
+
Every rule below follows from these; cite them by number when you record a copy decision.
|
|
10
|
+
|
|
11
|
+
1. **Clear before clever.** A string exists so a person can act. Personality is allowed only where it costs no clarity, and never in an error.
|
|
12
|
+
2. **The work, in the user's words — never the machine.** A string that would change when a table, route, service, error code, environment variable or function is renamed is mechanism leaking into the interface (the documentation skill's stability test, applied to the screen). "Check that the Worker is running" and "BAD_CREDENTIALS: …" are the code talking; "Couldn't reach the server. Retry in a moment." is the product talking.
|
|
13
|
+
3. **Labels name, actions command, messages explain.** The grammatical form is set by the element, never by taste: a label is a noun phrase with no verb and no pronoun; an action is an imperative verb with its object; a message is full sentences. Mixing them is the commonest source of copy that reads "weird".
|
|
14
|
+
4. **One concept, one word.** The product's glossary binds every surface: if the record is a *candidate* on one page it is never an *applicant*, *person* or *profile* on the next, and a status is spelled the same in the chip, the filter and the toast. Never vary a term for elegance.
|
|
15
|
+
5. **Present tense, current state.** Copy describes what is, now. No narration of change ("moved to", "now supports", "new!"), no temporal hedges ("currently", "for now", "still") unless the state genuinely waits on a known event, and no talk about the product's own progress.
|
|
16
|
+
6. **Tone follows the reader's state.** Voice is constant; tone dials with the situation (§ Tone map). Calm and specific when something fails, brief when something succeeds, plain when something is destroyed.
|
|
17
|
+
7. **Every message answers the next question.** What happened, why — when the reason is known and useful — and what to do now. An error with no way forward is unfinished.
|
|
18
|
+
8. **Short, never cryptic.** Cut every word that carries nothing ("successfully", "please note", "in order to"); keep the small words that carry grammar ("the", "to", "that"), because a fragment stripped of them is ambiguous and translates badly. Front-load the word the reader scans for.
|
|
19
|
+
9. **People are people.** Singular *they* for anyone whose pronouns are unknown; no disability idioms; no blame ("You entered an invalid date" → "Enter a date after today"); no hype, no exclamation in failure, no condescension.
|
|
20
|
+
10. **Readable without the screen.** Copy never depends on position or colour ("the button on the right", "the red items"); link text names its destination; a label stays visible — a placeholder is never the label.
|
|
21
|
+
|
|
22
|
+
## Elements
|
|
23
|
+
|
|
24
|
+
Each element has one grammatical form (principle 3). Sentence case everywhere — page titles, navigation, buttons and headings included — because one case scheme cannot drift and reads calmer in a dense interface; proper nouns and product names keep their own casing.
|
|
25
|
+
|
|
26
|
+
| Element | Form | Rules | ❌ → ✅ |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| Page title | Noun phrase | Names the place or the record; matches its navigation entry word for word | "Manage your jobs here" → "Jobs" |
|
|
29
|
+
| Section heading | Noun phrase | Names the contents; a question only when the section answers one the user asked | "Here's what needs you" → "Your queue" |
|
|
30
|
+
| Navigation item, tab | Noun | The place, not an action; plural for a collection; never "My …" beside "Your …" | "View reports" → "Reports" |
|
|
31
|
+
| Table column header | Noun phrase, 1–3 words | Units live in the header, never in every cell; no "#" or "No." for counts | "How long in stage (days)" → "Days in stage" |
|
|
32
|
+
| Stat card | Label + numeral + optional caption + optional action | The **label** names what is counted, scope and threshold included; the **value** is a numeral, and zero is `0`; the **caption** adds one fact the number cannot carry (the oldest item's age, a trend, a target) and never restates the value in words; the **action** is a verb and its destination | "0 · Screenings to review · Nothing waiting" → "Awaiting screening · 0"; "Waiting too long · In one stage 13 days or more" → "Stalled 14+ days · 3 · oldest 21 days" |
|
|
33
|
+
| Button, menu action | Verb + object | The specific verb ("Publish job", never "Submit" or "OK"); the confirm button repeats the trigger's verb; no end punctuation; an ellipsis only when the action opens a further step that asks for input | "Submit" → "Send offer"; "Yes" → "Delete 3 candidates" |
|
|
34
|
+
| Link | The destination or the action | Never "click here", never a bare "Learn more" without its object; the article stays outside the link | "Click here for the audit log" → "Open the audit log" |
|
|
35
|
+
| Form label | Noun phrase | Always visible; mark whichever of required/optional is the minority, the same way on every form | "Please enter your email" → "Email" |
|
|
36
|
+
| Help text | One sentence | Below the field; states format, limit or consequence — never repeats the label | "Your password" → "At least 12 characters" |
|
|
37
|
+
| Placeholder | An example value, or nothing | Never instructions, never the label | "Enter email here" → "name@company.com" |
|
|
38
|
+
| Inline validation | Instruction | At the field; says what to enter, not what was wrong | "Invalid email" → "Enter an email like name@company.com" |
|
|
39
|
+
| Error (banner, toast, page) | Title + sentence | Title: "Couldn't {verb} {object}"; body: the reason in the user's terms, then the next step; codes and stack detail only behind a details/copy affordance for support | "Error 500: INTERNAL" → "Couldn't save the job. Retry in a moment — your changes are still here." |
|
|
40
|
+
| Permission refusal | Title + sentence | Says what the person can't do and who can; never a lecture, never "Access denied" alone | "403 Forbidden" → "Only admins can change integrations. Ask an admin for access." |
|
|
41
|
+
| Empty state | Heading + one sentence + at most one action | Distinguish the three causes, each with its own copy: **first use** (what will appear and how to start), **filtered to nothing** (say so and offer to clear filters), **failed to load** (that is an error, not emptiness) | "No data" → "No candidates yet" / "Candidates appear here when someone applies or you add one." / [Add candidate] |
|
|
42
|
+
| Loading | Noun phrase, or nothing | Silent under a second; past that, name what is loading; never "Please wait" | "Please wait…" → "Loading candidates…" |
|
|
43
|
+
| Success toast | Past-tense statement | Names the object and the outcome; offers Undo where the action is reversible; no "successfully", no exclamation | "Job was successfully published!" → "Job published" |
|
|
44
|
+
| Confirmation dialog | Question title + consequence + verb buttons | Title names the action and its object; body states what is lost and whether it can be undone; buttons are the verb and "Cancel"; never "Are you sure?" | "Are you sure?" [Yes] [No] → "Delete 3 candidates?" / "Their applications and notes are deleted too. This can't be undone." / [Delete candidates] [Cancel] |
|
|
45
|
+
| Tooltip | One sentence or noun phrase | Supplementary only — nothing a person needs is hidden in it; describes what the control does | "Click to toggle" → "Collapse the sidebar" |
|
|
46
|
+
| Status chip, badge | 1–2 words | Adjective or past participle from the glossary's status vocabulary, identical wherever the status appears | "In Progress", "in-progress", "Ongoing" → "In progress" |
|
|
47
|
+
| Count and pagination | Numeral + noun | "12 candidates", "1–25 of 340"; singular and plural both handled | "Showing results: 12" → "12 candidates" |
|
|
48
|
+
| Notification, email from the product | Subject names the event | Who did what to which object; the body links straight to it | "Update" → "Priya submitted feedback on Ana Silva" |
|
|
49
|
+
|
|
50
|
+
## Mechanics
|
|
51
|
+
|
|
52
|
+
| Matter | Rule |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| Person | Sentences may address the user as "you". Labels contain no pronouns. The product refers to itself rarely; "we" only when a human team acts (support, review). A system failure is phrased as the event ("Couldn't send the invite"), never as "We encountered an error". |
|
|
55
|
+
| Contractions | In sentences, yes ("can't", "you'll") — they read human. Never in labels or buttons. |
|
|
56
|
+
| Numbers | Numerals always, 1–9 included. Thousands separators. Abbreviate (`1.2k`) only where space forces it, and never in a value someone acts on. Percent as `%`. Ranges with an en dash (`3–5 days`). Currency per locale; a code (`USD`) wherever more than one currency can appear. |
|
|
57
|
+
| Dates and times | Relative for the recent past ("5 min ago", "Yesterday"), absolute beyond a week ("12 Oct", the year added only when it differs from the current one). A time zone wherever two people could read the same time differently. The package's formatting foundations decide the exact shapes. |
|
|
58
|
+
| Punctuation | No end punctuation on labels, buttons, headings, chips or single-fragment tooltips; full sentences end with a period. Exclamation points never in errors or warnings and at most one, rarely, in success. Em dash: one per message at most, never as a joint between clauses. Oxford comma. Curly quotes. No ampersand unless it is part of a name. |
|
|
59
|
+
| Abbreviations | Spell out on first use unless universal to the audience (URL, PDF, ID, CSV). Internal acronyms and code names never appear. |
|
|
60
|
+
| Truncation | Truncate text at the end with the full value on hover; never truncate a number, a date or the distinguishing end of an identifier. |
|
|
61
|
+
| Inclusion | Singular *they*; neutral role nouns; age, disability and health only when relevant, and then person-first unless the person prefers otherwise; no idioms built on disability ("blind spot", "falls on deaf ears"). |
|
|
62
|
+
| Translation-ready | Subject–verb–object sentences, active voice; no idioms, slang or puns; repeat the noun rather than lean on an ambiguous "it"; no strings assembled from fragments, because word order differs by language; leave room for 30% longer text. |
|
|
63
|
+
|
|
64
|
+
### Word choices
|
|
65
|
+
|
|
66
|
+
Pick one of each pair for the whole product and never mix them.
|
|
67
|
+
|
|
68
|
+
| Use | Not | Because |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| Sign in / sign out (verb), sign-in (noun) | log in, login, log on | One pair across every surface |
|
|
71
|
+
| Select, choose | click, tap | Device-neutral |
|
|
72
|
+
| Create (a new record) | add, make, new | *Add* is for attaching something that already exists |
|
|
73
|
+
| Add (attach existing) | create, assign | Keeps *create* meaning "new record" |
|
|
74
|
+
| Delete (destroys) | remove | *Remove* detaches and leaves the record; the two must never be swapped |
|
|
75
|
+
| Remove (detaches) | delete | As above |
|
|
76
|
+
| Archive (hides, reversible) | delete | Tells the person it can come back |
|
|
77
|
+
| Cancel (abandons an action) | close, dismiss | *Close* only dismisses something with nothing to lose |
|
|
78
|
+
| Save (keeps changes) | submit, apply | *Send*, *Publish*, *Invite* when the action reaches someone else |
|
|
79
|
+
| Set up (verb), setup (noun) | — | Verb and noun differ |
|
|
80
|
+
| Email | e-mail, E-mail | — |
|
|
81
|
+
| Can't, couldn't | unable to, failed to | Plain, human, shorter |
|
|
82
|
+
|
|
83
|
+
## Tone map
|
|
84
|
+
|
|
85
|
+
Voice holds; tone moves with the reader's state (principle 6). The voice pack's own tone map refines these defaults for its register.
|
|
86
|
+
|
|
87
|
+
| Situation | Reader's state | Tone | Pattern |
|
|
88
|
+
| --- | --- | --- | --- |
|
|
89
|
+
| Routine labels and actions | Focused, scanning | Neutral, brisk | Noun phrases and verbs; nothing extra |
|
|
90
|
+
| First use, empty | Orienting | Encouraging, factual | What appears here and the one way to start |
|
|
91
|
+
| Success | Satisfied, moving on | Brief | Past tense, object named, Undo if reversible |
|
|
92
|
+
| Error the person can fix | Mildly frustrated | Calm, specific | What to enter or change, at the place it applies |
|
|
93
|
+
| Failure that isn't theirs | Frustrated, blocked | Accountable, steady | What failed, that their work is safe if it is, what to do (retry, wait), no internals |
|
|
94
|
+
| Destructive confirmation | Cautious | Plain, explicit | The object, the loss, whether it can be undone — the plainness is the safeguard |
|
|
95
|
+
| Warning before a consequence | Attentive | Direct | The consequence first, then the choice |
|
|
96
|
+
| Permission refusal | Blocked, possibly annoyed | Respectful | What they can't do, who can, how to ask |
|
|
97
|
+
| Long wait | Uncertain | Reassuring | What is happening and, if known, how long |
|
|
98
|
+
| Milestone | Pleased | Warm, never hyped | One sentence of acknowledgement, no fanfare |
|
|
99
|
+
|
|
100
|
+
## The copy pass on an existing app
|
|
101
|
+
|
|
102
|
+
When the ask is to fix an app's wording, run this as the improve step's content scope (`existing-apps.md`). An explicit ask to correct the copy lifts the never-silently-change protection from navigation labels; legal copy stays protected unless the ask names it.
|
|
103
|
+
|
|
104
|
+
1. **Inventory by surface, rendered.** Read each surface's strings in the source and drive the surface, so conditional strings (empty, error, refused, loading) are seen as well as the happy path.
|
|
105
|
+
2. **Fix the glossary first.** List the domain nouns, the status vocabulary and the verbs the app uses; choose one word per concept (principle 4) and record the list in `product.md` under its vocabulary, where every later string is checked against it.
|
|
106
|
+
3. **Rewrite by element.** Take each string's element from § Elements and apply its form and rules; the server messages that reach the interface are in scope, because a person reads them.
|
|
107
|
+
4. **Keep the contract honest.** A test that asserts a string is updated with it — the copy is the promise it checks, so a changed string is an intended behaviour change, never a weakened test. A feature document that quotes promised wording is updated in the same change.
|
|
108
|
+
5. **Sweep for the tells** below before calling the pass done.
|
|
109
|
+
|
|
110
|
+
### Copy tells
|
|
111
|
+
|
|
112
|
+
Each is a near-certain defect; fix it or record why it stays.
|
|
113
|
+
|
|
114
|
+
| Tell | Principle |
|
|
115
|
+
| --- | --- |
|
|
116
|
+
| "Successfully", "Please", "Oops", "Uh oh", "Whoops" | 8, 1 |
|
|
117
|
+
| "Are you sure?", "Click here", a bare "Learn more", "Submit", "OK" as a confirm button | 3, 10 |
|
|
118
|
+
| "Invalid …", "Error:" as a prefix, an error code or an exception name inside a sentence | 2, 7 |
|
|
119
|
+
| An exclamation point in an error or a warning | 6 |
|
|
120
|
+
| Title Case On A Button Or Heading; a period on a label or button | Elements |
|
|
121
|
+
| "Currently", "for now", "new", "now supports", "has been moved" | 5 |
|
|
122
|
+
| A service, table, route, environment variable or library named in user-facing copy | 2 |
|
|
123
|
+
| Two words for one concept across surfaces, or one status spelled two ways | 4 |
|
|
124
|
+
| A stat caption that restates its value in words ("0 · Nothing waiting") | Elements |
|
|
125
|
+
| A placeholder doing a label's job; help text repeating its label | 10 |
|
|
126
|
+
| A sentence assembled from fragments joined at runtime | Mechanics |
|