@nurix/etna 0.19.33 → 0.19.35
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/harness-index.json +5 -1
- package/data/harnesses/code/CLAUDE.md +21 -11
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/rules/general.md +1 -0
- package/data/harnesses/code/rules/testing.md +1 -1
- package/data/harnesses/code/rules/verification.md +51 -0
- package/data/harnesses/code/skills/test-plan/SKILL.md +3 -3
- package/data/harnesses/delivery/.prettierignore +29 -0
- package/data/harnesses/delivery/.prettierrc.json +3 -0
- package/data/harnesses/delivery/.vscode/settings.json +19 -0
- package/data/harnesses/delivery/CLAUDE.md +123 -0
- package/data/harnesses/delivery/agents/brainstorm.md +144 -0
- package/data/harnesses/delivery/agents/data-generator.md +23 -0
- package/data/harnesses/delivery/agents/eval-runner.md +23 -0
- package/data/harnesses/delivery/agents/judge.md +23 -0
- package/data/harnesses/delivery/agents/lld-mode.md +56 -0
- package/data/harnesses/delivery/agents/maintenance.md +229 -0
- package/data/harnesses/delivery/agents/prompt-iterator.md +23 -0
- package/data/harnesses/delivery/agents/red-team.md +23 -0
- package/data/harnesses/delivery/agents/regression-runner.md +28 -0
- package/data/harnesses/delivery/agents/retro.md +46 -0
- package/data/harnesses/delivery/codex/agents/brainstorm.toml +142 -0
- package/data/harnesses/delivery/codex/agents/data-generator.toml +22 -0
- package/data/harnesses/delivery/codex/agents/eval-runner.toml +22 -0
- package/data/harnesses/delivery/codex/agents/judge.toml +22 -0
- package/data/harnesses/delivery/codex/agents/lld-mode.toml +52 -0
- package/data/harnesses/delivery/codex/agents/maintenance.toml +228 -0
- package/data/harnesses/delivery/codex/agents/prompt-iterator.toml +22 -0
- package/data/harnesses/delivery/codex/agents/red-team.toml +22 -0
- package/data/harnesses/delivery/codex/agents/regression-runner.toml +27 -0
- package/data/harnesses/delivery/codex/agents/retro.toml +45 -0
- package/data/harnesses/delivery/harness.json +11 -0
- package/data/harnesses/delivery/hooks/generate-ownership-index.mjs +148 -0
- package/data/harnesses/delivery/hooks/hooks.json +16 -0
- package/data/harnesses/delivery/rules/changelog.md +19 -0
- package/data/harnesses/delivery/rules/evals.md +23 -0
- package/data/harnesses/delivery/rules/model-tiers.md +18 -0
- package/data/harnesses/delivery/rules/nomenclature.md +34 -0
- package/data/harnesses/delivery/rules/prompting.md +23 -0
- package/data/harnesses/delivery/skills/brainstorm/README.md +56 -0
- package/data/harnesses/delivery/skills/brainstorm/SKILL.md +173 -0
- package/data/harnesses/delivery/skills/brainstorm/references/doctrine.md +98 -0
- package/data/harnesses/delivery/skills/brainstorm/references/harvest.md +86 -0
- package/data/harnesses/delivery/skills/brainstorm/references/session-schema.md +186 -0
- package/data/harnesses/delivery/skills/brainstorm/scripts/detector.mjs +460 -0
- package/data/harnesses/delivery/skills/cost-report/SKILL.md +24 -0
- package/data/harnesses/delivery/skills/documentation/SKILL.md +129 -0
- package/data/harnesses/delivery/skills/documentation/references/examples.md +279 -0
- package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +44 -0
- package/data/harnesses/delivery/skills/documentation/references/style-guide.md +340 -0
- package/data/harnesses/delivery/skills/documentation/references/untemplated.md +38 -0
- package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +140 -0
- package/data/harnesses/delivery/skills/documentation/templates/Readme.md +31 -0
- package/data/harnesses/delivery/skills/documentation/templates/api-reference.md +20 -0
- package/data/harnesses/delivery/skills/documentation/templates/architecture-decision.md +121 -0
- package/data/harnesses/delivery/skills/documentation/templates/backlog.md +33 -0
- package/data/harnesses/delivery/skills/documentation/templates/changelog-entry.md +57 -0
- package/data/harnesses/delivery/skills/documentation/templates/changelog-index.md +41 -0
- package/data/harnesses/delivery/skills/documentation/templates/docs-readme.md +72 -0
- package/data/harnesses/delivery/skills/documentation/templates/domain-model.md +30 -0
- package/data/harnesses/delivery/skills/documentation/templates/environment-registry.md +15 -0
- package/data/harnesses/delivery/skills/documentation/templates/feature.md +149 -0
- package/data/harnesses/delivery/skills/documentation/templates/glossary.md +11 -0
- package/data/harnesses/delivery/skills/documentation/templates/memory-main.md +25 -0
- package/data/harnesses/delivery/skills/documentation/templates/migration-runbook.md +34 -0
- package/data/harnesses/delivery/skills/documentation/templates/non-goals.md +11 -0
- package/data/harnesses/delivery/skills/documentation/templates/operations-procedure.md +36 -0
- package/data/harnesses/delivery/skills/documentation/templates/plan.md +64 -0
- package/data/harnesses/delivery/skills/documentation/templates/protected-files.md +37 -0
- package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +104 -0
- package/data/harnesses/delivery/skills/documentation/templates/security-overview.md +27 -0
- package/data/harnesses/delivery/skills/documentation/templates/structure.md +65 -0
- package/data/harnesses/delivery/skills/documentation/templates/system-overview.md +32 -0
- package/data/harnesses/delivery/skills/documentation/templates/testing-strategy.md +29 -0
- package/data/harnesses/delivery/skills/escalate/SKILL.md +25 -0
- package/data/harnesses/delivery/skills/prompt-eval/SKILL.md +22 -0
- package/data/harnesses/delivery/skills/prompt-library/SKILL.md +36 -0
- package/data/harnesses/delivery/skills/route/SKILL.md +21 -0
- package/data/harnesses/etna/CLAUDE.md +1 -1
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/rules/general.md +1 -0
- package/data/harnesses/etna/rules/testing.md +1 -1
- package/data/harnesses/hr/harness.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,279 @@
|
|
|
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
|
|
25
|
+
|
|
26
|
+
**Input:**
|
|
27
|
+
|
|
28
|
+
- `serverData` (array) - Fresh from API
|
|
29
|
+
- `localData` (array) - Current state
|
|
30
|
+
- `changes` (object) - `{ added, updated, removed }`
|
|
31
|
+
|
|
32
|
+
**Output:** `{ merged: array, conflicts: array }`
|
|
33
|
+
|
|
34
|
+
**Merge Rules:**
|
|
35
|
+
|
|
36
|
+
- Server wins for conflicts
|
|
37
|
+
- Local additions preserved
|
|
38
|
+
- Local removals marked as intent
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Example 2: State Documentation
|
|
44
|
+
|
|
45
|
+
### ❌ Bad: State Everywhere
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
## Component State
|
|
49
|
+
|
|
50
|
+
const [items, setItems] = useState([]);
|
|
51
|
+
|
|
52
|
+
## Hook State
|
|
53
|
+
|
|
54
|
+
{ data: items, isLoading: loading, error: null }
|
|
55
|
+
|
|
56
|
+
## Redux State
|
|
57
|
+
|
|
58
|
+
{ items: [], loading: false, error: null }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Problems:** Documents transient state, repeats shapes.
|
|
62
|
+
|
|
63
|
+
### ✅ Good: Persistence Points Only
|
|
64
|
+
|
|
65
|
+
```markdown
|
|
66
|
+
## State
|
|
67
|
+
|
|
68
|
+
**Frontend (at persistence):**
|
|
69
|
+
|
|
70
|
+
{
|
|
71
|
+
"data": [],
|
|
72
|
+
"changes": { "added": [], "updated": [], "removed": [] }
|
|
73
|
+
// "cache": {} // UNUSED: dead key; kept so old persisted state rehydrates
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
**Storage:** localStorage `app_state`
|
|
77
|
+
|
|
78
|
+
**Backend:**
|
|
79
|
+
|
|
80
|
+
export const items = pgTable('items', {
|
|
81
|
+
id: text('id').primaryKey(),
|
|
82
|
+
data: jsonb('data'),
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Example 3: Changelog
|
|
89
|
+
|
|
90
|
+
### ❌ Bad: Vague
|
|
91
|
+
|
|
92
|
+
```markdown
|
|
93
|
+
# 2025-01-05 - Updates
|
|
94
|
+
|
|
95
|
+
## Changes
|
|
96
|
+
|
|
97
|
+
- Updated editor
|
|
98
|
+
- Fixed bugs
|
|
99
|
+
- Improved performance
|
|
100
|
+
|
|
101
|
+
## Files
|
|
102
|
+
|
|
103
|
+
- Various files in src/
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### ✅ Good: Function-Level Detail
|
|
107
|
+
|
|
108
|
+
```markdown
|
|
109
|
+
# 2025-01-05 - Version-Based Merge
|
|
110
|
+
|
|
111
|
+
## Summary
|
|
112
|
+
|
|
113
|
+
Replaced change-tracking merge with version-based conflict resolution.
|
|
114
|
+
|
|
115
|
+
## Changes
|
|
116
|
+
|
|
117
|
+
### Added
|
|
118
|
+
|
|
119
|
+
- `mergeAndDerive(server, local, versionsMatch, type)` in `src/utils/merge.js`
|
|
120
|
+
- Purpose: Single-pass merge with change detection
|
|
121
|
+
- Returns: `{ merged, changes }`
|
|
122
|
+
|
|
123
|
+
### Changed
|
|
124
|
+
|
|
125
|
+
- `useDataSync()` in `src/hooks/useDataSync.js`
|
|
126
|
+
- Changed: Now compares versions before merge
|
|
127
|
+
|
|
128
|
+
### Removed
|
|
129
|
+
|
|
130
|
+
- `deriveChanges()` from `src/utils/derive.js`
|
|
131
|
+
- Replaced by: Logic in `mergeAndDerive()`
|
|
132
|
+
|
|
133
|
+
## Breaking Changes
|
|
134
|
+
|
|
135
|
+
⚠️ **Merge behavior changed**
|
|
136
|
+
|
|
137
|
+
- Old: Local changes always preserved
|
|
138
|
+
- New: Local preserved only if versions match
|
|
139
|
+
|
|
140
|
+
## Files Changed
|
|
141
|
+
|
|
142
|
+
- `src/hooks/useDataSync.js`
|
|
143
|
+
- `src/utils/merge.js`
|
|
144
|
+
- `src/utils/derive.js` (deleted)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Example 4: Data Flow
|
|
150
|
+
|
|
151
|
+
### ❌ Bad: Prose Description
|
|
152
|
+
|
|
153
|
+
```markdown
|
|
154
|
+
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...
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### ✅ Good: Diagram + Key Points
|
|
158
|
+
|
|
159
|
+
```markdown
|
|
160
|
+
## Data Flow
|
|
161
|
+
|
|
162
|
+
┌─────────────────────────────────────────┐
|
|
163
|
+
│ DATA SYNC │
|
|
164
|
+
├─────────────────────────────────────────┤
|
|
165
|
+
│ │
|
|
166
|
+
│ ┌──────┐ ┌──────┐ ┌──────┐ │
|
|
167
|
+
│ │Server│────▶│Merge │────▶│Redux │ │
|
|
168
|
+
│ │ API │ │ │ │Store │ │
|
|
169
|
+
│ └──────┘ └──────┘ └──────┘ │
|
|
170
|
+
│ │ │
|
|
171
|
+
│ ▼ │
|
|
172
|
+
│ Version Check │
|
|
173
|
+
│ │
|
|
174
|
+
└─────────────────────────────────────────┘
|
|
175
|
+
|
|
176
|
+
**Trigger:** `useAppInit()` on page load
|
|
177
|
+
|
|
178
|
+
**Version Rule:** Match → local wins, Mismatch → server wins
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Example 5: Architecture Decision revision
|
|
184
|
+
|
|
185
|
+
### ❌ Bad: Supersession chain
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
docs/architecture/decisions/
|
|
189
|
+
├── AD-002-auth-keycloak.md (status: Superseded)
|
|
190
|
+
├── AD-006-auth-better-auth.md (status: Superseded, "supersedes AD-002")
|
|
191
|
+
└── AD-011-auth-better-auth-v2.md (status: Accepted, "supersedes AD-006")
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Problems:** Three files hold one subject; the reader must diff a chain to learn the current truth; two of the three are wrong-but-present (the same pathology as keeping `report_v1.sql` beside the live `report_v2.sql`); the reasoning that killed Keycloak is stranded in a dead file nobody opens.
|
|
195
|
+
|
|
196
|
+
### ✅ Good: One subject, updated in place
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
docs/architecture/decisions/
|
|
200
|
+
└── AD-002-auth.md (status: Accepted, last-updated bumped)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
```markdown
|
|
204
|
+
## Decision
|
|
205
|
+
|
|
206
|
+
We use Better Auth with one-shot credential issuance… ← current truth, no journey
|
|
207
|
+
|
|
208
|
+
…
|
|
209
|
+
|
|
210
|
+
## Decision Changelog
|
|
211
|
+
|
|
212
|
+
- 2026-05-02 — Moved issuance to one-shot tokens because refresh-token theft
|
|
213
|
+
surfaced in review. Implemented by [plan](…). (Previously: long-lived refresh tokens.)
|
|
214
|
+
- 2026-03-18 — Replaced Keycloak with Better Auth because self-hosting cost
|
|
215
|
+
outweighed SSO needs. Implemented by [plan](…). (Previously: Keycloak.)
|
|
216
|
+
- 2026-01-10 — Initial decision accepted. Implemented by [plan](…).
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Why it works:** The body answers "how does auth work and why" without archaeology; the tail preserves every reversal with its trigger; the rejected alternatives stay findable in the one file a reader actually opens.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Example 6: Stripping history from a truth doc
|
|
224
|
+
|
|
225
|
+
The move agents fumble: deleting narration is only half the job — the story must land in a record.
|
|
226
|
+
|
|
227
|
+
### ❌ Bad: The journey narrated in place
|
|
228
|
+
|
|
229
|
+
```markdown
|
|
230
|
+
## Export Pipeline
|
|
231
|
+
|
|
232
|
+
The exporter was extracted from the legacy `reports` worker (2026-06-02) and
|
|
233
|
+
now lives in `src/export/`. Phases 0–2 of the rewrite are complete; streaming
|
|
234
|
+
output is not yet implemented. Treat any reference to `reports/export.js` as
|
|
235
|
+
stale — it was superseded by `src/export/run.js`.
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### ✅ Good: Present-tense truth doc + a dated record carrying the story
|
|
239
|
+
|
|
240
|
+
The feature doc states only what is:
|
|
241
|
+
|
|
242
|
+
```markdown
|
|
243
|
+
## Export Pipeline
|
|
244
|
+
|
|
245
|
+
`src/export/run.js` renders every export format from one job queue. Output is
|
|
246
|
+
buffered per job (streaming is out of scope — see `docs/history/backlog.md`).
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
And the change-story goes to `docs/history/changelog/2026-06-02-export-extraction.md`:
|
|
250
|
+
|
|
251
|
+
```markdown
|
|
252
|
+
# 2026-06-02 — Export pipeline extracted
|
|
253
|
+
|
|
254
|
+
## Summary
|
|
255
|
+
|
|
256
|
+
Extracted export logic from the `reports` worker into `src/export/`.
|
|
257
|
+
|
|
258
|
+
## Changes
|
|
259
|
+
|
|
260
|
+
### Removed
|
|
261
|
+
|
|
262
|
+
- `reports/export.js` — replaced by `src/export/run.js`; all callers repointed.
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Why it works:** the truth doc needs no archaeology to act on; the dates, the predecessor, and the supersession live in a frozen record; the unbuilt part is a backlog pointer, not a "not yet" hedge; and no stale-reference tripwire survives because the references themselves were fixed.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Quick Comparison
|
|
270
|
+
|
|
271
|
+
| Aspect | Bad | Good |
|
|
272
|
+
| ---------- | -------------------- | --------------------------- |
|
|
273
|
+
| Code | Full implementations | Signatures + contracts |
|
|
274
|
+
| State | Every occurrence | Persistence points only |
|
|
275
|
+
| Flows | Prose paragraphs | ASCII diagrams |
|
|
276
|
+
| Changelogs | "Updated X" | Function names + migrations |
|
|
277
|
+
| Decisions | New doc per revision | One AD per subject, updated in place |
|
|
278
|
+
| History | Narrated in the doc | Present-tense doc + dated record |
|
|
279
|
+
| Length | 100+ lines | 20-40 lines |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Frontmatter Derivation — feature-doc ownership
|
|
2
|
+
|
|
3
|
+
Load when: creating a feature doc, updating one whose documented scope moved, or running a baseline/reconcile pass over many docs.
|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
## When to run
|
|
8
|
+
|
|
9
|
+
- **Baseline / reconcile** — for every feature doc whose code paths aren't yet declared in its `owns:` frontmatter (the `maintenance` agent (baseline mode) calls this)
|
|
10
|
+
- **New feature doc** — when creating a doc via the [Feature template](../templates/feature.md), project its `owns:` globs
|
|
11
|
+
- **Doc update** — when the documented scope changes, update the doc's `owns:` globs
|
|
12
|
+
|
|
13
|
+
## How to derive the frontmatter
|
|
14
|
+
|
|
15
|
+
A feature doc's ownership frontmatter is `owns:` (required), `module:` (optional), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body.
|
|
16
|
+
|
|
17
|
+
**1. `owns:`** (the path scope)
|
|
18
|
+
|
|
19
|
+
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.
|
|
20
|
+
|
|
21
|
+
| Doc references | Glob |
|
|
22
|
+
| ------------------------------------ | ------------------------- |
|
|
23
|
+
| Multiple files under one directory | `src/feature/**` |
|
|
24
|
+
| Specific files in a shared directory | List each file explicitly |
|
|
25
|
+
| A single entry-point file | The exact file path |
|
|
26
|
+
|
|
27
|
+
Glob each pattern against the codebase. At `status: active`, drop any that match nothing; at `status: draft`, projected globs may match nothing yet — confirm them against real code when the doc flips to `active`.
|
|
28
|
+
|
|
29
|
+
**2. `module:`**
|
|
30
|
+
|
|
31
|
+
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).
|
|
32
|
+
|
|
33
|
+
**3. `keywords:` & `status:`**
|
|
34
|
+
|
|
35
|
+
`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.
|
|
36
|
+
|
|
37
|
+
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.
|
|
38
|
+
|
|
39
|
+
## Rules
|
|
40
|
+
|
|
41
|
+
- 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.
|
|
42
|
+
- Use glob patterns for directories, explicit paths for individual files. At `active`, never list paths that don't exist in the codebase; a `draft`'s projected paths are confirmed at `active`.
|
|
43
|
+
- 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.
|
|
44
|
+
- For baseline/reconcile with many docs, use parallel sub-agents to read source and propose `owns:` globs.
|
|
@@ -0,0 +1,340 @@
|
|
|
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
|
|
15
|
+
|
|
16
|
+
**Input:**
|
|
17
|
+
|
|
18
|
+
- `param1` (type) - Description
|
|
19
|
+
- `param2` (type, optional) - Description
|
|
20
|
+
|
|
21
|
+
**Output:** `{ field1, field2 }`
|
|
22
|
+
|
|
23
|
+
**Side Effects:** State updates, API calls, etc.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Parameter Rules
|
|
27
|
+
|
|
28
|
+
- Name + type + one-line purpose
|
|
29
|
+
- Mark optional params with `(type, optional)`
|
|
30
|
+
- Nest object properties:
|
|
31
|
+
```markdown
|
|
32
|
+
- `options` (object) - Configuration
|
|
33
|
+
- `options.retry` (boolean) - Enable retries
|
|
34
|
+
- `options.timeout` (number) - Timeout in ms
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Return Values
|
|
38
|
+
|
|
39
|
+
Always specify:
|
|
40
|
+
|
|
41
|
+
- Type: `Array<Object>`, `boolean`, `{ merged, changes }`
|
|
42
|
+
- Shape for objects/arrays
|
|
43
|
+
- Meaning: "True if sync successful"
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## State Documentation
|
|
48
|
+
|
|
49
|
+
### When to Document State
|
|
50
|
+
|
|
51
|
+
✅ Do:
|
|
52
|
+
|
|
53
|
+
- Redux persistence (localStorage, IndexedDB)
|
|
54
|
+
- Database schemas
|
|
55
|
+
- API request/response shapes
|
|
56
|
+
|
|
57
|
+
❌ Don't:
|
|
58
|
+
|
|
59
|
+
- Component-level state
|
|
60
|
+
- Derived/computed state
|
|
61
|
+
- Temporary UI state
|
|
62
|
+
|
|
63
|
+
### Format
|
|
64
|
+
|
|
65
|
+
````markdown
|
|
66
|
+
**Frontend (at persistence):**
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"activeField": "value"
|
|
71
|
+
// "deprecated": null // UNUSED: dead key; kept so old persisted state rehydrates
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Storage:** localStorage key `state_key`
|
|
76
|
+
|
|
77
|
+
**Backend:**
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
export const table = pgTable('table', {
|
|
81
|
+
id: text('id').primaryKey(),
|
|
82
|
+
data: jsonb('data'),
|
|
83
|
+
// old: text('old'), // UNUSED: dead column; nothing reads it
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
````
|
|
87
|
+
|
|
88
|
+
### Mark Unused Keys
|
|
89
|
+
|
|
90
|
+
Always comment deprecated/unused fields. The annotation states why the field is dead _now_ — never where it went, what replaced it, or when it will be removed (no "Remove in v3", no "Migrated to newField"; that is history narration, § The Two Natures below):
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"active": [],
|
|
95
|
+
// "legacy": {} // UNUSED: dead key; kept for rehydrate compatibility
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## ASCII Diagrams
|
|
102
|
+
|
|
103
|
+
### When to Use
|
|
104
|
+
|
|
105
|
+
- Data flows
|
|
106
|
+
- System architecture
|
|
107
|
+
- Component interactions
|
|
108
|
+
- Process flows
|
|
109
|
+
|
|
110
|
+
**Docs only.** Diagrams belong in documents read on demand (feature docs, ADs, operations). Instruction files — `CLAUDE.md`, rules, agent definitions, `SKILL.md` prose — never carry them: they load on every turn or every invocation, and a table or a sentence carries the same information at a fraction of the tokens.
|
|
111
|
+
|
|
112
|
+
### Pattern
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
┌─────────────────────────────────────────┐
|
|
116
|
+
│ TITLE │
|
|
117
|
+
├─────────────────────────────────────────┤
|
|
118
|
+
│ │
|
|
119
|
+
│ ┌──────┐ ┌──────┐ ┌──────┐ │
|
|
120
|
+
│ │ A │────▶│ B │────▶│ C │ │
|
|
121
|
+
│ └──────┘ └──────┘ └──────┘ │
|
|
122
|
+
│ │ │ │
|
|
123
|
+
│ ▼ ▼ │
|
|
124
|
+
│ Detail Detail │
|
|
125
|
+
│ │
|
|
126
|
+
└─────────────────────────────────────────┘
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Characters
|
|
130
|
+
|
|
131
|
+
- Boxes: `┌─┐│└┘├┤┬┴┼`
|
|
132
|
+
- Arrows: `───▶` `◀───` `│▼` `│▲`
|
|
133
|
+
- Width: ~70 chars max
|
|
134
|
+
|
|
135
|
+
### UI Wireframes
|
|
136
|
+
|
|
137
|
+
For screen layouts (not data flows), use these conventions:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
**Route:** `path/:id`
|
|
141
|
+
**Tab:** Tab Name
|
|
142
|
+
|
|
143
|
+
┌────────────────────────────────────┐
|
|
144
|
+
│ Title [i]3 [Button]│
|
|
145
|
+
│ [i]Label [Tag1][Tag2][+Add] │
|
|
146
|
+
└────────────────────────────────────┘
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
- `[text]` = clickable button/badge
|
|
150
|
+
- `[i]` = icon (followed by label or count)
|
|
151
|
+
- `v` / `^` = expand/collapse indicator
|
|
152
|
+
- Show each UI state (collapsed/expanded) as separate diagrams
|
|
153
|
+
- Include Route/Tab context above wireframe
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Code Examples
|
|
158
|
+
|
|
159
|
+
### Rules
|
|
160
|
+
|
|
161
|
+
- Under 15 lines
|
|
162
|
+
- Show contracts, not implementations
|
|
163
|
+
- Use pseudocode for algorithms
|
|
164
|
+
|
|
165
|
+
✅ Good:
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
// Critical: Balanced brace matching
|
|
169
|
+
function extract(json) {
|
|
170
|
+
// Track brace depth
|
|
171
|
+
// Ignore braces inside strings
|
|
172
|
+
// Return complete objects only
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
❌ Bad: Full 50-line implementation
|
|
177
|
+
|
|
178
|
+
(Worked example: [`examples.md`](examples.md) Example 1.)
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Writing Style
|
|
183
|
+
|
|
184
|
+
### Voice
|
|
185
|
+
|
|
186
|
+
Use imperative/active:
|
|
187
|
+
|
|
188
|
+
- ✅ "Fetches data from server"
|
|
189
|
+
- ✅ "Returns array of objects"
|
|
190
|
+
- ❌ "This function is used to fetch"
|
|
191
|
+
- ❌ "An array is returned"
|
|
192
|
+
|
|
193
|
+
### When Prose Adds Value
|
|
194
|
+
|
|
195
|
+
Prose is valuable for context that contracts can't capture:
|
|
196
|
+
|
|
197
|
+
| Use Prose For | Example |
|
|
198
|
+
| --- | --- |
|
|
199
|
+
| Section intros | "When the editor mounts, `useAppInit` is called with the `appId` from URL." |
|
|
200
|
+
| Non-obvious behavior | "The hook always fetches fresh data. There is no caching or version checking." |
|
|
201
|
+
| Design rationale | "Why parallel fetches? Each entity type is independent, reducing load time." |
|
|
202
|
+
| Edge cases | "If created then deleted before save, it's removed from `added[]` without adding to `removed[]`." |
|
|
203
|
+
| Limitations, stated as facts | "`useAppInit` is standalone — nothing in the mount path calls it." |
|
|
204
|
+
| Usage context | "Used to show 'Unsaved' badge, warn before navigation, enable save buttons." |
|
|
205
|
+
|
|
206
|
+
### When to Avoid Prose
|
|
207
|
+
|
|
208
|
+
- Describing WHAT code does (use signatures instead)
|
|
209
|
+
- Step-by-step flows (use diagrams instead)
|
|
210
|
+
- Structured comparisons (use tables instead)
|
|
211
|
+
|
|
212
|
+
### Conciseness
|
|
213
|
+
|
|
214
|
+
One line when possible:
|
|
215
|
+
|
|
216
|
+
- ✅ "Merge server data with local changes using version-based conflict resolution"
|
|
217
|
+
- ❌ "This function takes the data from the server and also takes the local data..."
|
|
218
|
+
|
|
219
|
+
### Tables
|
|
220
|
+
|
|
221
|
+
Use for structured info:
|
|
222
|
+
|
|
223
|
+
```markdown
|
|
224
|
+
| Parameter | Type | Description |
|
|
225
|
+
| --------- | ------ | -------------- |
|
|
226
|
+
| `data` | object | Fresh from API |
|
|
227
|
+
| `local` | object | Current state |
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## The Two Natures — Tense & History
|
|
233
|
+
|
|
234
|
+
Every document is a **truth document** (states current absolutes, updated in place) or a **record** (dated account of activity, frozen or append-only) — see `SKILL.md` § The Two Natures. The tense rules follow directly:
|
|
235
|
+
|
|
236
|
+
**Truth documents 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 journey — the dates, the migrations — lives **only** in records (`docs/history/`: changelog, plans, migrations). Three sanctioned exceptions: `docs/memory/` is the agent's own dated ledger; an AD's **Decision Changelog** tail carries that decision's dated revision history; and `docs/structure.md`'s **Health Log** tail carries the maintenance agent's tooling-stamped audit rows. In both tail bridges the body stays current-truth-only — head is truth, tail is provenance.
|
|
237
|
+
|
|
238
|
+
**Records are never edited to match the present.** A frozen plan stays wrong-in-hindsight; a changelog entry describes what shipped as it shipped. A scope change gets a new dated record that links back.
|
|
239
|
+
|
|
240
|
+
Strip this language from truth documents:
|
|
241
|
+
|
|
242
|
+
| ❌ Historical narration (belongs in a record) | ✅ Present-tense fact (belongs in the truth doc) |
|
|
243
|
+
| --- | --- |
|
|
244
|
+
| "Folded in from the `NuStack-X` repo (2026-06-12)." | "Vendor-connector catalogue; one subpath per vendor." |
|
|
245
|
+
| "Built 2026-06-14; shipped + verified 2026-06-13." | "`agentSessionWorkflow` runs an outer turn loop over `runAgentLoop`." |
|
|
246
|
+
| "The legacy worker was deleted in the 2026-06-14 fold." | "One worker interprets `WorkflowDefinition`." |
|
|
247
|
+
| "ex-`@nurix/mcp-runtime`, M9 Phase C; was X, now Y." | "MCP client runtime, wired into `agentTriggerWorkflow`." |
|
|
248
|
+
| "Build Sequence phases 0–4 are complete." | Nothing — progress lives in the plan/backlog record; the doc describes what exists |
|
|
249
|
+
| "There is no standalone `skills/components/` — treat any reference to it as stale." | Nothing — delete or repoint the stale references; state only the present design |
|
|
250
|
+
| "Read first: `docs/history/plans/2026-…-fold.md`" (routing) | "Read first: `docs/architecture/<current-truth-doc>.md`" |
|
|
251
|
+
|
|
252
|
+
Rules:
|
|
253
|
+
|
|
254
|
+
- **No dates and no progress narration in truth documents.** Nothing about _when_ something shipped, was verified, folded, or was removed — and no completion markers either: no "phases 0–4 are complete", no per-item `✅ shipped` / `⏳ pending`. Progress tracking is a **record's** job (the plan, the backlog); a truth document describes what exists, as if it had always been so.
|
|
255
|
+
- **No stale-reference tripwires.** Never write "X is gone — treat references to X as stale"; that is a redirect doc compressed into one sentence. Delete or repoint every stale reference instead (same rule as the **No redirect docs** rule in `SKILL.md` § The Two Natures) and state only the present fact.
|
|
256
|
+
- **No version or phase framing.** A bare `v1`/`v2` as a label, "Phase 1/2", "the old X", "supersedes the earlier" — there is one design; describe it without its predecessors. (A version naming an external present-tense fact stays: a schema literal like `design-tokens/v2`, a dependency pin like `@0.14.0`.)
|
|
257
|
+
- **Temporal hedges are progress markers in prose.** "currently", "not yet", "still", "for now" smuggle a ⏳ into a truth document — state the fact without the hedge ("the hook is standalone; nothing in the mount path calls it") and let the backlog record carry the intention.
|
|
258
|
+
- **A published artifact's own version surface is external fact.** Release notes and upgrade guides for a shipped package may use version framing (`v1 → v2`) — that is the artifact's public contract, not the doc narrating its own past. They live beside the artifact or under `docs/operations/`, never in `docs/features/` or `docs/architecture/`.
|
|
259
|
+
- **Cite the AD for the _why_, never the _when_.** `Provenance: AD-002` is good (it points to the decision rationale). "Decided in AD-002 and shipped 2026-06-13" is not.
|
|
260
|
+
- **Routing/index docs point only to truth documents as a topic's authority.** A row whose "read first" target for a topic is a historical plan or changelog is a redirect-for-history — repoint it to the current truth doc, or drop the row. (An index _of the records themselves_ — a History section listing `plans/`, `changelog/` — is sanctioned: that indexes records, it doesn't route a topic.)
|
|
261
|
+
- **When a doc changes because the system changed, the change-story goes in `docs/history/` (a changelog entry), and the truth document simply becomes correct in present tense.** Never leave the diff narrated in place.
|
|
262
|
+
- **A decision that moves is an edit, not a new document.** Rewrite the AD's affected sections to the new truth and append the revision to its Decision Changelog — never mint a parallel doc and never leave the old choice narrated in the body.
|
|
263
|
+
|
|
264
|
+
Worked example of the strip-and-relocate move: [`examples.md`](examples.md) Example 6.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Mechanics
|
|
269
|
+
|
|
270
|
+
- Inline-code every identifier, filename, command, and config key.
|
|
271
|
+
- Bullet rules take the form "**bold assertion** — explanation."
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Structure
|
|
276
|
+
|
|
277
|
+
### Headers
|
|
278
|
+
|
|
279
|
+
```markdown
|
|
280
|
+
# Document Title (H1 - once)
|
|
281
|
+
|
|
282
|
+
## Major Section (H2)
|
|
283
|
+
|
|
284
|
+
### Subsection (H3)
|
|
285
|
+
|
|
286
|
+
#### Detail (H4 - sparingly)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Headings are retrieval keys.** Search and agents retrieve sections out of context, and a bare `## State` reads identically across every feature doc. In long docs, qualify generic headings with the feature name — `## State — invoice-pdf`, `### Merge rules — data sync` — so a section stands alone when retrieved. Short docs whose H1 disambiguates can keep bare headings.
|
|
290
|
+
|
|
291
|
+
### Standard Layout
|
|
292
|
+
|
|
293
|
+
```markdown
|
|
294
|
+
# [Title]
|
|
295
|
+
|
|
296
|
+
**Goal:** One-line purpose
|
|
297
|
+
|
|
298
|
+
## Architecture
|
|
299
|
+
|
|
300
|
+
[Diagram + explanation]
|
|
301
|
+
|
|
302
|
+
## Key Functions
|
|
303
|
+
|
|
304
|
+
[Signatures and contracts]
|
|
305
|
+
|
|
306
|
+
## State
|
|
307
|
+
|
|
308
|
+
[Persistence shapes]
|
|
309
|
+
|
|
310
|
+
## Files
|
|
311
|
+
|
|
312
|
+
[Source file list]
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### File References
|
|
316
|
+
|
|
317
|
+
Always end with:
|
|
318
|
+
|
|
319
|
+
```markdown
|
|
320
|
+
## Files
|
|
321
|
+
|
|
322
|
+
- `src/path/main.js` - Core logic
|
|
323
|
+
- `src/path/hooks.js` - React hooks
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Summary
|
|
329
|
+
|
|
330
|
+
| Aspect | Rule |
|
|
331
|
+
| ---------- | ------------------------------- |
|
|
332
|
+
| Functions | Always include signatures |
|
|
333
|
+
| Parameters | Type + purpose |
|
|
334
|
+
| Returns | Type + shape |
|
|
335
|
+
| State | Persistence points only |
|
|
336
|
+
| Diagrams | ASCII for all flows — docs only, never instruction files |
|
|
337
|
+
| Code | Under 15 lines, contracts only |
|
|
338
|
+
| Voice | Imperative/active |
|
|
339
|
+
| Mechanics | Inline-code identifiers; bold-assertion bullets |
|
|
340
|
+
| Length | Concise, one line when possible |
|