@gobing-ai/spur 0.3.19 → 0.3.21

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.
@@ -0,0 +1,31 @@
1
+ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
2
+ # Forbid getByLabelText queries on button accessible names in web component tests.
3
+ #
4
+ # WHY: HTML `<button>` elements are non-labellable per WHATWG HTML spec. In DOM Testing
5
+ # Library, `getByLabelText` queries elements associated with `<label>` tags. When used to
6
+ # query a `<button>` with an `aria-label` attribute, it works when happy-dom DOM state is
7
+ # fresh, but throws `TestingLibraryElementError: element associated with this label is non-labellable`
8
+ # when running in full multi-file test suites on CI (e.g. Linux runners).
9
+ # Real incident: CI-only failure in apps/web/tests/modules/task-kanban/components.test.tsx on 2026-07-24.
10
+ #
11
+ # FIX: Use `getByRole('button', { name: '...' })` or `getByRole('button', { name: /.../ })`,
12
+ # which queries the W3C accessible name provided by `aria-label`.
13
+ include:
14
+ - "apps/web/tests/**/*.test.ts"
15
+ - "apps/web/tests/**/*.test.tsx"
16
+ exclude:
17
+ - "**/node_modules/**"
18
+ - "**/dist/**"
19
+
20
+ rules:
21
+ - id: prefer-accessible-role-for-button-queries
22
+ description: >
23
+ Do not query button accessible names with `getByLabelText` in web React tests.
24
+ `<button>` elements are non-labellable per WHATWG spec, causing timing-dependent
25
+ CI failures when tests run sequentially in a single process.
26
+ Use `getByRole('button', { name: ... })` instead.
27
+ severity: warning
28
+ evaluator:
29
+ type: rg
30
+ config:
31
+ pattern: "getByLabelText\\(['\"]Sort "
@@ -4,7 +4,7 @@ Entry point for AI coding agents in this repository. Symlink `CLAUDE.md` / `GEMI
4
4
  equivalents) here when the platform expects those names.
5
5
 
6
6
  **Read this first every session.** Lean: harness routing + project facts + where depth lives.
7
- Does **not** restate skill runbooks or the full `spur` verb catalog.
7
+ Does **not** restate skill runbooks or the full `spur` / `superskill` verb catalogs.
8
8
 
9
9
  ---
10
10
 
@@ -13,9 +13,16 @@ Does **not** restate skill runbooks or the full `spur` verb catalog.
13
13
  <!-- PROJECT-SPECIFIC: filled by `spur init` (`{project-name}` / `{project-description}`). -->
14
14
  **{project-name}** — {project-description}.
15
15
 
16
- This project uses **Spur** as its harness: the `spur` CLI for deterministic corpus/ops, and Spur’s
17
- agent surface (`/sp:dev-*` commands + `sp:*` subagents/skills) for planning, execution, review, and
18
- docs hygiene. Prefer the harness over ad-hoc process unless the operator overrides for a one-off.
16
+ This project uses two complementary first-class harness tools:
17
+
18
+ - **Spur** `spur` provides deterministic project corpus/ops; the `sp` agent surface
19
+ (`/sp:dev-*` commands + `sp:*` subagents/skills) drives planning, execution, review, and docs
20
+ hygiene.
21
+ - **Superskill** — `superskill` installs plugin capabilities across supported coding agents and
22
+ manages the authoring and quality lifecycle for skills, commands, agents, hooks, and main-agent
23
+ configs.
24
+
25
+ Prefer these entry surfaces over ad-hoc process unless the operator overrides for a one-off.
19
26
 
20
27
  ---
21
28
 
@@ -41,6 +48,8 @@ All product development work goes through the harness by default.
41
48
  | Docs drift / sync / lessons | Skill **`sp:doc-evolve`** + `docs/99_PROJECT_CONSTITUTION.md` | Patching derived docs over authority |
42
49
  | Wrap completed work | `/sp:dev-wrap`, `/sp:dev-wrapall` | Skipping learnings / doc sync |
43
50
  | Session index / memory | Skill **`sp:indexed-context`** + `.spur/context/` | Full-tree re-reads every turn |
51
+ | Install / sync a plugin across coding agents | **`superskill install <plugin>`** | Hand-copying per-platform adapters |
52
+ | Capability authoring / quality lifecycle | **`superskill <noun> --help`** (`agent`, `skill`, `command`, `hook`, `magent`) | Bypassing the noun's validation / evaluation gates |
44
53
 
45
54
  **Non-negotiable (unless operator overrides):**
46
55
 
@@ -51,10 +60,13 @@ All product development work goes through the harness by default.
51
60
  3. **`--json` for machines** — parse CLI with `--json`.
52
61
  4. **Route, don’t invent** — verbs → `sp:spur-cli`; lifecycle → `/sp:dev-*` / `sp:super-coder`;
53
62
  multi-noun corpus → `sp:expert-spur`; review → `sp:super-reviewer`; docs process → `sp:doc-evolve`.
63
+ 5. **Keep tool ownership explicit** — project lifecycle/corpus/gates → Spur; plugin installation and
64
+ capability lifecycle → Superskill. Do not hand-maintain per-platform adapters Superskill generates.
54
65
 
55
66
  **Platform fallback:** Platforms without slash commands and/or subagents still use the harness.
56
- Equivalent path: skills `sp:spur-dev`, `sp:spur-cli`, `sp:code-verification` (and related) plus the
57
- `spur` CLI. Do not invent a parallel process because `/sp:dev-*` is unavailable.
67
+ Install the plugin through Superskill for the target platform, then use skills `sp:spur-dev`,
68
+ `sp:spur-cli`, `sp:code-verification` (and related) plus the `spur` CLI. Do not invent a parallel
69
+ process because `/sp:dev-*` is unavailable.
58
70
 
59
71
  Invoke CLI: `spur <noun> <verb> … --json` (or the project’s documented dev entry).
60
72
 
@@ -68,7 +80,7 @@ Invoke CLI: `spur <noun> <verb> … --json` (or the project’s documented dev e
68
80
  **Conflict rule:** lower number wins on content (`00` decisions, `01` scope, `99` process). Fix
69
81
  authority first, then derived docs, then this file.
70
82
 
71
- ### Doc map (constitution §4.1)
83
+ ### Doc map
72
84
 
73
85
  | Doc | Owns | Authority | When |
74
86
  |------|------|-----------|------|
@@ -82,7 +94,20 @@ authority first, then derived docs, then this file.
82
94
  | `AGENTS.md` (this file) | **ENTRY** | Derived | First every session |
83
95
 
84
96
  **Routing:** decision → `00`; scope → `01`; mechanism → `03`; surface → `04`; phase → `02`;
85
- feature status → `05`. Working layers §4.2; audits §7; satellites §4.5.
97
+ feature status → `05`. Working-layer, audit, and satellite rules live in the project constitution.
98
+
99
+ ---
100
+
101
+ ## Design system
102
+
103
+ **Conditional contract:** If repository-root `DESIGN.md` exists, read it before planning or
104
+ implementing any change to UI, styling, interaction, accessibility, or responsive behavior. Treat
105
+ it as the project source of truth for visual and interaction design — tokens, components, patterns,
106
+ and UX constraints — and keep affected work consistent with it. If it is absent, continue with the
107
+ project's established UI conventions.
108
+
109
+ Root `DESIGN.md` owns UI/UX guidance; `docs/04_DESIGN.md` still owns command, config, schema, and DTO
110
+ surface shapes under the doc map above.
86
111
 
87
112
  ---
88
113
 
@@ -125,6 +150,22 @@ spur <noun> --help
125
150
 
126
151
  ---
127
152
 
153
+ ## Superskill CLI surface
154
+
155
+ **Ownership boundary:** Superskill is the install-time portability and capability-quality plane;
156
+ Spur remains the project lifecycle and deterministic corpus/ops plane.
157
+
158
+ ```bash
159
+ superskill install <plugin> --dry-run
160
+ superskill install <plugin> --targets <list>
161
+ superskill <agent|skill|command|hook|magent> --help
162
+ ```
163
+
164
+ Use `superskill <noun> --help` for the current lifecycle verbs and flags. Do not duplicate its full
165
+ catalog here or maintain generated per-platform capability copies in the project.
166
+
167
+ ---
168
+
128
169
  ## Conventions & boundaries
129
170
 
130
171
  - Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`, …); breaking changes in a
@@ -4,29 +4,39 @@ doc: 00_ADR
4
4
  owns: WHY — which cross-cutting decision was made, and the one-line reason
5
5
  authority: authoritative
6
6
  version: 1.0.0
7
- created_at: 1970-01-01T00:00:00.000Z
8
- updated_at: 1970-01-01T00:00:00.000Z
7
+ owner: _(project owner)_
8
+ updated_at: {{init-date}}
9
+ read_before: any structural change
10
+ edit_rules: 99 §6.1
11
+ sync: [T1, T2]
9
12
  ---
10
13
 
11
14
  # Architecture Decision Records
12
15
 
13
- > Authoritative on **decisions**. Lower number wins — this doc overrides all others on decisions.
14
- > Each entry is append-only; supersession is by a new dated entry, never by editing an old one.
15
- > Only real cross-cutting decisions belong here — not implementation notes, not feature status, not
16
- > how-to guidance. Entries that grow past decision + reason are carrying mechanism that belongs in
17
- > `03`/`04`; link it instead of inlining it.
16
+ ## ADR-001 Adopt this doc structure
18
17
 
19
- ## ADR-001 (example) Adopt this doc structure
18
+ **Status:** Accepted · **Date:** {{init-date}}
20
19
 
21
- - **Date:** 1970-01-01
22
- - **Status:** accepted
23
- - **Context:** Project needs a single source of truth for decisions and scope.
24
- - **Decision:** Adopt the Spur doc structure (`00`–`05` + `99` constitution).
25
- - **Reason:** Separates WHY (`00`) from WHAT (`01`) from HOW (`03`/`04`) — one fact, one home.
20
+ **Decision.** Adopt the Spur doc structure (`00`–`05` + `99` constitution).
21
+
22
+ **Why.** Separates WHY (`00`) from WHAT (`01`) from HOW (`03`/`04`) one fact, one home.
23
+
24
+ **Detail:** `docs/99_PROJECT_CONSTITUTION.md` §4.1.
26
25
 
27
26
  <!--
28
- Add new ADRs here. Copy the entry shape above (Date, Status, Context, Decision, Reason).
27
+ Add new ADRs here. Entry shape (per 99 §6.1):
28
+
29
+ ## ADR-NNN: <Decision title, outcome-shaped>
30
+
31
+ **Status:** Accepted | Accepted (design) | Superseded by ADR-MMM | Skipped · **Date:** YYYY-MM-DD
32
+
33
+ **Decision.** <What was decided — the smallest complete statement of the choice.>
34
+
35
+ **Why.** <One line. The single strongest reason.>
36
+
37
+ **Detail:** <pointer into 03/04/plans — depth never lives here.>
38
+
29
39
  A decision that reverses a prior ADR adds a new entry that says "supersedes ADR-NNN".
30
40
  An Amendment records the decision delta + one-line reason — not the mechanism. Implementation
31
41
  paths, detailed semantics, and multi-paragraph rationale belong in 03/04, not in the amendment.
32
- -->
42
+ -->
@@ -4,14 +4,15 @@ doc: 01_PRD
4
4
  owns: WHAT — product vision, users, scope (in / out / deferred)
5
5
  authority: authoritative-on-scope
6
6
  version: 1.0.0
7
- created_at: 1970-01-01T00:00:00.000Z
8
- updated_at: 1970-01-01T00:00:00.000Z
7
+ owner: _(project owner)_
8
+ updated_at: {{init-date}}
9
+ read_before: adding a command or feature
10
+ edit_rules: 99 §6.2
11
+ sync: [T1, T4, T6]
9
12
  ---
10
13
 
11
14
  # Product Requirements Document
12
15
 
13
- > Authoritative on **scope**. In-scope vs out-of-scope vs deferred lives here and nowhere else.
14
-
15
16
  ## 1. Vision
16
17
 
17
18
  _(One sentence: what this product is and who it is for.)_
@@ -28,10 +29,14 @@ _(One sentence: what this product is and who it is for.)_
28
29
 
29
30
  - _(capability the product delivers)_
30
31
 
31
- ### Out of scope
32
+ ### Supporting
32
33
 
33
- - _(explicitly excluded capability prevents scope creep)_
34
+ - _(capability that enables an in-scope item but is not user-facing)_
34
35
 
35
36
  ### Deferred
36
37
 
37
- - _(capability intentionally postponed — not a commitment)_
38
+ - _(capability intentionally postponed — not a commitment; carry the condition that would reactivate it)_
39
+
40
+ ### Out of scope
41
+
42
+ - _(explicitly excluded capability — prevents scope creep)_
@@ -4,19 +4,27 @@ doc: 02_ROADMAP
4
4
  owns: WHEN — phases, current vs deferred, sequencing
5
5
  authority: derived
6
6
  version: 1.0.0
7
- created_at: 1970-01-01T00:00:00.000Z
8
- updated_at: 1970-01-01T00:00:00.000Z
7
+ derived_from: [00_ADR, 01_PRD]
8
+ owner: _(project owner)_
9
+ updated_at: {{init-date}}
10
+ read_before: placing work in a phase
11
+ edit_rules: 99 §6.3
12
+ sync: [T5]
9
13
  ---
10
14
 
11
15
  # Roadmap
12
16
 
13
- > Derived from `01_PRD` (scope) and `00_ADR` (decisions). Edit when phase status changes.
14
-
15
17
  ## Phases
16
18
 
17
- | Phase | Status | Items |
18
- |-------|--------|-------|
19
- | Phase 0 — Foundation | ✅ done | _(list the real, shipped deliverable names)_ |
20
- | Phase 1 — _(name)_ | ⏳ planned | _(items)_ |
19
+ | Phase | Status | Items | Exit criterion |
20
+ |-------|--------|-------|----------------|
21
+ | Phase 0 — Foundation | ✅ done | _(list the real, shipped deliverable names)_ | _(what must be true to exit)_ |
22
+ | Phase 1 — _(name)_ | ⏳ planned | _(items)_ | _(what must be true to exit)_ |
21
23
 
22
24
  **Status legend:** ✅ done · 🔶 partial · ⏳ planned · 💤 deferred
25
+
26
+ <!--
27
+ Markers: [x] done · [~] partial · [ ] pending. [x]/[~] carry a one-line evidence note.
28
+ When a deliverable lands under a different name than planned, rewrite the bullet to the real name.
29
+ Insert sub-phases (1.5) rather than renumbering existing ones.
30
+ -->
@@ -4,14 +4,16 @@ doc: 03_ARCHITECTURE
4
4
  owns: HOW — module boundaries, data flow, runtime model, invariants
5
5
  authority: derived
6
6
  version: 1.0.0
7
- created_at: 1970-01-01T00:00:00.000Z
8
- updated_at: 1970-01-01T00:00:00.000Z
7
+ derived_from: [00_ADR, 01_PRD]
8
+ owner: _(project owner)_
9
+ updated_at: {{init-date}}
10
+ read_before: cross-module, seam, or schema work
11
+ edit_rules: 99 §6.4
12
+ sync: [T1]
9
13
  ---
10
14
 
11
15
  # Architecture
12
16
 
13
- > Derived (ADR wins). Read before cross-module/seam/schema work; edit when boundaries or mechanisms change.
14
-
15
17
  ## 1. Module map
16
18
 
17
19
  ```
@@ -24,4 +26,9 @@ _(Describe the primary data path: input → processing → output. Name the seam
24
26
 
25
27
  ## 3. Invariants
26
28
 
27
- - _(state or property that always holds — the thing tests should protect)_
29
+ - _(state or property that always holds — phrased so a constraint rule or reviewer can check it mechanically)_
30
+
31
+ <!--
32
+ Describes the CURRENT architecture only. Future/accepted designs go in sections explicitly
33
+ titled "(accepted design — ADR-NNN; not yet built)". On conflict with 00, the ADR wins; fix here.
34
+ -->
@@ -1,17 +1,29 @@
1
1
  ---
2
2
  name: Design
3
3
  doc: 04_DESIGN
4
- owns: SURFACE — concrete shapes: every CLI command, flag, config key, env var, table, DTO
4
+ owns: SURFACE — concrete shapes: every CLI command, flag, config key, env var, table, DTO; index over docs/design/
5
5
  authority: derived
6
6
  version: 1.0.0
7
- created_at: 1970-01-01T00:00:00.000Z
8
- updated_at: 1970-01-01T00:00:00.000Z
7
+ derived_from: [00_ADR, 01_PRD]
8
+ owner: _(project owner)_
9
+ updated_at: {{init-date}}
10
+ read_before: changing a command, flag, env var, or schema
11
+ edit_rules: 99 §6.5
12
+ sync: [T3, T9]
9
13
  ---
10
14
 
11
15
  # Design
12
16
 
13
- > Derived. Concrete shapes every command, flag, config key, env var, schema, and DTO. Edit when
14
- > a surface changes.
17
+ > **Index page** over `docs/design/` satellites (99 §4.5). Each surface area gets a
18
+ > `docs/design/<slug>.md` satellite; this index carries the surface map + pointers.
19
+ > Edit order: satellite first, then index row — same change (T9).
20
+
21
+ ## UI/UX boundary
22
+
23
+ Repository-root `DESIGN.md` owns all UI/UX design, including visual language, design tokens,
24
+ components, layout, interaction, accessibility, and responsive behavior. Read and update it for UI
25
+ work; keep this document focused on non-UI surface design. If `DESIGN.md` is absent, follow the
26
+ project's established UI conventions rather than adding UI guidance here.
15
27
 
16
28
  ## 1. CLI commands
17
29
 
@@ -19,12 +31,18 @@ updated_at: 1970-01-01T00:00:00.000Z
19
31
  _(command) <positional> [--flag <value>] [--json]
20
32
  ```
21
33
 
22
- | Command | Description |
23
- |---------|-------------|
24
- | _(command)_ | _(one-line description)_ |
34
+ | Command | Description | Design doc |
35
+ |---------|-------------|------------|
36
+ | _(command)_ | _(one-line description)_ | `docs/design/_(slug)_.md` |
25
37
 
26
38
  ## 2. Configuration keys
27
39
 
28
40
  | Key | Type | Default | Description |
29
41
  |-----|------|---------|-------------|
30
42
  | _(key)_ | _(type)_ | _(default)_ | _(description)_ |
43
+
44
+ <!--
45
+ Shapes only — rationale lives in 00/03. Behavioral notes are shapes ("resolving zero rules exits 1"
46
+ — keep); justifications are not ("...because a silent gate is the worst failure mode" — cut).
47
+ Transcribe command signatures from the code registrations, never from memory.
48
+ -->
@@ -1,16 +1,22 @@
1
1
  ---
2
2
  name: Features
3
3
  doc: 05_FEATURES
4
- owns: STATUS — feature decomposition + state
4
+ owns: STATUS — feature decomposition + state; index over docs/features/
5
5
  authority: derived
6
6
  version: 1.0.0
7
- created_at: 1970-01-01T00:00:00.000Z
8
- updated_at: 1970-01-01T00:00:00.000Z
7
+ derived_from: [00_ADR, 01_PRD]
8
+ owner: _(project owner)_
9
+ updated_at: {{init-date}}
10
+ read_before: finding a feature's state
11
+ edit_rules: 99 §6.6
12
+ sync: [T4, T9]
9
13
  ---
10
14
 
11
15
  # Features
12
16
 
13
- > Derived. Feature status roll-up. Edit when a feature's status changes.
17
+ > **Index page** over `docs/features/` satellites (99 §4.5). Both the satellites and this index's
18
+ > generated region are **tool-owned** (e.g. `spur feature`/`ftree`); edit through the tool, never
19
+ > with raw file writes. Edit order: satellite first, then refresh index (T9).
14
20
 
15
21
  ## Status legend
16
22
 
@@ -18,6 +24,11 @@ updated_at: 1970-01-01T00:00:00.000Z
18
24
 
19
25
  ## Feature tree
20
26
 
21
- | ID | Feature | Status | Parent | Notes |
22
- |----|---------|--------|--------|-------|
23
- | F1 | _(root feature)_ | ⏳ planned | — | _(one-line scope)_ |
27
+ | ID | Feature | Status | Parent | Notes | Satellite |
28
+ |----|---------|--------|--------|-------|-----------|
29
+ | F1 | _(root feature)_ | ⏳ planned | — | _(one-line scope)_ | `docs/features/F1__(slug)_.md` |
30
+
31
+ <!--
32
+ Never trust a row you have not verified — check status against code before citing or building on it.
33
+ One item per satellite; <feature-id> is the stable grep anchor. Renaming is a tool operation.
34
+ -->
@@ -3,63 +3,457 @@ name: Project Constitution
3
3
  doc: 99_PROJECT_CONSTITUTION
4
4
  owns: PROCESS — how the key files are maintained
5
5
  authority: authoritative-on-process
6
- version: 1.0.0
7
- created_at: 1970-01-01T00:00:00.000Z
8
- updated_at: 1970-01-01T00:00:00.000Z
6
+ version: 1.3.0
7
+ created_at: {{init-date}}
8
+ updated_at: {{init-date}}
9
+ edit_rules: 99 §6.8
10
+ sync: [T7]
11
+ read_before: editing any numbered doc above
9
12
  ---
10
13
 
11
14
  # Project Constitution — How to Organize the Project
12
15
 
13
- > **This is a template.** Spur's own constitution at
14
- > [docs/99_PROJECT_CONSTITUTION.md](https://github.com/gobing-ai/spur/blob/main/docs/99_PROJECT_CONSTITUTION.md)
15
- > is the canonical version. Copy the full content there into this file for a real project, then
16
- > localize the Lessons section (§8) and the tool-binding column (§3).
17
-
18
16
  ## 1. What this is & what this is not
19
17
 
20
18
  This is the **constitution** for the project's key files: an accumulated, machine-maintained set
21
19
  of rules and lessons for running the same file structure across different projects and
22
- cooperating with multiple coding agents (Claude Code, Codex, Gemini CLI, pi, Antigravity,
23
- OpenCode, OpenClaw, ...).
20
+ cooperating with multiple coding agents (Claude Code, Codex, Gemini CLI, pi, omp, Antigravity,
21
+ OpenCode, OpenClaw, Hermes, Grok, ...).
24
22
 
25
23
  - One copy lives in every project at `docs/99_PROJECT_CONSTITUTION.md`.
26
24
  - It is **byte-identical across projects** except the Lessons sections (§8) and the tool-binding
27
25
  column (§3). When it improves in one project, propagate to the others — forks are drift.
28
26
  - It contains **zero project-specific facts** — no project command names, package names, feature
29
- states, or decisions. Project facts live in the numbered docs this file governs.
27
+ states, or decisions. Project facts live in the numbered docs this file governs. If you find a
28
+ project fact here, that itself is drift: move it to its owning doc.
29
+
30
+ This is **not** a project review summary, a technical review list, or a product-design
31
+ reflection.
32
+
33
+ Audience: humans and coding agents equally. Every rule below is written to be checkable — an
34
+ agent should be able to verify compliance mechanically, not interpret intent.
30
35
 
31
36
  ## 2. Authority model
32
37
 
38
+ Two axes that cannot collide:
39
+
33
40
  | Axis | Question | Winner |
34
41
  |------|----------|--------|
35
42
  | **Content** | What is true about the project? | Lower number wins: `00_ADR` is binding on *decisions*; `01_PRD` is authoritative on *scope*; `02`–`05` are derived |
36
43
  | **Process** | How are the key files maintained? | **This file** |
37
44
 
38
- ## 3. Doc map
45
+ They cannot conflict because this file holds no project content (§1 rule 3).
46
+
47
+ **Why this file is numbered 99, not 00:** "lower number wins" is a *content* rule, and this file
48
+ plays on the other axis. The out-of-band number is the visible signal that the constitution sits
49
+ outside the content chain — renumbering it into the chain (e.g. as `00`) would re-entangle the
50
+ two axes and force a renumber of every content doc, invalidating the dense web of cross-pointers
51
+ (`03 §12`-style references baked into append-only ADR text) for a purely aesthetic gain. Do not
52
+ renumber.
53
+
54
+ **Content conflict rule:** when two docs disagree, fix the **authoritative** doc first (with a
55
+ dated amendment if it is append-only), then the derived doc, then `AGENTS.md` — and flag the
56
+ drift in the commit message or task. Never average two conflicting statements into a third.
57
+
58
+ ## 3. Shared tools
59
+
60
+ Tools are bound by **role**; roles are permanent, bindings evolve. This table is the only
61
+ project-variable section besides Lessons — update the binding when the toolchain migrates.
62
+
63
+ | Role | Current binding | Notes |
64
+ |------|-----------------|-------|
65
+ | Spec lifecycle — tasks | _(project tool — e.g. `spur task` or a task CLI)_ | Task files are tool-owned; edit through the tool, never the Write tool |
66
+ | Spec lifecycle — features | _(project tool — e.g. `spur feature` or a feature CLI)_ | Same tool-owned rule |
67
+ | Delivery harness | _(project harness — e.g. `spur`)_ | Quality gates are self-hosted through it where possible |
68
+ | Agent-facing wrappers | per-project plugin dir (e.g. `plugins/sp/`) | **Fat Skills, thin others:** skills are the SSOT for agent-facing behavior and may be arbitrarily rich; slash commands and subagents are thin wrappers of skills (every agent supports skills; command/subagent support varies) |
69
+
70
+ ## 4. Common file layout
71
+
72
+ ### 4.1 The doc map (canonical template)
73
+
74
+ Each project's `AGENTS.md` embeds an instantiated copy of this table (§4.4). A fact lives in
75
+ **one** doc; other docs link to it, never restate it.
76
+
77
+ | Doc | Owns the question | Authority | Read / edit when |
78
+ |-----|-------------------|-----------|------------------|
79
+ | `docs/00_ADR.md` | **WHY** — which cross-cutting decision was made, and the one-line reason | **Authoritative** (wins all content) | Read before any structural change; add a dated entry before diverging from a decision |
80
+ | `docs/01_PRD.md` | **WHAT** — product vision, users, scope (in / out / deferred) | **Authoritative on scope** | Read before adding a command/feature; edit when scope changes |
81
+ | `docs/02_ROADMAP.md` | **WHEN** — phases, current vs deferred, sequencing | Derived | Read to place work in a phase; edit when phase status changes |
82
+ | `docs/03_ARCHITECTURE.md` | **HOW** — module boundaries, data flow, runtime model, invariants, rationale-in-depth | Derived (ADR wins) | Read before cross-module/seam/schema work; edit when boundaries or mechanisms change |
83
+ | `docs/04_DESIGN.md` | **SURFACE** — concrete shapes: every CLI command, flag, config key, env var, table, DTO; **index over `docs/design/<slug>.md`** (§4.5) | Derived | Read/edit when changing a command, flag, env var, or schema — same commit |
84
+ | `docs/05_FEATURES.md` | **STATUS** — feature decomposition + state (✅ done / 🔶 partial / ⏳ planned / 💤 deferred); **index over `docs/features/<id>_<slug>.md`** (§4.5) | Derived | Read to find a feature's state; edit when a feature's status changes |
85
+ | `docs/99_PROJECT_CONSTITUTION.md` | **PROCESS** — how the files above are maintained | **Authoritative on process** | Read before editing any doc above; edit per §6.8 |
86
+ | `AGENTS.md` (repo root) | **ENTRY** — how agents work in this repo: stack, commands, gates, conventions + the instantiated doc map | Derived (from 99 + 00/01/04) | Read first every session; regenerate factual blocks from code (§6.7) |
87
+
88
+ **Routing — put each fact in its owning doc, link from the rest:**
89
+
90
+ - Decision + one-line reason → `00`. Rationale/mechanism in depth → `03`.
91
+ - Scope (in/out/deferred) → `01`. Mechanism / data flow / invariants → `03`.
92
+ - Command/flag/config/schema/DTO shapes → `04`. Phase timing → `02`. Feature status → `05`.
93
+ - If you are writing *how it's built* or *why* inside `00`/`01`/`02`, it belongs in `03`/`04`.
94
+
95
+ ### 4.2 Working layers (outside the authority chain)
96
+
97
+ | Location | Purpose | Rules |
98
+ |----------|---------|-------|
99
+ | `docs/plans/YYYY-MM-DD-<topic>.md` | Dated working documents: research, triage, design discussions, decision records-in-progress | They **record**, they do not **govern**. Once concluded, immutable except dated correction sections. Decisions they reach must be promoted into `00`–`05` to take effect |
100
+ | `docs/tasks/` | Task files | Tool-owned (§3). Never edited with raw file writes |
101
+ | other `docs/` folders | Optional scratch (analysis, refactor notes, ...) | Nothing in the authority chain may depend on them |
102
+
103
+ `docs/design/` and `docs/features/` are **not** scratch — they are the satellite layers of `04` and
104
+ `05` and are governed by §4.5.
105
+
106
+ ### 4.3 Standard frontmatter (the doc's machine-readable contract)
107
+
108
+ Every numbered doc (`00`–`05`, and `99` itself) opens with YAML frontmatter carrying its doc-map
109
+ row plus bookkeeping — so an agent learns the doc's contract from the file head without loading
110
+ the doc map, and tooling can validate it:
111
+
112
+ ```yaml
113
+ ---
114
+ doc: 03_ARCHITECTURE
115
+ owns: HOW — module boundaries, data flow, runtime model, invariants
116
+ authority: derived # authoritative | authoritative-on-scope | authoritative-on-process | derived
117
+ version: 1.1.0
118
+ derived_from: [00_ADR, 01_PRD] # omit for 00
119
+ owner: <name>
120
+ updated_at: YYYY-MM-DD
121
+ read_before: cross-module, seam, or schema work
122
+ edit_rules: 99 §6.4
123
+ sync: [T1] # §5 trigger IDs that obligate touching this doc
124
+ ---
125
+ ```
126
+
127
+ Rules:
128
+
129
+ 1. The frontmatter **is** the instantiated copy of this file's §4.1 row — `owns`/`authority`
130
+ must match it verbatim in meaning; the §7 audit checks this. On mismatch, §4.1 wins.
131
+ 2. `edit_rules` points to the owning §6 subsection — rules are never restated in frontmatter
132
+ (pointers over prose, §6.0).
133
+ 3. Bump `version` (minor) on any substantive edit; always refresh `updated_at` in the same edit.
134
+ A doc whose `updated_at` predates a change it should reflect is drift — repair per §7.
135
+ 4. Frontmatter replaces the legacy bold header block (`**Version:** …` lines); a doc carrying
136
+ both is drift.
137
+ 5. Doc **bodies do not restate** their own authority or the conflict rule ("when this conflicts
138
+ with the ADR, the ADR wins") — frontmatter `authority` and §2 own that. Preamble
139
+ restatements are drift.
140
+
141
+ ### 4.4 AGENTS.md synchronization
142
+
143
+ - `AGENTS.md` is the **per-project instantiation**: the §4.1 table (instantiated), plus
144
+ project-specific stack, commands, verification gates, and conventions.
145
+ - This file is the canonical template; when §4.1 or §5 changes here, re-sync `AGENTS.md` in the
146
+ same change.
147
+ - `AGENTS.md` may **add** project facts; it may never **contradict** the numbered docs. On
148
+ contradiction, the numbered doc wins — fix `AGENTS.md`.
149
+
150
+ ### 4.5 Index + satellite docs (`04`/`05` and their folders)
151
+
152
+ Two derived docs are **index pages** over a folder of per-item **satellite** files. The index holds
153
+ the headline rows + pointers; each satellite holds one item's detail. This keeps the index readable
154
+ (loaded every session) while detail scales without bloating it.
155
+
156
+ | Index doc | Satellite folder | Satellite file name | Satellite ownership |
157
+ |-----------|------------------|---------------------|---------------------|
158
+ | `docs/04_DESIGN.md` | `docs/design/` | `docs/design/<slug>.md` | Hand-maintained derived doc (§6.5) |
159
+ | `docs/05_FEATURES.md` | `docs/features/` | `docs/features/<feature-id>_<slug>.md` | **Tool-owned** (§3 — `spur feature`/`ftree`); satellites *and* the index region are written by the tool, never by raw file writes |
160
+
161
+ Rules (both axes):
162
+
163
+ 1. **The index is the single entry point.** A reader starts at `04`/`05`; every satellite is
164
+ reachable from exactly one index row. A satellite with no index row, or an index row with no
165
+ satellite, is drift (§7 audit).
166
+ 2. **One item per satellite.** `<slug>` (design) / `<feature-id>_<slug>` (features) is the grep
167
+ anchor (§6.0 rule 6) — stable once chosen; renaming is a rename of the file *and* its index row in
168
+ the same change.
169
+ 3. **Detail lives only in the satellite; the index carries pointer + status only.** The index never
170
+ restates a satellite's body (§6.0 rule 2). For `05`, a row is `<id> <status> <name> → pointer`;
171
+ for `04`, an index row names the surface area and points at its `docs/design/<slug>.md`.
172
+ 4. **The index is regenerable for `05`** (tool-written) and **hand-curated for `04`** — but in both
173
+ cases the satellite is the source of truth and the index is derived from it. Never edit `05`'s
174
+ generated index region by hand; never let a `04` index row diverge from its satellite.
175
+ 5. **Edit order is fixed (§5 T9): detail first, then index.** Write/update the satellite, then update
176
+ the index row — in the **same change**. Updating the index before the detail exists creates a
177
+ pointer to nothing; the reverse leaves the detail unindexed. For tool-owned features, "update the
178
+ index" is running the tool's refresh (e.g. `spur feature refresh`), not a manual edit.
179
+
180
+ ## 5. Sync triggers — same-commit obligations
181
+
182
+ The root cause of stale key files is *unsynchronized success*: code ships, docs don't hear about
183
+ it. Each trigger below has a stable ID (referenced by doc frontmatter `sync:` lists, §4.3) and
184
+ names the docs that must be touched **in the same commit / same change**:
185
+
186
+ | ID | When this happens | Touch (same change) |
187
+ |----|-------------------|---------------------|
188
+ | T1 | New cross-cutting decision, or reversal of one | `00` **first** (dated entry), then `03` mechanism, `01` if scope shifts |
189
+ | T2 | A code change would contradict an existing ADR | **Stop.** Add the superseding/amending ADR entry first — never silently diverge |
190
+ | T3 | Command, flag, config key, env var, schema, or DTO added/changed | `04` + the `AGENTS.md` surface block |
191
+ | T4 | A feature ships or changes state | its `05` row; a new `01` scope row if it is new surface |
192
+ | T5 | A phase completes, reorders, or gains items | `02` (update the bullet to the *real, shipped name* of the deliverable) |
193
+ | T6 | Scope added / cut / deferred | `01`; placement in `02` |
194
+ | T7 | The doc map or process changes | this file → re-sync `AGENTS.md` (§4.4) → propagate to sibling projects |
195
+ | T8 | A multi-wave batch is planned | schedule "doc sync" as an **explicit work item** — same-commit discipline does not survive on memory alone |
196
+ | T9 | A design or feature item is added/changed | the satellite **first** (`docs/design/<slug>.md` or `docs/features/<id>_<slug>.md`), **then** its index row in `04`/`05` — same change (§4.5 rule 5) |
197
+
198
+ ## 6. Edit principles per file
199
+
200
+ ### 6.0 Writing rules (all key files)
201
+
202
+ Token economy is a design goal: these files are read by LLM agents at session start, every
203
+ session, across every project — a redundant sentence is paid for thousands of times. Precise
204
+ **and** concise; precision wins when they conflict.
205
+
206
+ 1. Declarative, information-dense sentences. No filler, no marketing adjectives, no hedging, no
207
+ narrative buildup.
208
+ 2. A fact lives once — link or point (`see 03 §12`) instead of restating, both in-file and
209
+ cross-file. Restatement is the largest token sink in a doc system, bigger than any tone rule.
210
+ 3. Tables for enumerable facts; prose only where reasoning is needed.
211
+ 4. Front-load: rule first, elaboration after — readers (human or agent) may only take the head.
212
+ 5. Define a term once, then reuse it verbatim. Synonyms read as new concepts to a machine.
213
+ 6. Headings and IDs (`ADR-NNN`, `T1`–`T8`, `§6.x`, feature rows) are grep targets and
214
+ cross-reference anchors — never rename casually.
215
+ 7. **Concise never beats correct.** If brevity creates ambiguity, add the missing words: tokens
216
+ saved in reading are lost many times over in a misexecuted run.
217
+
218
+ These rules are stated once, here. Per-file sections below and doc frontmatter inherit them via
219
+ pointer — restating them per file would violate rule 2.
220
+
221
+ ### 6.1 `docs/00_ADR.md`
222
+
223
+ Entry template:
224
+
225
+ ```markdown
226
+ ## ADR-NNN: <Decision title, outcome-shaped>
227
+
228
+ **Status:** Accepted | Accepted (design) | Superseded by ADR-MMM | Skipped · **Date:** YYYY-MM-DD
229
+
230
+ **Decision.** <What was decided — the smallest complete statement of the choice.>
231
+
232
+ **Why.** <One line. The single strongest reason.>
233
+
234
+ **Detail:** <pointer into 03/04/plans — depth never lives here.>
235
+ ```
236
+
237
+ 1. **One decision per entry.** If a draft contains a principle *and* a deferred design *and* a
238
+ mechanism choice *and* implementation tips — split it: decision(s) here, mechanism in `03`,
239
+ shapes in `04`, tips nowhere (they are implementation guidance, not decisions).
240
+ 2. **ADR = decision + one-line reason.** No Zod patterns, no lock details, no code idioms.
241
+ 3. **Append-only.** Never renumber, never delete, never rewrite history. Corrections are dated
242
+ `**Amendment (YYYY-MM-DD)**` blocks inside the entry; reversals are **new entries** that name
243
+ what they supersede, while the old entry's Status becomes `Superseded by ADR-MMM`.
244
+ 4. **Numbering:** next free integer, one sequence per repo. A burned/skipped number gets a stub
245
+ entry (`Status: Skipped`) so the gap is audit-clean and never reused.
246
+ 5. **`Accepted (design)`** means decided but not built — readers must be able to tell decided
247
+ from shipped.
248
+ 6. **Before any code that contradicts an ADR:** the superseding entry lands first (§5 row 2).
249
+ 7. **Retrofit rule:** the entry template binds **new entries and amendments only**. Historical
250
+ entries are never restructured to match it — append-only beats stylistic consistency. The
251
+ non-entry preamble is normal editable text.
252
+ 8. **Amendments record the decision delta.** An `**Amendment**` block records *what changed about the
253
+ decision* — the new choice and its one-line reason — plus a `Detail:` pointer for mechanism.
254
+ Implementation file paths, detailed semantics, and multi-paragraph rationale belong in `03`/`04`,
255
+ not in the amendment body. If an amendment would carry more than a few lines of non-decision text,
256
+ the mechanism has leaked in; link it instead of inlining it.
257
+
258
+ ### 6.2 `docs/01_PRD.md`
259
+
260
+ 1. Owns vision, users, principles, scope. **No mechanism** (→ `03`), **no timing** (→ `02`),
261
+ **no shapes** (→ `04`).
262
+ 2. **Every shipped surface has a scope row.** When a command/capability ships, its row enters
263
+ the in-scope table in the same change — shipped-but-unlisted is the most common drift.
264
+ 3. Scope states are explicit: *in (committed)* / *supporting* / *deferred (needs design
265
+ reconfirmation)* / *out of scope*. A deferred item carries the condition that would
266
+ reactivate it.
267
+ 4. Surface beyond the committed set is **not ported/built speculatively** — re-confirm the need
268
+ first and record the evidence pointer (a dated plans doc, usage data) in the entry that
269
+ admits it.
270
+ 5. **Scope tables carry membership only** — no delivery-status columns (`05` owns status; a
271
+ status column in `01` is a guaranteed drift magnet). Likewise, quantitative gate values
272
+ (coverage thresholds, etc.) live with their enforcement config — point to the gate, never
273
+ restate the numbers.
274
+
275
+ ### 6.3 `docs/02_ROADMAP.md`
276
+
277
+ 1. Derived: it may **sequence** facts from `00`/`01`/`05` but never introduce new ones.
278
+ 2. Every phase has a goal sentence, checkbox items, and an explicit **Exit:** criterion.
279
+ 3. Markers: `[x]` done · `[~]` partial · `[ ]` pending. `[x]`/`[~]` carry a one-line evidence
280
+ note (what shipped, where).
281
+ 4. When a deliverable lands under a different name than planned, rewrite the bullet to the real
282
+ name — a roadmap that tracks dead names reads as undelivered work.
283
+ 5. Phases gate on the previous one. Insert sub-phases (`1.5`) rather than renumbering existing
284
+ ones.
285
+
286
+ ### 6.4 `docs/03_ARCHITECTURE.md`
287
+
288
+ 1. Describes the **current** architecture. Future/accepted designs are allowed only in sections
289
+ explicitly titled `(accepted design — ADR-NNN; not yet built)`.
290
+ 2. Owns module boundaries, data flow, runtime model, invariants, and rationale-in-depth. Not
291
+ schemas/signatures (code and `04`), not decisions (`00`).
292
+ 3. Write invariants as **enforceable statements** — phrased so a constraint rule or a reviewer
293
+ can check them mechanically.
294
+ 4. When a migration replaces a mechanism (parser, dispatcher, bootstrap), update the module
295
+ descriptions in the same change — stale module lists survive multiple releases unnoticed.
296
+ 5. On conflict with `00`: the ADR wins; fix here and flag.
297
+
298
+ ### 6.5 `docs/04_DESIGN.md` + `docs/design/<slug>.md`
299
+
300
+ `04` is the **index page** over the `docs/design/` satellites (§4.5). The index carries the surface
301
+ map + pointers; each `docs/design/<slug>.md` holds one surface area's detailed design.
302
+
303
+ 1. **Same-commit rule:** any change to a command, flag, config key, env var, table, or DTO
304
+ updates `04` (and its satellite) in that commit (§5 T3/T9). In batch planning, doc sync is an
305
+ explicit scheduled item.
306
+ 2. **Detail-first edit order (§4.5 rule 5 / T9):** write or update the `docs/design/<slug>.md`
307
+ satellite first, then update its `04` index row — never the reverse. A new surface area gets a
308
+ new satellite + a new index row in the same change.
309
+ 3. Prefer **generated** artifacts over hand-maintained ones (e.g. OpenAPI from the contract);
310
+ never hand-write what can be derived — and never let a derivable artifact be edited by hand.
311
+ 4. Shapes only. Rationale lives in `00`/`03`. **Behavioral notes are shapes** ("resolving zero
312
+ rules exits 1" — keep); justifications are not ("...because a silent gate is the worst
313
+ failure mode" — cut, or point to `00`/`03`). This applies to satellites too — they hold
314
+ *detailed shapes*, not rationale.
315
+ 5. Command signatures are **transcribed from the code registrations**, never from memory or from
316
+ an older doc revision — a signature is a factual block in the §6.7 sense.
317
+ 6. The index never restates a satellite's body (§6.0 rule 2): an `04` row names the surface area,
318
+ its status, and points at `docs/design/<slug>.md`. `<slug>` is a stable grep anchor (§6.0 rule 6).
319
+
320
+ ### 6.6 `docs/05_FEATURES.md` + `docs/features/<feature-id>_<slug>.md`
321
+
322
+ `05` is the **index page** over the `docs/features/` satellites (§4.5). Both the satellites and `05`'s
323
+ generated index region are **tool-owned** (§3 — `spur feature`/`ftree`): edit through the tool, never
324
+ with raw file writes.
325
+
326
+ 1. One index row per deliverable, each with a concrete **acceptance** check, status from the legend
327
+ (✅ done · 🔶 partial · ⏳ planned · 💤 deferred), and a pointer to its
328
+ `docs/features/<feature-id>_<slug>.md` satellite.
329
+ 2. The satellite + its index row change in the **same change** that ships or re-scopes the feature
330
+ (§5 T4/T9).
331
+ 3. **Detail-first edit order (§4.5 rule 5 / T9):** update the feature satellite first (via the tool),
332
+ then refresh the index (e.g. `spur feature refresh`) — never hand-edit the generated index region,
333
+ and never update the index ahead of the detail.
334
+ 4. **Never trust a row you have not verified.** Before citing or building on a status, check it
335
+ against code — status rows rot silently in both directions (done-but-⏳ and ⏳-but-claimed).
336
+ 5. `05` keeps headline rows + pointers; the full decomposition lives in the satellite files.
337
+ `<feature-id>` is the stable grep anchor (§6.0 rule 6); renaming is a tool operation, not a raw
338
+ edit.
339
+
340
+ ### 6.7 `AGENTS.md`
341
+
342
+ 1. Factual blocks that mirror code — the command surface, the workspace layout, tool versions —
343
+ are **regenerated from code**, never edited from memory. Verify with the actual registrations
344
+ (e.g. list the CLI's registered nouns/verbs) before writing the block.
345
+ 2. Keep it lean: link to the owning doc instead of restating its facts. `AGENTS.md` repeats only
346
+ what an agent needs in the first 30 seconds of a session.
347
+ 3. Surfaces that are decided-but-unbuilt are flagged as planned with their ADR pointer, and
348
+ marked "do not invoke as if they exist".
349
+ 4. Re-synced whenever this file changes the map or process (§4.4).
350
+
351
+ ### 6.8 This file (`99`)
352
+
353
+ 1. **No project facts** — ever (§1). Tool bindings (§3) and Lessons (§8) are the only
354
+ project-variable content.
355
+ 2. Structure and principles change only on operator request; Lessons sections are
356
+ machine-appendable per the §8 protocol without asking.
357
+ 3. When this file improves in one project, **propagate the improvement to sibling projects** —
358
+ it is one constitution with N copies, not N constitutions.
359
+
360
+ ## 7. Drift control
361
+
362
+ **Drift** = reality (code, shipped behavior) disagreeing with what a key file says, or two key
363
+ files disagreeing with each other.
364
+
365
+ **Repair protocol** (always this order):
366
+
367
+ 1. Fix the **authoritative** doc — for append-only files, by dated amendment, never rewriting.
368
+ 2. Then the derived docs that restate or sequence it.
369
+ 3. Then `AGENTS.md`.
370
+ 4. Flag what drifted and why in the commit message / task — a silent fix hides the systemic
371
+ cause.
372
+
373
+ **Audit cadence:** at every phase exit, and before designing any large batch, run the drift
374
+ audit:
375
+
376
+ - [ ] List the real CLI/tool surface from code; diff against `AGENTS.md`'s surface block and
377
+ `00`'s committed-surface entries.
378
+ - [ ] For every `05` row marked ✅/🔶, spot-check the acceptance against code; for every ⏳, check
379
+ it didn't quietly ship.
380
+ - [ ] For every shipped surface, confirm a `01` scope row exists.
381
+ - [ ] Check `02`'s current phase bullets name things that actually exist (no dead names).
382
+ - [ ] Check `03`'s module descriptions against the real file tree of each app/package.
383
+ - [ ] Confirm `04` covers every command/flag/config/schema that exists.
384
+ - [ ] For `04`/`05` (§4.5): every index row points to an existing satellite, and every satellite
385
+ (`docs/design/<slug>.md`, `docs/features/<id>_<slug>.md`) has exactly one index row — no orphan
386
+ satellites, no dangling pointers.
387
+ - [ ] Confirm `AGENTS.md`'s doc map matches §4.1 of this file.
388
+ - [ ] Confirm each doc's frontmatter matches its §4.1 row and its `updated_at` is plausible
389
+ against recent commits (§4.3).
390
+
391
+ Findings are repaired via the protocol above, and anything systemic becomes a Lesson (§8) — or,
392
+ if it recurs, a new rule in §6.
393
+
394
+ ## 8. Lessons learned per file
395
+
396
+ **Append protocol (machine-maintained):**
397
+
398
+ - Format: `- [YYYY-MM-DD] <project>: <lesson — what went wrong / what to do instead>`
399
+ - Threshold is **low** — when in doubt, append. Check for an existing equivalent first; bump its
400
+ date instead of duplicating.
401
+ - **Promotion rule:** a lesson that recurs or hardens into practice is promoted into a §6 rule
402
+ (or a §5 trigger) and removed from this section. Lessons are the inbox; §5/§6 are the law.
403
+ Promotion is the only sanctioned deletion.
404
+ - Lessons carry project provenance because this file is copied across projects — a lesson from
405
+ one project is a warning, not yet a law, for the others.
406
+
407
+ ### Lessons for `docs/00_ADR.md`
408
+
409
+ _(empty — add lessons as the project evolves)_
410
+
411
+ ### Lessons for `docs/01_PRD.md`
412
+
413
+ _(empty — add lessons as the project evolves)_
414
+
415
+ ### Lessons for `docs/02_ROADMAP.md`
416
+
417
+ _(empty — add lessons as the project evolves)_
418
+
419
+ ### Lessons for `docs/03_ARCHITECTURE.md`
420
+
421
+ _(empty — add lessons as the project evolves)_
422
+
423
+ ### Lessons for `docs/04_DESIGN.md`
424
+
425
+ _(empty — add lessons as the project evolves)_
426
+
427
+ ### Lessons for `docs/05_FEATURES.md`
428
+
429
+ _(empty — add lessons as the project evolves)_
430
+
431
+ ### Lessons for `AGENTS.md`
39
432
 
40
- | Doc | Owns the question | Authority |
41
- |-----|-------------------|-----------|
42
- | `00_ADR.md` | **WHY** — decisions + one-line reason | Authoritative (wins all) |
43
- | `01_PRD.md` | **WHAT** — product vision, scope | Authoritative on scope |
44
- | `02_ROADMAP.md` | **WHEN** — phases, sequencing | Derived |
45
- | `03_ARCHITECTURE.md` | **HOW** — module boundaries, data flow | Derived |
46
- | `04_DESIGN.md` | **SURFACE** — commands, flags, schemas | Derived |
47
- | `05_FEATURES.md` | **STATUS** — feature decomposition + state | Derived |
48
- | `99_PROJECT_CONSTITUTION.md` | **PROCESS** — how files are maintained | Authoritative on process |
433
+ _(empty add lessons as the project evolves)_
49
434
 
50
- ## 4. Sync triggers
435
+ ### Lessons for this file (`99`)
51
436
 
52
- When a change touches one of these, the listed doc MUST be updated in the **same commit**:
437
+ _(empty add lessons as the project evolves)_
53
438
 
54
- | ID | Trigger | Doc(s) |
55
- |----|---------|--------|
56
- | T1 | New cross-cutting decision (entry = decision + one-line reason; amendment = decision delta only — mechanism goes in `03`/`04`, not the amendment) | `00` first, then `03` mechanism |
57
- | T3 | Command/flag/config/schema/DTO added/changed | `04` + `AGENTS.md` |
58
- | T4 | Feature ships or changes state | `05` row |
59
- | T6 | Scope added / cut / deferred | `01` |
439
+ ## 9. Bootstrapping a new project
60
440
 
61
- ## 5. Lessons
441
+ Checklist to instantiate this structure in a fresh repo:
62
442
 
63
- | Date | Lesson |
64
- |------|--------|
65
- | 1970-01-01 | _(empty add lessons as the project evolves)_ |
443
+ 1. Copy this file verbatim to `docs/99_PROJECT_CONSTITUTION.md`; empty the §8 lessons of
444
+ other projects' entries or keep them as inherited warnings (recommended: keep).
445
+ 2. Update §3 bindings if the new project's toolchain differs.
446
+ 3. Create `docs/00_ADR.md` with the §4.3 frontmatter and `ADR-001` recording the founding
447
+ decision (stack, structure, the why).
448
+ 4. Create `docs/01_PRD.md`: vision paragraph, users, principles table, scope tables (in /
449
+ supporting / deferred / out).
450
+ 5. Create `docs/02_ROADMAP.md` with Phase 0 and its exit criterion.
451
+ 6. Create `docs/03_ARCHITECTURE.md`: topology, dependency boundary, runtime model — current
452
+ state only.
453
+ 7. Create `docs/04_DESIGN.md` (may start near-empty) and `docs/05_FEATURES.md` (legend + first
454
+ rows).
455
+ 8. Create root `AGENTS.md`: instantiated §4.1 doc map, stack/layout, commands, verification
456
+ gate, conventions. Symlink `CLAUDE.md` (and equivalents) to it.
457
+ 9. Wire the §3 tools (spec lifecycle, harness) per their own docs.
458
+ 10. First-session rule for any agent: read `AGENTS.md` → this file → `00`/`01` before touching
459
+ anything.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/spur",
3
- "version": "0.3.19",
3
+ "version": "0.3.21",
4
4
  "description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
5
5
  "keywords": [
6
6
  "spur",
package/spur.js CHANGED
@@ -74710,7 +74710,7 @@ import { join as join15, resolve as resolve5 } from "path";
74710
74710
  var CLI_CONFIG = {
74711
74711
  binaryName: "spur",
74712
74712
  binaryLabel: "spur",
74713
- binaryVersion: "0.3.19",
74713
+ binaryVersion: "0.3.21",
74714
74714
  configDir: ".spur",
74715
74715
  configFile: ".spur/config.yaml",
74716
74716
  databaseFile: ".spur/spur.db"
@@ -74770,6 +74770,10 @@ function substituteAgentsMdTemplate(content, projectName) {
74770
74770
  const description = "local Spur project";
74771
74771
  return content.replaceAll("{project-name}", projectName).replaceAll("{project-description}", description);
74772
74772
  }
74773
+ function substituteDocTemplateTokens(content, date6 = new Date) {
74774
+ const dateStr = date6.toISOString().slice(0, 10);
74775
+ return content.replaceAll("{{init-date}}", dateStr);
74776
+ }
74773
74777
  var INDEXED_CONTEXT_BLOCK = `
74774
74778
  ---
74775
74779
 
@@ -74908,6 +74912,8 @@ ${contextEntry}
74908
74912
  const configRoot = bundledConfigRoot();
74909
74913
  if (configRoot !== null) {
74910
74914
  for (const relPath of listBundledProjectSeedFiles()) {
74915
+ if (relPath.startsWith("templates/docs/"))
74916
+ continue;
74911
74917
  const sourcePath = join15(configRoot, relPath);
74912
74918
  if (!await context4.fs.exists(sourcePath))
74913
74919
  continue;
@@ -74927,6 +74933,9 @@ ${contextEntry}
74927
74933
  if (entry.target === "AGENTS.md") {
74928
74934
  body = substituteAgentsMdTemplate(body, projectName);
74929
74935
  }
74936
+ if (entry.source.startsWith("templates/docs/")) {
74937
+ body = substituteDocTemplateTokens(body);
74938
+ }
74930
74939
  await writeIfNew(context4, targetPath, body, entryForce, result);
74931
74940
  }
74932
74941
  }
@@ -84577,7 +84586,7 @@ async function runStatusCore(path9, options, context4) {
84577
84586
  ]);
84578
84587
  const target = path9 === undefined ? undefined : await readTargetStatus(context4, path9);
84579
84588
  const status = {
84580
- ok: packageJsonExists,
84589
+ ok: spurConfigExists,
84581
84590
  packageJson: packageJsonExists,
84582
84591
  spurConfig: spurConfigExists,
84583
84592
  git,
@@ -84588,8 +84597,8 @@ async function runStatusCore(path9, options, context4) {
84588
84597
  context4.output.write(toJson2(status));
84589
84598
  } else {
84590
84599
  context4.output.write([
84591
- `Project: ${status.ok ? "ok" : "missing package.json"}`,
84592
- `.spur: ${spurConfigExists ? "ok" : "missing"}`,
84600
+ `Project: ${spurConfigExists ? "ok" : "missing .spur/config.yaml"}`,
84601
+ `Package: ${packageJsonExists ? "ok" : "none"}`,
84593
84602
  `Agents: ${agentSpecs.length === 0 ? "none" : agentSpecs.join(", ")}`,
84594
84603
  `Git: ${git.root === null ? "none" : `${git.branch ?? "detached"}${git.dirty ? " dirty" : " clean"}`}`,
84595
84604
  ...target === undefined ? [] : [`Path: ${target.path} ${target.size} bytes`]