# Documentation Style Guide

Writing rules for clear, maintainable documentation.

---

## Function Documentation

### Signature Format

```markdown
### `functionName(param1, param2, options)`

**Goal:** One-line purpose

**Input:**

- `param1` (type) - Description
- `param2` (type, optional) - Description

**Output:** `{ field1, field2 }`

**Side Effects:** State updates, API calls, etc.
```

### Parameter Rules

- Name + type + one-line purpose
- Mark optional params with `(type, optional)`
- Nest object properties:
  ```markdown
  - `options` (object) - Configuration
    - `options.retry` (boolean) - Enable retries
    - `options.timeout` (number) - Timeout in ms
  ```

### Return Values

Always specify:

- Type: `Array<Object>`, `boolean`, `{ merged, changes }`
- Shape for objects/arrays
- Meaning: "True if sync successful"

---

## State Documentation

### When to Document State

✅ Do:

- Redux persistence (localStorage, IndexedDB)
- Database schemas
- API request/response shapes

❌ Don't:

- Component-level state
- Derived/computed state
- Temporary UI state

### Format

````markdown
**Frontend (at persistence):**

```json
{
  "activeField": "value"
  // "deprecated": null  // UNUSED: dead key; kept so old persisted state rehydrates
}
```

**Storage:** localStorage key `state_key`

**Backend:**

```ts
export const table = pgTable('table', {
  id: text('id').primaryKey(),
  data: jsonb('data'),
  // old: text('old'),  // UNUSED: dead column; nothing reads it
});
```
````

### Mark Unused Keys

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):

```json
{
  "active": [],
  // "legacy": {}  // UNUSED: dead key; kept for rehydrate compatibility
}
```

---

## ASCII Diagrams

### When to Use

- Data flows
- System architecture
- Component interactions
- Process flows

**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.

### Pattern

```
┌─────────────────────────────────────────┐
│              TITLE                       │
├─────────────────────────────────────────┤
│                                          │
│   ┌──────┐     ┌──────┐     ┌──────┐   │
│   │  A   │────▶│  B   │────▶│  C   │   │
│   └──────┘     └──────┘     └──────┘   │
│        │                          │     │
│        ▼                          ▼     │
│    Detail                     Detail    │
│                                          │
└─────────────────────────────────────────┘
```

### Characters

- Boxes: `┌─┐│└┘├┤┬┴┼`
- Arrows: `───▶` `◀───` `│▼` `│▲`
- Width: ~70 chars max

### UI Wireframes

For screen layouts (not data flows), use these conventions:

```
**Route:** `path/:id`
**Tab:** Tab Name

┌────────────────────────────────────┐
│ Title   [i]3                [Button]│
│ [i]Label   [Tag1][Tag2][+Add]       │
└────────────────────────────────────┘
```

- `[text]` = clickable button/badge
- `[i]` = icon (followed by label or count)
- `v` / `^` = expand/collapse indicator
- Show each UI state (collapsed/expanded) as separate diagrams
- Include Route/Tab context above wireframe

---

## Mermaid Diagrams

**Structure at rest is ASCII; behaviour over time is mermaid.** A file tree, an on-disk layout, a load-class split, a wireframe — draw with box characters, because the diagram *is* the thing's shape. A sequence of turns, a state machine, a branching flow — write mermaid, because a renderer tracks the arrows better than a reader tracks them across box art, and the source stays diffable when a step is inserted.

**Docs only**, on the same reasoning as ASCII: a diagram never enters an instruction file.

### When to Use

| Diagram | Use for |
| --- | --- |
| `sequenceDiagram` | Who calls whom in what order — a session turn, a hand-off between components |
| `stateDiagram-v2` | Modes with transitions — a workflow, a record's lifecycle |
| `flowchart` | A process with branches, gates, or fan-out |
| `timeline` | A dated lineage, in records only — never in a truth document |

### Rules

- **At most 7 participants and 15 interactions** per diagram. Past that, split it — an unreadable diagram is worse than the prose it replaced.
- **Labels under 8 words**, no trailing punctuation.
- **Declare a direction** on every flowchart (`flowchart TD` / `LR`) so the render is stable.
- **The diagram never carries a fact the prose omits.** It restates structure for a reader who scans; a reader who greps must still find everything in the text.
- **No styling directives** — no `style`, no `classDef`, no theme overrides. Rendering is the reader's; the source stays portable across GitHub, Obsidian, and a plain editor.

```
flowchart LR
  A[Plan approved] --> B{boundary}
  B -->|BLOCK| C[Re-plan]
  B -->|PASS| D[testing plan-gate]
  D --> E[Implement]
```

---

## Code Examples

### Rules

- Under 15 lines
- Show contracts, not implementations
- Use pseudocode for algorithms

✅ Good:

```javascript
// Critical: Balanced brace matching
function extract(json) {
  // Track brace depth
  // Ignore braces inside strings
  // Return complete objects only
}
```

❌ Bad: Full 50-line implementation

(Worked example: [`examples.md`](examples.md) Example 1.)

---

## Writing Style

### Voice

Use imperative/active:

- ✅ "Fetches data from server"
- ✅ "Returns array of objects"
- ❌ "This function is used to fetch"
- ❌ "An array is returned"

### When Prose Adds Value

Prose is valuable for context that contracts can't capture:

| Use Prose For | Example |
| --- | --- |
| Section intros | "When the editor mounts, `useAppInit` is called with the `appId` from URL." |
| Non-obvious behavior | "The hook always fetches fresh data. There is no caching or version checking." |
| Design rationale | "Why parallel fetches? Each entity type is independent, reducing load time." |
| Edge cases | "If created then deleted before save, it's removed from `added[]` without adding to `removed[]`." |
| Limitations, stated as facts | "`useAppInit` is standalone — nothing in the mount path calls it." |
| Usage context | "Used to show 'Unsaved' badge, warn before navigation, enable save buttons." |

### When to Avoid Prose

- Describing WHAT code does (use signatures instead)
- Step-by-step flows (use diagrams instead)
- Structured comparisons (use tables instead)

### Conciseness

One line when possible:

- ✅ "Merge server data with local changes using version-based conflict resolution"
- ❌ "This function takes the data from the server and also takes the local data..."

### Tables

Use for structured info:

```markdown
| Parameter | Type   | Description    |
| --------- | ------ | -------------- |
| `data`    | object | Fresh from API |
| `local`   | object | Current state  |
```

---

## Self-Contained Documents & References

Two verbosity regimes, split by who pays for the words. **Instruction files** (`CLAUDE.md`, rules, agents, skill prose) load into an agent's context on every turn or invocation — they stay lean, per [`instruction-style.md`](instruction-style.md). **Documents** are read on demand, by humans and agents alike — they are written **verbose and self-contained**, and the cost of a reader hopping files exceeds the cost of extra words on the page.

- **The body reads whole without opening another file.** Restate the one or two sentences of context a borrowed concept needs, right where it's used — a reader forced mid-paragraph into a second document loses the thread of the first.
- **Restate for readability, cite for authority — never fork the fact.** A changing detail (a version, a count, a path list) keeps one canonical home; the restatement carries what the page needs to be understood and points at the authority for the rest. Link-don't-copy governs where a fact is *owned*, not how readable the page that uses it must be.
- **Inline links are the minimum that action requires.** Link mid-prose only where the reader must go there to act on this page. Every other sister document — everything the topic touches — belongs in one **Related** (or **References**) section at the document's end.
- **The Related tail is the document's entire link surface.** Deep relative paths (`../../../../…`) are fragile — a folder move breaks every one — so they are confined to that one block, where a path change touches one place; body mentions use the plain name (`the boundary skill`, `structure.md`) instead of a link.

---

## The Two Natures — Tense & History

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:

**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.

**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.

Strip this language from truth documents:

| ❌ Historical narration (belongs in a record) | ✅ Present-tense fact (belongs in the truth doc) |
| --- | --- |
| "Folded in from the `NuStack-X` repo (2026-06-12)." | "Vendor-connector catalogue; one subpath per vendor." |
| "Built 2026-06-14; shipped + verified 2026-06-13." | "`agentSessionWorkflow` runs an outer turn loop over `runAgentLoop`." |
| "The legacy worker was deleted in the 2026-06-14 fold." | "One worker interprets `WorkflowDefinition`." |
| "ex-`@nurix/mcp-runtime`, M9 Phase C; was X, now Y." | "MCP client runtime, wired into `agentTriggerWorkflow`." |
| "Build Sequence phases 0–4 are complete." | Nothing — progress lives in the plan/backlog record; the doc describes what exists |
| "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 |
| "Read first: `docs/history/plans/2026-…-fold.md`" (routing) | "Read first: `docs/architecture/<current-truth-doc>.md`" |

Rules:

- **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.
- **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.
- **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`.)
- **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.
- **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/`.
- **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.
- **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.)
- **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.
- **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.

Worked example of the strip-and-relocate move: [`examples.md`](examples.md) Example 6.

---

## Mechanics

- Inline-code every identifier, filename, command, and config key.
- Bullet rules take the form "**bold assertion** — explanation."

---

## Structure

### Headers

```markdown
# Document Title (H1 - once)

## Major Section (H2)

### Subsection (H3)

#### Detail (H4 - sparingly)
```

**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.

### Standard Layout

```markdown
# [Title]

**Goal:** One-line purpose

## Architecture

[Diagram + explanation]

## Key Functions

[Signatures and contracts]

## State

[Persistence shapes]

## Files

[Source file list]
```

### File References

Always end with:

```markdown
## Files

- `src/path/main.js` - Core logic
- `src/path/hooks.js` - React hooks
```

---

## Summary

| Aspect     | Rule                            |
| ---------- | ------------------------------- |
| Functions  | Always include signatures       |
| Parameters | Type + purpose                  |
| Returns    | Type + shape                    |
| State      | Persistence points only         |
| Diagrams   | ASCII for structure at rest, mermaid for behaviour over time — docs only, never instruction files |
| Code       | Under 15 lines, contracts only  |
| Voice      | Imperative/active               |
| Mechanics  | Inline-code identifiers; bold-assertion bullets |
| Length     | Concise, one line when possible |
