forge-orkes 0.79.0 → 0.80.0

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.
Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/template/.claude/hooks/forge-context-migrate.sh +297 -0
  3. package/template/.claude/hooks/forge-size-gate.sh +175 -0
  4. package/template/.claude/hooks/forge-state-rollup.sh +135 -2
  5. package/template/.claude/hooks/skill-gate-tiers.txt +6 -0
  6. package/template/.claude/hooks/tests/forge-context-migrate.test.sh +166 -0
  7. package/template/.claude/hooks/tests/forge-size-gate.test.sh +132 -0
  8. package/template/.claude/settings.json +5 -1
  9. package/template/.claude/skills/discussing/SKILL.md +30 -31
  10. package/template/.claude/skills/executing/SKILL.md +3 -3
  11. package/template/.claude/skills/forge/SKILL.md +112 -170
  12. package/template/.claude/skills/forge/references/manual-fallback-procedures.md +54 -0
  13. package/template/.claude/skills/planning/SKILL.md +11 -9
  14. package/template/.claude/skills/researching/SKILL.md +2 -0
  15. package/template/.claude/skills/verifying/SKILL.md +2 -2
  16. package/template/.forge/FORGE.md +79 -91
  17. package/template/.forge/checks/forge-jarvis-awareness.sh +46 -2
  18. package/template/.forge/checks/forge-jarvis-relay.sh +64 -16
  19. package/template/.forge/checks/tests/forge-jarvis-awareness.test.sh +58 -0
  20. package/template/.forge/checks/tests/forge-jarvis-relay.test.sh +50 -0
  21. package/template/.forge/migrations/0.80.0-context-md-sharding.md +158 -0
  22. package/template/.forge/migrations/0.80.0-size-gate-wiring.md +145 -0
  23. package/template/.forge/templates/constitution.md +1 -1
  24. package/template/.forge/templates/context-milestone.md +30 -0
  25. package/template/.forge/templates/slice-runner/config.yml +7 -1
@@ -31,20 +31,22 @@ If you find yourself writing a plan that only touches `src/models/`, `src/db/`,
31
31
 
32
32
  ## Step 1: Resolution Gate
33
33
 
34
- Read `.forge/context.md` **Needs Resolution**. If unchecked `- [ ]` items:
34
+ Read `.forge/context-log.md` **Needs Resolution** (Needs Resolution is not milestone-scoped — it lives in the log, not a per-milestone file). If unchecked `- [ ]` items:
35
35
  *"{N} items need input: [list]. For each: lock, defer, fix, or drop?"*
36
36
 
37
- Load `.forge/context.md` as the active decision set. Consult
37
+ Load `.forge/context/{id}.md` as the active decision set for milestone `{id}`. Consult
38
38
  `.forge/context-archive.md` only when the current milestone, stream, or
39
39
  requirement cites an older milestone decision (for example M9 e2e policy or M14
40
- backlog lifecycle). Do not load archived decision blocks wholesale.
40
+ backlog lifecycle) — check `.forge/context.md` (the derived index) first; if the
41
+ cited milestone has a row there, read its `context/{id}.md` directly instead of
42
+ the archive. Do not load archived decision blocks wholesale.
41
43
 
42
44
  | Choice | Action |
43
45
  |--------|--------|
44
46
  | Lock | Record in Locked Decisions |
45
47
  | Defer | Move to Deferred Ideas + revisit date |
46
48
  | Fix | Add as FR-xxx in `.forge/requirements/m{N}.yml` (current milestone) |
47
- | Drop | Note in Amendment Log |
49
+ | Drop | Note in Amendment Log (`.forge/context-log.md`) |
48
50
 
49
51
  Mark resolved `- [x]`. Target: 2-5 min.
50
52
  Scan **Carried Forward** -- items affecting current phase get same triage.
@@ -60,17 +62,17 @@ Record results in plan frontmatter.
60
62
 
61
63
  ## Step 3: Lock Decisions
62
64
 
63
- If missing, create `.forge/context.md` from template:
65
+ If missing, create `.forge/context/{id}.md` from `.forge/templates/context-milestone.md`:
64
66
  1. Ask user key decisions (framework, constraints, preferences)
65
67
  2. **Locked Decisions** (contracts)
66
68
  3. **Deferred Ideas** (out of scope)
67
69
  4. **Discretion Areas** (agent picks)
68
70
 
69
- Must complete BEFORE plans. Plans reference context.md.
71
+ Must complete BEFORE plans. Plans reference context/{id}.md.
70
72
 
71
73
  If a plan depends on an archived decision, cite the archive section in the plan
72
74
  or active context summary; do not copy the historical block back into
73
- `.forge/context.md`.
75
+ `.forge/context/{id}.md`.
74
76
 
75
77
  ## Step 4: Structure Requirements
76
78
 
@@ -396,7 +398,7 @@ Prompt pattern:
396
398
  > *"UI work detected. Invoke `testing` skill for e2e/integration coverage? (yes/no/later)"*
397
399
 
398
400
  - **yes** — defer to `testing` after planning completes; note in plan frontmatter
399
- - **no** — document rationale in `context.md` Discretion Areas
401
+ - **no** — document rationale in `context/{id}.md` Discretion Areas (or `context/_shared.md` if cross-cutting)
400
402
  - **later** — rides on the verifying **Interface Testing Gate**: when `interface` is declared in `project.yml`, that gate already BLOCKS at verifying if UI tests are still missing (no separate planning hook needed)
401
403
 
402
404
  Decision captured once, pre-code. Does not block planning.
@@ -472,7 +474,7 @@ Done when approved.
472
474
 
473
475
  ## Handoff
474
476
 
475
- 1. **Persist** -- plans `.forge/phases/`, reqs `.forge/requirements/m{N}.yml`, roadmap `.forge/roadmap.yml`, context `.forge/context.md`
477
+ 1. **Persist** -- plans `.forge/phases/`, reqs `.forge/requirements/m{N}.yml`, roadmap `.forge/roadmap.yml`, context `.forge/context/{id}.md`
476
478
  2. **Reserve version (if delivery bumps the version)** -- if any plan in this milestone will bump `package.json`/the project version: pull first, derive `version` = highest reserved `max()` bumped by this change's semver level, then **claim it in the ledger BEFORE editing releases.yml**: `.claude/hooks/forge-reserve.sh version --value <X.Y.Z> --milestone m-{N}` — a non-zero exit names the sibling milestone already holding that number (its reservation may be worktree-only and invisible in any file you can read): re-read `max()` counting the ledger's version claims and bump again (ADR-029). Then append ONE entry to `.forge/releases.yml` (Version Reservation Protocol, FORGE.md): `{milestone, version, bump, reserved_at, summary}`. **Never edit prior entries.** No version bump in scope → skip. Surface the reserved number to the user.
477
479
  3. **State** -- `current.status` = `executing` in `.forge/state/milestone-{id}.yml`
478
480
  4. **State-sync commit** (State Commit Protocol): `git -C {worktree_path} add .forge/` then `git -C {worktree_path} commit -m "chore(forge): sync state after planning — m{N} {phase-name}"` (worktree form — recorded `lifecycle.worktree_path` is authoritative over cwd; see FORGE.md State Commit Protocol. Scoped; never `git add .`). The `releases.yml` reservation rides in this commit — **push it** so a parallel session sees the number taken before they reserve.
@@ -9,6 +9,8 @@ Gather context before planning. Bad research leads to bad plans.
9
9
 
10
10
  > Entered via a worktree already, for new work (R10, `forge/SKILL.md` Step 3) — research writes `.forge/research/` state, so if this skill is somehow invoked directly on the main checkout for new work, enter one now before writing anything.
11
11
 
12
+ If resuming research on an existing milestone, skim `.forge/context/{id}.md` first (if present) — decisions already locked there are out of scope for research now; don't re-investigate what's already settled.
13
+
12
14
  ## Research Types
13
15
 
14
16
  ### 1. Codebase Research
@@ -19,7 +19,7 @@ After `/clear`, load with fresh eyes — don't carry the executor's assumptions:
19
19
  Read: .forge/state/milestone-{id}.yml → current phase, plans completed
20
20
  Read: .forge/project.yml → tech stack (for running tests)
21
21
  Read: .forge/phases/milestone-{id}/{phase}-{name}/plan-{NN}.md → must_haves (truths, artifacts, key_links)
22
- Read: .forge/context.md → locked decisions
22
+ Read: .forge/context/{id}.md → locked decisions for this milestone
23
23
  Read: .forge/requirements/m{N}.yml → requirement IDs for coverage check (current milestone, resolved from state)
24
24
  Read: .forge/deferred-issues/*.md → known pre-existing failures (glob the dir; else legacy .forge/deferred-issues.md; advisory)
25
25
  ```
@@ -295,7 +295,7 @@ After verification completes (PASSED or GAPS FOUND), run a quick retrospective o
295
295
 
296
296
  **6. User corrections**: User correct the same thing multiple times? Implicit rules that should become explicit.
297
297
 
298
- **Set `scope` on each observation** (see ADR-012): `framework` when the fix targets Forge's own skills/templates (tier heuristics, a skill's step, a template); `project` when it targets user-owned files (`constitution.md`, `design-system.md`, `context.md`). Record `suggestion_target` when known. This classifies the signal at write time so review can route `framework` signals upstream. Tier-override signals (#2) and the "constitution needs a new article" deviation case (#1) are usually `framework` and `project` respectively — judge by the file the fix touches, not the type.
298
+ **Set `scope` on each observation** (see ADR-012): `framework` when the fix targets Forge's own skills/templates (tier heuristics, a skill's step, a template); `project` when it targets user-owned files (`constitution.md`, `design-system.md`, `context/{id}.md`). Record `suggestion_target` when known. This classifies the signal at write time so review can route `framework` signals upstream. Tier-override signals (#2) and the "constitution needs a new article" deviation case (#1) are usually `framework` and `project` respectively — judge by the file the fix touches, not the type.
299
299
 
300
300
  **Surfacing is owned by `forge` boot — not here** (single review owner, ADR-012). `verifying` only *records* observations; it does not surface recommendations, prompt for fixes, or archive. The 3+ aggregation, the type→evolution suggestion table, the decline-ledger, and upstream routing all live in `forge` Step 1.2. Write the observation files (with `scope`) and move on — the next `forge` boot reviews them.
301
301
 
@@ -1,17 +1,15 @@
1
1
  # Forge
2
2
 
3
- Lean meta-prompting framework. Context engineering + constitutional governance on agent-native primitives. This file is the always-loaded **routing/index layer**: tables, invariants, and pointers. Procedures live in the skills that execute them; rationale lives in ADRs — both load only on demand.
3
+ Lean meta-prompting framework. Context engineering + constitutional governance on agent-native primitives. This file is the always-loaded **routing/index layer**: tables, invariants, pointers. Procedures live in the skills that execute them; rationale lives in ADRs — both load on demand only.
4
4
 
5
5
  ## Critical: No Native Plan Mode
6
6
 
7
- **NEVER use `EnterPlanMode` when Forge active.** Forge writes plans to `.forge/phases/` — native plan mode conflicts.
8
-
9
- All phases: **invoke via `Skill` tool**, never native behavior. `planning` → `Skill(planning)`, not `EnterPlanMode`.
7
+ **NEVER use `EnterPlanMode` when Forge active.** Forge writes plans to `.forge/phases/` — native plan mode conflicts. All phases: invoke via `Skill` tool, e.g. `planning` → `Skill(planning)`, not `EnterPlanMode`.
10
8
 
11
9
  ## Core Principles
12
10
 
13
11
  1. **Lean default, powerful when needed.** Quick → skip ceremony. Complex → full governance.
14
- 2. **Adapter-native.** Use each platform's built-ins through adapters. Avoid custom runtime unless the substrate truly needs it.
12
+ 2. **Adapter-native.** Use each platform's built-ins through adapters; avoid custom runtime unless the substrate needs it.
15
13
  3. **Context is sacred.** Size-gate artifacts, lazy-load skills, fresh agents for isolated work.
16
14
  4. **Decisions are contracts.** Lock before building. Honor or flag — never silently override.
17
15
  5. **Verify goals, not tasks.** "Does it work?" > "Did we finish checklist?"
@@ -21,7 +19,7 @@ All phases: **invoke via `Skill` tool**, never native behavior. `planning` → `
21
19
 
22
20
  ## Core Protocol And Adapters
23
21
 
24
- **Core protocol** lives in `.forge/`: project/constitution state, milestones, requirements, roadmap, context, streams, work packages, plans, verification, audits, and state ownership rules — durable behavior, not one platform's tool names. **Platform adapters** translate the protocol into a runtime (Claude Code skills/hooks, Codex/AGENTS behavior, manual multi-session handoffs). Adapter mechanics stay in adapter files and skills; they do not become core requirements.
22
+ **Core protocol** lives in `.forge/`: project/constitution state, milestones, requirements, roadmap, context, streams, work packages, plans, verification, audits, state ownership rules — durable behavior, not one platform's tool names. **Platform adapters** translate the protocol into a runtime (Claude Code skills/hooks, Codex/AGENTS behavior, manual handoffs) and stay out of core requirements.
25
23
 
26
24
  ## Project Streams
27
25
 
@@ -33,18 +31,16 @@ Three runtime coordination layers: Project, Stream, Work Package.
33
31
  | **Stream** | One active line of work: goal, branch/worktree, state, blockers, next action | `.forge/streams/{stream}.yml` + `brief.md` |
34
32
  | **Work Package** | Delegated bounded task inside a stream | `.forge/streams/{stream}/packages/{id}.yml` |
35
33
 
36
- Ordinary Quick/Standard/Full tiers run inside a stream. Project Chief / Chief of Staff coordinates multiple active streams or pivots without dropping context. Workers never coordinate laterally; they report to the stream or project chief. M10 worktrees are an optional isolation backend, not the primary UX.
34
+ Ordinary Quick/Standard/Full tiers run inside a stream; Project Chief / Chief of Staff coordinates multiple active streams or pivots without dropping context. Workers report to the stream or project chief, never laterally. M10 worktrees are an optional isolation backend, not the primary UX.
37
35
 
38
- **Merge often and early.** Integrate ready work **as soon as it is ready**, not at milestone end long-lived stream branches drift and the merge grows riskier the longer it waits. Realized producer-side (checkpoint publishing, below) and project-side (the Chief's Merge Cadence Check). Forge never force-pushes, never auto-resolves a conflict, and never auto-rebases.
36
+ **Merge often and early** integrate ready work as soon as it is ready, not at milestone end (long-lived branches drift, merges grow riskier). Realized producer-side (checkpoint publishing, below) + project-side (the Chief's Merge Cadence Check). Forge never force-pushes, auto-resolves a conflict, or auto-rebases.
39
37
 
40
38
  ### Stream Integration Checkpoints
41
39
 
42
- Event-driven continuous integration. **Mechanism + rationale: [ADR-027](../docs/decisions/ADR-027-integration-checkpoints-declaration-split.md).** Producer implementation: `verifying` (Integration Checkpoint Publish). Consumer: `forge` boot (Step 1 preflight). In brief:
40
+ Event-driven continuous integration ([ADR-027](../docs/decisions/ADR-027-integration-checkpoints-declaration-split.md)). Producer: `verifying` (Integration Checkpoint Publish). Consumer: `forge` boot (Step 1 preflight).
43
41
 
44
- - **Checkpoints are plan-marked** (`integration_checkpoint: true` in plan frontmatter; planning proposes last phase + depended-on phases the operator confirms). **The mark is the opt-in**: unmarked plans never auto-publish.
45
- - **Producer:** on a checkpoint phase's verified PASS in a worktree session, fast-forward-only publish (`git push origin HEAD:main`), **strand-guarded** — publish only when local `main` is an ancestor of the worktree HEAD; stranded do not push, surface "integrate through local main first" (forge#13). On success, set the **integration flag** — `.git/forge/integration-pending` in the machine-local git common dir.
46
- - **Intake (declaration split, B3'):** a new milestone/stream's **first** worktree commit is a declaration — milestone id (+ reservation), one-line intent, stream registration with `ownership` claims — ff-pushed to main immediately; content stays worktree-only until the milestone's own checkpoint. One-breath rule: main knows THAT work exists; the worktree knows WHAT it is.
47
- - **Consumer:** boot reads the flag (absent or already-seen → skip; no fetch, no scan). Clean fast-forwards run automatically in worktrees **and** the primary main checkout; any divergence surfaces a prompt — never an auto-rebase. Cross-machine, the flag doesn't exist — the opt-in `forge.worktree_rebase_check` / periodic fetch covers it, eventually.
42
+ - **Producer:** plan-marked checkpoints (`integration_checkpoint: true`, operator-confirmed) fast-forward-push on a worktree's verified PASS, strand-guarded (push only if local `main` is an ancestor of HEAD; stranded "integrate through local main first", forge#13), then set the machine-local integration flag. A stream's first worktree commit is a lighter declaration-only push (id + intent) so main knows work exists before content lands.
43
+ - **Consumer:** boot reads the flag (absent/seen skip, no fetch); clean fast-forwards run automatically, any divergence prompts never auto-rebase. Cross-machine: opt-in `forge.worktree_rebase_check`.
48
44
 
49
45
  ### Worktree Convention (base)
50
46
 
@@ -68,9 +64,9 @@ Where worktrees live and what they're named — single source of truth, base con
68
64
  Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
69
65
 
70
66
  ### Prototyping (minutes–hours, disposable)
71
- **Triggers:** "mock up"/"sketch"/"prototype"/"draw up"/"iterate on the UI"/"explore how X could look" — disposable in-app visual exploration behind an alpha/feature flag, no requirements locked yet
67
+ **Triggers:** disposable in-app visual exploration ("mock up", "sketch", "prototype", "explore how X could look") behind an alpha/feature flag, no requirements locked yet
72
68
  **Flow:** `prototyping` — establish flag → iterate ⟲ (render → react → adjust) → resolve (graduate→milestone | park | discard)
73
- **No verify/review gate by design** — the deliverable is a thing to look at and react to, not shippable code. Real UI work with known requirements is Standard + `designing` (which *does* gate on quality). See [ADR-022](../docs/decisions/ADR-022-prototyping-tier.md).
69
+ **No verify/review gate by design** — a thing to look at and react to, not shippable code. Real UI work with known requirements is Standard + `designing` (which *does* gate on quality). See [ADR-022](../docs/decisions/ADR-022-prototyping-tier.md).
74
70
 
75
71
  ### Quick (minutes)
76
72
  **Triggers:** bug fix, typo, config, dep bump, <50 lines
@@ -91,29 +87,27 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
91
87
 
92
88
  ## Skill Routing
93
89
 
94
- | Need to... | Skill | Tier |
95
- |------------|-------|------|
96
- | Start any task | `forge` | All |
97
- | Set up new project | `initializing` | First run |
98
- | Investigate codebase/tech/requirements | `researching` | Standard, Full |
99
- | Talk through approach/trade-offs | `discussing` | Standard, Full (on-demand) |
100
- | Architectural decisions | `architecting` | Full |
101
- | Break work into tasks with gates | `planning` | Standard, Full |
102
- | Build with deviation rules + atomic commits | `executing` | All |
103
- | Prove work delivers on goals (+ M9 e2e validation gate; captures the Human Verification Gate sign-off) | `verifying` | Standard, Full |
104
- | Audit health + catalog refactoring (+ M9 e2e audits; hard-blocks completion on the Human Verification Gate) + close-the-loop (surface resolved-but-open issues) | `reviewing` | Standard, Full |
105
- | Small scoped fix | `quick-tasking` | Quick |
106
- | Rapid disposable UI mockup behind an alpha flag (no verify/review gate) | `prototyping` | Prototyping |
107
- | UI with design system | `designing` | When UI |
108
- | Security review | `securing` | When auth/data/API |
109
- | E2E/integration tests + suite audit (+ M9 author-mode gate) | `testing` | When UI/flows or flaky suite |
110
- | Systematic debugging | `debugging` | When stuck |
111
- | Upgrade Forge files from the npm registry (default; local dev sync only via explicit `/upgrading dev`) | `upgrading` | On-demand |
112
- | Cross-session memory | `beads-integration` | When Beads installed |
113
- | Project/read Forge work in Notion | `notion-integration` | When Notion configured |
114
- | Multi-agent backend (experimental) | `orchestrating` | Optional, usually selected by Chief/Streams |
115
-
116
- > Experimental skills require opt-in install — see `packages/create-forge/experimental/m10/README.md`.
90
+ | Need to... | Skill |
91
+ |------------|-------|
92
+ | Start any task | `forge` |
93
+ | First-run project setup | `initializing` |
94
+ | Investigate before building | `researching` |
95
+ | Talk through trade-offs | `discussing` |
96
+ | Architectural decisions | `architecting` |
97
+ | Break work into gated tasks | `planning` |
98
+ | Build with deviation rules + atomic commits | `executing` |
99
+ | Prove goals delivered (+ M9 e2e gate; see Human Verification Gate) | `verifying` |
100
+ | Health/security/refactor gate + close-the-loop | `reviewing` |
101
+ | Small scoped fix | `quick-tasking` |
102
+ | Disposable UI mockup behind an alpha flag | `prototyping` |
103
+ | UI with design system | `designing` |
104
+ | Security review | `securing` |
105
+ | E2E/integration tests + suite audit (+ M9 author-mode gate) | `testing` |
106
+ | Systematic debugging | `debugging` |
107
+ | Upgrade Forge files (registry default; `/upgrading dev` for local sync) | `upgrading` |
108
+ | Cross-session memory | `beads-integration` |
109
+ | Project/read Forge work in Notion | `notion-integration` |
110
+ | Multi-agent backend (experimental — see `packages/create-forge/experimental/m10/README.md`) | `orchestrating` |
117
111
 
118
112
  ## Context Engineering
119
113
 
@@ -125,7 +119,7 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
125
119
  | `requirements/m{N}.yml` | 50 KB/file | Prevents scope creep |
126
120
  | `plan.md` | 30 KB | Keeps executor context <50% |
127
121
  | `constitution.md` | 10 KB | Gates must be scannable |
128
- | `context.md` | 12 KB | Active decisions only; history archives to `context-archive.md` |
122
+ | `context.md` | 12 KB | Derived index, rendered fresh every boot — one row per milestone, pointing at `context/{id}.md` (full decisions live there, single-owner-mutable) |
129
123
  | `refactor-backlog.yml` | 150 KB | Terminal items archive to `refactor-backlog-archive.yml` (advisory) |
130
124
  | `streams/active.yml` | 20 KB | Traffic map must stay cheap to load |
131
125
  | `streams/{stream}.yml` | 15 KB | Stream state stays resumable without becoming history |
@@ -136,90 +130,84 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
136
130
 
137
131
  ### Accumulating Artifacts
138
132
 
139
- Every new accumulating artifact declares: owner, size gate, archive/compaction rule, `derived` vs source-of-truth status, and migration behavior. Defaults: `roadmap.yml`, `requirements/*.yml`, `releases.yml`, `reservations.yml` are source-of-truth — load scoped slices, not whole history. `phases/`, `audits/`, `research/`, `archive/`, `context-archive.md`, `reservations-archive.yml` are historical — load only by milestone/stream/package/version (R104: `reservations-archive.yml` holds every row `forge-reserve compact` has dropped from `reservations.yml`, verbatim; the working file alone still carries every kind's floor). `prototypes/{slug}.md` is single-owner mutable while `exploring|parked`; terminal statuses archive to `prototypes/archive/`. Runtime/generated files (`.mcp-server/*.db*`, logs, spike DBs, `.git/forge/*`) are excluded from framework context unless debugging them. The board (ADR-025): `.forge/notion/map.yml` is derived, git-ignored, rebuildable; board config is the `board:` block in `project.yml` (absent ⇒ inert). Template copies sync mechanically — not separate concepts.
133
+ Every new accumulating artifact declares owner, size gate, archive/compaction rule, `derived` vs source-of-truth status, migration behavior. `roadmap.yml`, `requirements/*.yml`, `releases.yml`, `reservations.yml` are source-of-truth — load scoped slices, not whole history. `phases/`, `audits/`, `research/`, `archive/`, `context-archive.md`, `reservations-archive.yml` are historical — load only by milestone/stream/package/version (R104: `reservations-archive.yml` holds every row `compact` dropped; the working file keeps each kind's floor). `prototypes/{slug}.md` is single-owner while `exploring|parked`; terminal `prototypes/archive/`. Runtime/generated files (`.mcp-server/*.db*`, logs, spike DBs, `.git/forge/*`) are excluded unless debugging. Board (ADR-025): `.forge/notion/map.yml` is derived; config is `board:` in `project.yml` (absent ⇒ inert). Template copies sync mechanically.
140
134
 
141
135
  ### Fresh Agent Pattern
142
- Task touches 20+ files or complex subsystem → spawn fresh executor with isolated context. Prevents context rot.
136
+ 20+ files or a complex subsystem → spawn a fresh executor with isolated context. Prevents context rot.
143
137
 
144
138
  ### Context Handoff
145
- Each phase writes outputs to `.forge/` before completing. At phase boundaries, recommend `/clear`; the next phase loads from disk. Advisory — skip for short phases under 40% context.
139
+ Each phase writes outputs to `.forge/` before completing; at boundaries recommend `/clear`, next phase loads from disk. Advisory — skip under 40% context.
146
140
 
147
141
  ### Lazy Loading
148
- Skills load only when invoked. Active context is `.forge/context.md`; consult `.forge/context-archive.md` only when older decisions matter.
142
+ Skills load only when invoked. `.forge/context.md` is a derived index (id/name/status/path per milestone) — consult it for orientation, then read the specific `context/{id}.md` when a milestone's actual decisions are needed. `context-archive.md` predates this model and is superseded (its content lives in `context/{id}.md` now); consult it only for pre-0.80.0 history not yet folded in.
149
143
 
150
144
  ### Rules Layer (`.claude/rules/`)
151
- Three policy weights, lightest-first (ADR-018): **`constitution.md`** (always-loaded hard gates, 10 KB) → **`.claude/rules/`** (lightweight ambient guidance — always-on, or path-scoped via `paths:` glob at zero cost until a matching file is touched) → **skills** (heavy, opt-in). Core ships one always-on rule, `agent-discipline.md`; stack-specific rules are opt-in (`experimental/conventions/`). Format + authoring: `.claude/rules/README.md` (itself always loaded).
145
+ Three policy weights, lightest-first (ADR-018): `constitution.md` (always-loaded hard gates, 10 KB) → `.claude/rules/` (ambient guidance — always-on, or path-scoped via `paths:` glob at zero cost until a matching file is touched) → skills (heavy, opt-in). Core ships one always-on rule, `agent-discipline.md`; stack-specific rules are opt-in (`experimental/conventions/`). Format + authoring: `.claude/rules/README.md`.
152
146
 
153
147
  ## Model Routing
154
148
 
155
- Configured in `project.yml` under `models:` — `default`, `parent_session` (advisory), `by_complexity.{trivial|standard|complex}` (per-task, M24), `skills.{name}` (per-skill).
149
+ Configured in `project.yml` under `models:` — `default`, `parent_session` (advisory), `by_complexity.{trivial|standard|complex}` (per-task), `skills.{name}` (per-skill).
156
150
 
157
- **Precedence:** `by_complexity.{task.complexity}` → `skills.X` → `default` → parent model. **Complexity overrides skill** (LOCKED, context.md § M24): a task's `by_complexity` resolution wins over `models.skills.{skill}` the per-task signal is the granular one; a task with no complexity resolves via the unchanged chain, zero behavior change untagged.
151
+ **Precedence:** `by_complexity.{task.complexity}` → `skills.X` → `default` → parent model. **Complexity overrides skill** (LOCKED, `context.md` § M24) — a task with no complexity resolves via the unchanged chain, zero behavior change untagged.
158
152
 
159
- **All advisory** — forge displays the expected model at each transition and suggests `/model` on mismatch; the review gate logs the model used. Forge cannot auto-switch models.
153
+ **All advisory** — forge displays the expected model at each transition, suggests `/model` on mismatch; the review gate logs the model used. Forge cannot auto-switch models.
160
154
 
161
- **Subagent inheritance.** A skill spawning subagents MUST pass the resolved `model` param explicitly — subagents do NOT inherit skill-level routing (without the param they run on the parent model, defeating the routing intent). Resolve **per task** where the task declares `complexity`, else the skill chain; surface *"Spawning {role} with model: {model} (from {source})"*. An inline task inherits the session model and cannot be re-routed.
155
+ **Subagent inheritance.** A skill spawning subagents MUST pass the resolved `model` param explicitly — subagents do NOT inherit skill-level routing. Resolve per task where it declares `complexity`, else the skill chain; surface *"Spawning {role} with model: {model} (from {source})"*. An inline task inherits the session model.
162
156
 
163
- **Spawn gate — predicate A (LOCKED, context.md § M24; refined m-33).** Executing's mandatory spawn on a complexity-tagged task fires **only when the resolved model differs from the live session model**. Resolved == live always the case with no `models:` block makes the spawn a pure no-op, so the tag becomes a context signal only (spawn iff a context trigger independently fires). WHY: an unconditional spawn burned ~315k subagent tokens on m-30 for zero routing benefit.
157
+ **Spawn gate — predicate A (LOCKED, `context.md` § M24; refined m-33).** Executing's mandatory spawn on a complexity-tagged task fires only when the resolved model differs from the live session model resolved == live (always true with no `models:` block) makes the spawn a no-op, so the tag becomes a context signal only.
164
158
 
165
159
  ## Agents
166
160
 
167
161
  | Agent | Role | Tools | When |
168
162
  |-------|------|-------|------|
169
- | `researcher` | Investigation | Read-only (Read, Glob, Grep, WebFetch) | Research |
170
- | `planner` | Planning + constitutional gates | Read + Write (plan files) | Planning |
163
+ | `researcher` | Investigation | Read-only | Research |
164
+ | `planner` | Planning + constitutional gates | Read + Write (plans) | Planning |
171
165
  | `executor` | Building + deviation rules | All dev tools | Execution |
172
166
  | `verifier` | Goal-backward verification | Read + Bash (tests) | Verification |
173
- | `reviewer` | Security + architecture + refactoring (breadth pass, gates the health report) | Read, Bash, Grep, Glob | Reviewing |
174
- | `tester` | E2E/integration authoring + suite analysis | Dual-mode: author (Write/Edit/Bash/git) · analyst (read-only) | Testing skill |
175
- | `security-reviewer` | Confidence-gated security depth (≥8, exploit-scenario required) | Read, Grep, Glob, Bash | Optional deep-dive |
176
- | `performance-reviewer` | Real bottlenecks only (Impact = frequency × cost; ≥8 + ≥Medium) | Read, Grep, Glob, Bash | Optional deep-dive |
177
- | `doc-reviewer` | Docs-vs-source accuracy (≥8; Blocker/Major/Minor) | Read, Grep, Glob, Bash | Optional deep-dive |
167
+ | `reviewer` | Security/architecture/refactoring (breadth, gates the health report) | Read, Bash, Grep, Glob | Reviewing |
168
+ | `tester` | E2E/integration authoring + suite analysis | Author (Write/Edit/Bash/git) or read-only | Testing skill |
169
+ | `security-reviewer` | Security depth (≥8, exploit-scenario required) | Read, Grep, Glob, Bash | Deep-dive |
170
+ | `performance-reviewer` | Real bottlenecks only (frequency × cost; ≥8 + ≥Medium) | Read, Grep, Glob, Bash | Deep-dive |
171
+ | `doc-reviewer` | Docs-vs-source accuracy (≥8; Blocker/Major/Minor) | Read, Grep, Glob, Bash | Deep-dive |
178
172
 
179
- The three specialist reviewers complement the generalist `reviewer` — single-axis, defensible depth, read-only, pulled in deliberately (from `reviewing` or direct). The 3-mode `reviewer` remains the breadth pass that gates the milestone health report.
173
+ The three specialists complement `reviewer` — single-axis, read-only, pulled in deliberately. `reviewer`'s 3-mode pass remains the breadth gate on the milestone health report.
180
174
 
181
175
  ## Project Init (First Run)
182
176
 
183
- No `.forge/project.yml` → auto-detect project type:
184
-
185
- **Brownfield** (has package.json/src/.git): detect frameworks → absorb → verify docs vs code → scan stack → detect design system → analyze patterns → infer constitution → user confirms.
186
-
187
- **Greenfield**: project basics → design system → constitution → state init.
188
-
189
- Quick tier skips init.
177
+ No `.forge/project.yml` → auto-detect project type. **Brownfield** (has package.json/src/.git): frameworks → absorb → verify docs vs code → scan stack → design system → patterns → infer constitution → user confirms. **Greenfield**: project basics → design system → constitution → state init. Quick tier skips init.
190
178
 
191
179
  ## State Management
192
180
 
193
181
  State lives in `.forge/`. One line per artifact; protocol detail lives in the named ADRs and skills:
194
182
 
195
- - `project.yml` — vision, stack, design system, verification, constraints (<5 KB). Optional `jarvis.dev_lane_cmd` (m-48) is the stack-agnostic seam Jarvis runs to spin up a slice's local dev server for operator UAT before a PR opens; absent ⇒ manual lane start. See `docs/jarvis.md`.
183
+ - `project.yml` — vision, stack, design system, verification, constraints (<5 KB). Optional `jarvis.dev_lane_cmd` (m-48) seams Jarvis's dev-server spin-up for UAT; absent ⇒ manual start (`docs/jarvis.md`).
196
184
  - `constitution.md` — active architectural gates
197
185
  - `design-system.md` — component mapping table
198
- - `requirements/m{N}.yml` — per-milestone structured requirements with `[NEEDS CLARIFICATION]` markers. **FR/DEF/NFR ids are globally unique across all milestone files** — reserve via the ID Reservation Protocol before writing. M9 e2e gate fields (`e2e`, `observable_outcome`, `validated`, hash) lazy-migrate; absent ⇒ `false`.
186
+ - `requirements/m{N}.yml` — per-milestone structured requirements, `[NEEDS CLARIFICATION]` markers. **FR/DEF/NFR ids globally unique** — reserve first. M9 e2e gate fields lazy-migrate; absent ⇒ `false`.
199
187
  - `roadmap.yml` — phases, milestones, dependencies
200
- - `state/index.yml` — DERIVED milestone registry, **git-ignored render-on-read cache** (0.53.0): regenerated at every boot from the milestone files by the **`forge-state-rollup.sh` SessionStart hook** (issue #22; skills only *read* it); never committed, never hand-edited. Rendered in any checkout (gitignored local write), but worktree agents never write *committed* derived-source state; absent on a fresh clone (sentinel is `project.yml`). Rows carry the derived `release_state`.
201
- - **Derived `release_state`** ([ADR-024](../docs/decisions/ADR-024-merged-validated-fold.md)) — `{unmerged, merged, validated}` computed at rollup by `.claude/hooks/forge-release-fold.sh` (git-only, offline; the fold binary is the only source — agent prose never re-derives it), never stored. Validation binding via `forge.validation_event`: `in_session_signoff` (default; absent ⇒ this) or `promotion_approval` (CI-signed `promotion/{sha}` tag). Inert until a repo opts in; full spec in ADR-024 + the fold header.
188
+ - `state/index.yml` — DERIVED milestone registry, git-ignored render-on-read cache (0.53.0), regenerated at boot by `forge-state-rollup.sh` (issue #22; read-only for skills); never committed; absent on a fresh clone (sentinel `project.yml`). Rows carry derived `release_state`.
189
+ - **Derived `release_state`** ([ADR-024](../docs/decisions/ADR-024-merged-validated-fold.md)) — `{unmerged, merged, validated}`, computed at rollup (`forge-release-fold.sh`, git-only, offline), never stored. Binding via `forge.validation_event`: `in_session_signoff` (default) or `promotion_approval` (CI-signed tag); inert until opted in.
202
190
  - `state/milestone-{id}.yml` — per-milestone cursor (**single source of truth**): position, decisions, blockers. One owner at a time.
203
- - `state/desire-paths/` — append-only framework-usage observations, one file per observation, `scope: project|framework` (absent ⇒ project); occurrence counts derived by globbing. **`forge` boot is the single review owner** — surfaces groups at 3+, persists declines (no re-nag), routes `framework`-scope signals upstream ([ADR-012](../docs/decisions/ADR-012-upstream-desire-path-feedback-channel.md)); `verifying` captures but never surfaces. An issue-sourced entry SHOULD carry a back-reference (`resolves_issue: N`; ADRs use `**Context source:** forge#N`) — close-the-loop keys off it.
204
- - `context.md` — active locked decisions + deferred ideas (≤12 KB); history archives to `context-archive.md`
205
- - `streams/active.yml` — DERIVED Project Chief traffic map, git-ignored render-on-read cache, rendered by the same `forge-state-rollup.sh` hook — see Stream Rollup below ([ADR-015](../docs/decisions/ADR-015-derived-stream-registry.md))
206
- - `streams/{stream}.yml` (+ `brief.md`, `packages/{id}.yml`) — per-stream **source of truth**: coordination lifecycle, ownership, shared surfaces, blockers, merge readiness, optional `stream.milestone` link (milestone-backed streams omit workflow phase — the rollup reads it from the milestone)
191
+ - `state/desire-paths/` — append-only usage observations, `scope: project|framework` (absent ⇒ project); counts derived by globbing. `forge` boot is the single review owner — surfaces groups at 3+, persists declines, routes `framework`-scope upstream ([ADR-012](../docs/decisions/ADR-012-upstream-desire-path-feedback-channel.md)); `verifying` captures, never surfaces. Issue-sourced entries carry `resolves_issue: N`.
192
+ - `context/{id}.md` (+ derived `context.md` index) — locked decisions + deferred ideas per milestone; history archives to `context-archive.md`
193
+ - `streams/active.yml` — DERIVED traffic map, git-ignored render-on-read cache, same hook — see Stream Rollup ([ADR-015](../docs/decisions/ADR-015-derived-stream-registry.md))
194
+ - `streams/{stream}.yml` (+ `brief.md`, `packages/{id}.yml`) — per-stream **source of truth**: lifecycle, ownership, surfaces, blockers, merge readiness, optional `stream.milestone` link (rollup reads phase from the milestone)
207
195
  - `research/milestone-{id}.md` — dated immutable findings snapshot
208
196
  - `phases/milestone-{id}/{phase}-{name}/plan-{NN}.md` — task plans with must_haves frontmatter (`{id}`=milestone, `{phase}`=phase# verbatim, `{name}`=kebab, `{NN}`=seq)
209
- - `refactor-backlog.yml` — refactoring catalog worked via quick-tasking; status vocab `pending | in_progress | done | dismissed | deferred`; terminal items auto-archive to `refactor-backlog-archive.yml` on the next reviewing/quick-tasking write
197
+ - `refactor-backlog.yml` — quick-tasking catalog; vocab `pending|in_progress|done|dismissed|deferred`; terminal items auto-archive
210
198
  - `releases.yml` — append-only version-reservation registry (Version Reservation Protocol)
211
- - `reservations.yml` — append-only id-reservation audit trail + cross-machine floor (ID Reservation Protocol); `forge-reserve compact` (R104) moves dropped rows verbatim to `reservations-archive.yml`, retaining each kind's max + a 14-day tail
212
- - `state/issue-loop/declined/{N}.yml` — append-only close-the-loop decline markers; `reviewing` writes one when the operator declines a surfaced resolved-but-open issue (no re-nag). Inert once the issue closes.
199
+ - `reservations.yml` — append-only id-reservation audit trail + cross-machine floor; `forge-reserve compact` (R104) moves dropped rows to `reservations-archive.yml`, keeping each kind's max + a 14-day tail
200
+ - `state/issue-loop/declined/{N}.yml` — close-the-loop decline markers (no re-nag) from `reviewing`; inert once the issue closes
213
201
  - `archive/milestone-{id}/` — archived milestone artifacts (archive-delete)
214
- - `prototypes/{slug}.md` — resumable disposable-mockup state (`exploring | parked | graduated | discarded`); terminal → `prototypes/archive/`. Single-owner, one driver. See `Skill(prototyping)`.
202
+ - `prototypes/{slug}.md` — disposable-mockup state (`exploring|parked|graduated|discarded`); terminal → `prototypes/archive/`. Single-owner. See `Skill(prototyping)`.
215
203
 
216
- **Milestones** group phases into concurrent streams — own state file, no conflicts across sessions; can be deferred (frozen in place) or archive-deleted. Registry status vocab: `not_started | active | deferred | complete`. **`current.status` is authoritative** — complete only at `current.status == complete`; 100% tasks ≠ done (verifying + reviewing + the recorded human sign-off still gate).
204
+ **Milestones** group phases into concurrent streams — own state file, no cross-session conflicts; deferred (frozen) or archive-deleted. Status vocab: `not_started | active | deferred | complete`. **`current.status` is authoritative** — 100% tasks ≠ done (verifying + reviewing + the recorded human sign-off still gate).
217
205
 
218
206
  **Format:** YAML for machine state, Markdown for human content.
219
207
 
220
208
  ### Stream Rollup
221
209
 
222
- `active.yml` is a pure projection by a deterministic, idempotent **join**: per-stream files contribute coordination state; active milestones contribute `phase` (any active milestone with no stream file gets a derived `implicit` row — coverage is computed, not maintained); `merge_queue` derives from `merge.readiness: ready`. A **step-0 completed-stream auto-close sweep** runs first: a milestone-backed stream whose milestone is `complete`, not yet `closed`, with no live worktree is auto-closed (no zombie "ready to merge" rows). Rendered by the same `forge-state-rollup.sh` hook (above) at boot and at `chief-of-staff` Show/Sync / mid-session milestone CRUD; it runs Rollup 1.0 **first** (the join reads the fresh `index.yml`), and confines the committed-source sweep to the main checkout. **Numbered procedure: the ADR-015 addendum.** Each field has exactly one source and coverage is computed, so two-registry drift cannot occur.
210
+ `active.yml` is a deterministic **join**: per-stream files contribute coordination state; active milestones contribute `phase` (stream-file-less active milestone derived `implicit` row); `merge_queue` derives from `merge.readiness: ready`. A **step-0 auto-close sweep** closes milestone-backed streams whose milestone is `complete`, not `closed`, with no live worktree. Rendered by the same hook at boot and at `chief-of-staff` Show/Sync/CRUD; Rollup 1.0 runs first, sweep confined to main. Numbered procedure: the ADR-015 addendum each field has one source, so drift cannot occur.
223
211
 
224
212
  ### State Commit Protocol
225
213
 
@@ -230,7 +218,7 @@ git add .forge/ # scoped — respects .gitignore; never `git add .`
230
218
  git commit -m "chore(forge): sync state after {phase} — m{N} {phase-name}"
231
219
  ```
232
220
 
233
- **In a worktree session, pin with the recorded path** — `git -C {worktree_path} add/commit` (`lifecycle.worktree_path` is authoritative over cwd; the process cwd can silently reset to the launch checkout across turns, and a wrong-cwd git op can even exit 0). Guard: compare `git rev-parse --show-toplevel` to the recorded path before the first write — full discipline in `executing` (Worktree cwd discipline) and `verifying` (Worktree cwd guard). State-sync commits are separate from per-task code commits (which stay atomic during executing).
221
+ **In a worktree session, pin with the recorded path** — `git -C {worktree_path} add/commit` (cwd can silently reset to the launch checkout across turns; a wrong-cwd op can even exit 0). Guard: compare `git rev-parse --show-toplevel` to the recorded path before the first write — full discipline in `executing`/`verifying`. State-sync commits are separate from per-task code commits.
234
222
 
235
223
  ### State Ownership (multi-worktree safety)
236
224
 
@@ -238,12 +226,12 @@ git commit -m "chore(forge): sync state after {phase} — m{N} {phase-name}"
238
226
 
239
227
  | Class | Files | Write rule |
240
228
  |---|---|---|
241
- | **Single-owner mutable** | `state/milestone-{id}.yml`, `phases/milestone-{id}/`, `research/milestone-{id}.md` | Exactly one writer at a time — the checkout currently driving that milestone. Other worktrees never touch it (not even read-then-write; pull from main instead). |
229
+ | **Single-owner mutable** | `state/milestone-{id}.yml`, `phases/milestone-{id}/`, `research/milestone-{id}.md`, `context/{id}.md` | Exactly one writer at a time — the checkout currently driving that milestone. Other worktrees never touch it (not even read-then-write; pull from main instead). |
242
230
  | **Single-owner mutable (per stream)** | `streams/{stream}.yml`, `streams/{stream}/brief.md`, `streams/{stream}/packages/*.yml` | The stream's current driver writes them; distinct streams own distinct files — no cross-stream contention. |
243
- | **Derived (git-ignored render-on-read cache)** | `state/index.yml`, `streams/active.yml`, the rendered `release_state` column | Never hand-edited, **never committed** — regenerated by rollup from sources at every boot. Any session may render its own copy; absence on a fresh clone is normal (render-then-read; the sentinel is `project.yml`). |
231
+ | **Derived (git-ignored render-on-read cache)** | `state/index.yml`, `streams/active.yml`, `context.md`, the rendered `release_state` column | Never hand-edited, **never committed** — regenerated by rollup from sources at every boot. Any session may render its own copy; absence on a fresh clone is normal (render-then-read; the sentinel is `project.yml`). `context.md` specifically joins `context/{id}.md` files with `state/index.yml` (ADR-033). |
244
232
  | **Append-only shared** | `releases.yml`, `reservations.yml`, `state/desire-paths/*`, `deferred-issues/*` | Many writers OK; structure prevents collision (append-only entries / distinct filenames). |
245
233
  | **Machine-local runtime** | `.git/forge/id-reservations`, `.git/forge/integration-pending` | Git common dir — shared across a machine's worktrees, never git-tracked, excluded from framework context. |
246
- | **Shared mutable** | `context.md`, `refactor-backlog.yml`, `requirements/m{N}.yml` | Write only your milestone/stream block; within a block, append-only — strike through instead of rewriting. |
234
+ | **Shared mutable** | `refactor-backlog.yml`, `requirements/m{N}.yml` | Write only your milestone/stream block; within a block, append-only — strike through instead of rewriting. |
247
235
  | **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md`, `.claude/skills/`, `.claude/agents/` | Rarely changes except via `/upgrading` (registry default — the npm bin is the sync engine; local dev sync only via explicit `/upgrading dev`). Canonical on main; worktrees lag until they rebase. An upgrade touches only its own checkout — `upgrading` Step 8 offers live-worktree rebases (never auto); opt-in `forge.worktree_rebase_check` is the boot-time net. Gitignored carve-outs (`.mcp.json`, experimental hooks) propagate via the experimental installer, not git. |
248
236
 
249
237
  Ownership rules (quick reference):
@@ -255,11 +243,11 @@ Ownership rules (quick reference):
255
243
 
256
244
  ### Version Reservation Protocol
257
245
 
258
- The project version + CHANGELOG slot are shared resources — `.forge/releases.yml` (append-only) removes the number from per-milestone scope. **Reserve early, at planning**: derive `max() + bump`, **claim it in the ledger first** `forge-reserve version --value <X.Y.Z>` (record-only; a conflict names the sibling milestone holding the number, its claim possibly worktree-only — re-read and re-bump; ADR-029) — then append ONE `{milestone, version, bump, reserved_at, summary}` entry and **commit + push the reservation BEFORE editing the version file** so a parallel session sees the number taken. Never edit prior entries. **Delivery never invents a number** write only the reserved version; no reservation → reserve at delivery (pull, `max() + bump`, append, push, then write). **Race:** the second push rebases onto the first (append-only → clean), re-reads `max()`, takes the next number. **Bump criteria (0.x):** patch = bug fix/doc/sync/refinement; minor = new skill/agent/routing-row/auto-trigger/state-artifact/capability; major = post-1.0 breaking. Default to minor when in doubt — a capability shipped as a patch drifts the version away from truth.
246
+ The version + CHANGELOG slot are shared — `.forge/releases.yml` (append-only). **Reserve at planning**: derive `max() + bump`, claim in the ledger first (`forge-reserve version --value <X.Y.Z>` conflict names the sibling milestone holding it), append ONE `{milestone, version, bump, reserved_at, summary}` entry, **commit + push before editing the version file**. Never edit prior entries; never invent a number at delivery no reservation found → reserve then, same steps. Push race rebase onto the file, re-read `max()`. Bump criteria + race narrative: `planning`'s Reserve-version step + ADR-029.
259
247
 
260
248
  ### ID Reservation Protocol
261
249
 
262
- Sequential ids `ADR-NNN`, `DEF-NNN`, `FR-`/`NFR-NNN`, milestone `M-NN`, refactor `R0NN`, roadmap phase/wave numbers — are shared cross-worktree resources; scan-and-increment sees only committed state, so concurrent worktrees claim the same number and collide silently until merge. **Reserve with the helper before creating the artifact**: `forge-reserve <kind> --milestone <id> [--summary <text>]` (`.claude/hooks/forge-reserve.sh`, kinds `adr|def|fr|nfr|milestone|refactor|phase|wave|version`; id formats per [ADR-023](../docs/decisions/ADR-023-extend-id-reservation-to-milestone-refactor-ids.md) + ADR-029 — phase/wave registry tokens are `P-0NN`/`W-0NN` while roadmap.yml keeps bare ints; `version` is record-only via `--value` (the ledger makes in-flight claims sibling-visible; `releases.yml` stays the durable registry)) prints the id and dual-writes the **machine-local ledger** (`.git/forge/id-reservations`, git common dir — the same-machine coordination point, written under a `mkdir` lock) plus the tracked `.forge/reservations.yml` (durable audit trail + cross-machine floor; the caller commits it with the work). **Next number = `max(ledger ∪ in-tree ∪ main:reservations.yml) + 1`** per kind the in-tree scan includes archives, so a compacted id is never reallocated. Reserve points: `architecting` (adr), `planning` (fr/nfr/def, phase/wave, version), `forge` Rollup / `discussing` / `prototyping` (milestone), `reviewing` (refactor). Deferred issues are counter-free per-issue files (`.forge/deferred-issues/{date}-{milestone}-{slug}.md`) no DI-NNN, nothing to collide on. Accepted gap: concurrent reserves on *different machines* fall back to merge-time renumber, bounded by the floor. On any residual collision (legacy/un-reserved ids), **keep the older milestone's id and renumber the newer**. Lazy migration — the ledger self-creates on first reserve. Full rationale: [ADR-021](../docs/decisions/ADR-021-id-reservation-ledger-git-common-dir.md) (supersedes ADR-016) + ADR-023 + ADR-029. Versions stay in `releases.yml` (separate semver/CHANGELOG semantics); the ledger only carries their claims.
250
+ Sequential ids (`ADR-NNN`, `DEF-NNN`, `FR-`/`NFR-NNN`, milestone `M-NN`, refactor `R0NN`, roadmap phase/wave) are shared cross-worktree resources scan-and-increment collides silently until merge. **Reserve before create**: `forge-reserve <kind> --milestone <id> [--summary <text>]` (`.claude/hooks/forge-reserve.sh`, kinds `adr|def|fr|nfr|milestone|refactor|phase|wave|version`). Next id = **`max(ledger ∪ in-tree ∪ main:reservations.yml) + 1`** per kind; residual collision older milestone keeps the id, newer renumbers. Reserve points: `architecting` (adr), `planning` (fr/nfr/def, phase/wave, version), `forge` Rollup/`discussing`/`prototyping` (milestone), `reviewing` (refactor). Deferred issues are counter-free — nothing to collide on. Full mechanics (ledger + lock, id-format table, cross-machine floor, lazy migration): the helper's header comment + [ADR-021](../docs/decisions/ADR-021-id-reservation-ledger-git-common-dir.md) (supersedes ADR-016) + ADR-023 + ADR-029.
263
251
 
264
252
  ## Deviation Rules
265
253
 
@@ -284,16 +272,16 @@ verification:
284
272
  - cmd: "npm run lint"
285
273
  - cmd: "npm test"
286
274
  - cmd: "npx tsc --noEmit"
287
- advisory: true # pre-existing failures — warn only
288
- auto_fix: true # fix and retry on failure
289
- max_retries: 2 # max attempts per command
275
+ advisory: true # pre-existing failures — warn only
276
+ auto_fix: true # fix and retry on failure
277
+ max_retries: 2 # max attempts per command
290
278
  ```
291
279
 
292
- Auto-detected from `package.json` at init. Advisory mode warns, never blocks. Auto-fix loop: read output → fix → amend → re-run (≤ `max_retries`; retries count toward the 3-strike task limit). Empty commands = no gate (opt-out). `verification.e2e_soft_cap` (default 10) — advisory per-milestone cap on `e2e:true` stories, surfaced by `reviewing`, never blocks.
280
+ Auto-detected from `package.json` at init. Advisory mode warns, never blocks. Auto-fix loop: read output → fix → amend → re-run (≤ `max_retries`; retries count toward the 3-strike limit). Empty commands = opt-out. `verification.e2e_soft_cap` (default 10) — advisory per-milestone cap on `e2e:true` stories, surfaced by `reviewing`, never blocks.
293
281
 
294
282
  ### Truth checks (executable must_haves)
295
283
 
296
- Plans MAY declare a per-truth `check:` shell command in `must_haves.truths` (exit 0 = pass; authored goal-backward at planning, before code exists; linted by planning Step 8). `executing` runs declared checks once at plan completion (early fix-loop signal, never a verdict); `verifying` re-executes them and applies the **executed-evidence rule**: VERIFIED only with a recorded command + exit code + output excerpt — no executed evidence → UNCERTAIN or human-route, never VERIFIED. Legacy bare-string truths stay valid.
284
+ Plans MAY declare a per-truth `check:` shell command in `must_haves.truths` (exit 0 = pass; authored goal-backward at planning, before code exists). `executing` runs declared checks once at plan completion (early fix-loop signal, never a verdict); `verifying` re-executes, applying the **executed-evidence rule**: VERIFIED only with a recorded command + exit code + output excerpt — no evidence → UNCERTAIN or human-route. Legacy bare-string truths stay valid.
297
285
 
298
286
  ### Human Verification Gate (close precondition)
299
287
 
@@ -308,8 +296,8 @@ Plans MAY declare a per-truth `check:` shell command in `must_haves.truths` (exi
308
296
 
309
297
  ## Beads Integration (Optional)
310
298
 
311
- With Beads installed: `bd prime` (session context), `bd ready` (unblocked tasks), `bd complete` (update deps), `bd compact` (summarize old). Without Beads, `.forge/state/` + Session Memory suffice.
299
+ With Beads: `bd prime` (session context), `bd ready` (unblocked tasks), `bd complete` (update deps), `bd compact` (summarize old). Without it, `.forge/state/` + Session Memory suffice.
312
300
 
313
301
  ## Atomic Commits
314
302
 
315
- One commit per task. Format: `{type}({scope}): {description}` — types `feat fix test refactor chore docs`. Never `git add .` or `git add -A` — stage individually. Phase handoffs additionally emit one scoped `chore(forge): sync state …` commit (State Commit Protocol) so `.forge/` state never drifts out of git.
303
+ One commit per task. Format: `{type}({scope}): {description}` — types `feat fix test refactor chore docs`. Never `git add .`/`-A` — stage individually. Phase handoffs additionally emit one scoped `chore(forge): sync state …` commit (State Commit Protocol) so `.forge/` state never drifts out of git.
@@ -69,6 +69,43 @@ fold_state() { # fold_state <milestone-id>
69
69
  [ -n "$_rs" ] && printf '%s' "$_rs" || printf 'unknown'
70
70
  }
71
71
 
72
+ # ── milestone name lookup (issue #34 — bare ids are useless with 40+ milestones in flight).
73
+ # Reads milestone.name (nested under the top-level `milestone:` key) from the worktree's own
74
+ # state file — a naive `grep -m1 '^name:'` returns empty since the key is indented under
75
+ # `milestone:`, not top-level. Same nested-key awk pattern as yget() in
76
+ # forge-board-render.sh (parent/child scan), specialized to milestone/name. Degrades to empty
77
+ # on any miss (absent file, absent key) — callers degrade to the bare id, never crash. ────────
78
+ milestone_name() { # milestone_name <milestone-id> <worktree-path>
79
+ _mid="${1:-}"; _wt="${2:-}"
80
+ [ -n "$_mid" ] && [ -n "$_wt" ] || { printf ''; return 0; }
81
+ _id="${_mid#m-}"
82
+ _f="$_wt/.forge/state/milestone-$_id.yml"
83
+ [ -f "$_f" ] || { printf ''; return 0; }
84
+ awk '
85
+ /^milestone:/ { inp=1; next }
86
+ inp && /^[A-Za-z]/ { inp=0 }
87
+ inp && /^[[:space:]]+name:/ {
88
+ sub(/^[[:space:]]*[^:]+:[[:space:]]*/, "")
89
+ sub(/[[:space:]]*#.*/, "")
90
+ gsub(/^["'"'"']|["'"'"']$/, "")
91
+ print; exit
92
+ }
93
+ ' "$_f"
94
+ }
95
+
96
+ # ── "m-<id> — <name>", truncated ~60 chars so one slice-list row stays one line; degrades to
97
+ # the bare id (never a blank "m- — " prefix) when the name can't be resolved. ────────────────
98
+ named_milestone() { # named_milestone <milestone-id> <worktree-path>
99
+ _mid="${1:-}"; _wt="${2:-}"
100
+ [ -n "$_mid" ] || { printf ''; return 0; }
101
+ _nm="$(milestone_name "$_mid" "$_wt")"
102
+ if [ -n "$_nm" ]; then
103
+ printf '%s' "$_mid — $_nm" | cut -c1-60
104
+ else
105
+ printf '%s' "$_mid"
106
+ fi
107
+ }
108
+
72
109
  # ── milestone id derivation for a matched branch (issue #25, bare-branch loosening). A
73
110
  # forge/m-* branch keeps its original textual derivation unchanged (strip forge/, strip the
74
111
  # 8-hex session suffix). A bare branch (m-<id>-slug | m<digits>-slug) derives the id from the
@@ -143,7 +180,8 @@ _slices="$(list_slices)"
143
180
  if [ -n "$_slices" ]; then
144
181
  printf '%s\n' "$_slices" | while IFS="$TAB" read -r _m _br _pt; do
145
182
  if [ "$DRY_RUN" -eq 1 ]; then _rs='(dry-run)'; else _rs="$(fold_state "$_m")"; fi
146
- printf ' %-10s %-26s release_state=%-9s %s\n' "$_m" "$_br" "$_rs" "$_pt"
183
+ _disp="$(named_milestone "$_m" "$_pt")"
184
+ printf ' %-40s %-26s release_state=%-9s %s\n' "$_disp" "$_br" "$_rs" "$_pt"
147
185
  done
148
186
  else
149
187
  printf ' (none on this machine)\n'
@@ -165,7 +203,13 @@ elif [ -f "$BOARD" ]; then
165
203
  _id="$(printf '%s' "$_ln" | sed -n 's/.*"forge_id":[[:space:]]*"\([^"]*\)".*/\1/p')"
166
204
  _st="$(printf '%s' "$_ln" | sed -n 's/.*"status":[[:space:]]*"\([^"]*\)".*/\1/p')"
167
205
  _rs="$(printf '%s' "$_ln" | sed -n 's/.*"release_state":[[:space:]]*"\([^"]*\)".*/\1/p')"
168
- printf ' %s status=%s release_state=%s\n' "${_id:-?}" "${_st:-?}" "${_rs:-?}"
206
+ _nm="$(printf '%s' "$_ln" | sed -n 's/.*"name":[[:space:]]*"\([^"]*\)".*/\1/p')"
207
+ if [ -n "$_nm" ]; then
208
+ _disp="$(printf '%s' "${_id:-?} — $_nm" | cut -c1-60)"
209
+ else
210
+ _disp="${_id:-?}"
211
+ fi
212
+ printf ' %s status=%s release_state=%s\n' "$_disp" "${_st:-?}" "${_rs:-?}"
169
213
  done
170
214
  else
171
215
  printf ' (all board units complete — nothing in flight)\n'