forge-orkes 0.61.0 → 0.62.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.
- package/package.json +1 -1
- package/template/.forge/FORGE.md +95 -199
package/package.json
CHANGED
package/template/.forge/FORGE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Forge
|
|
2
2
|
|
|
3
|
-
Lean meta-prompting framework. Context engineering + constitutional governance on agent-native primitives.
|
|
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.
|
|
4
4
|
|
|
5
5
|
## Critical: No Native Plan Mode
|
|
6
6
|
|
|
@@ -21,13 +21,11 @@ All phases: **invoke via `Skill` tool**, never native behavior. `planning` → `
|
|
|
21
21
|
|
|
22
22
|
## Core Protocol And Adapters
|
|
23
23
|
|
|
24
|
-
**Core protocol** lives in `.forge/`: project/constitution state, milestones, requirements, roadmap, context, streams, work packages, plans, verification, audits, and state ownership rules
|
|
25
|
-
|
|
26
|
-
**Platform adapters** translate the protocol into a runtime. Each platform adapter maps core behavior to its tools: Claude Code skills/hooks, Codex/AGENTS behavior, manual multi-session handoffs, or future agent surfaces. Adapter mechanics stay in adapter files and skills; they should not become core requirements.
|
|
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.
|
|
27
25
|
|
|
28
26
|
## Project Streams
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
Three runtime coordination layers: Project, Stream, Work Package.
|
|
31
29
|
|
|
32
30
|
| Layer | Purpose | Default Context |
|
|
33
31
|
|---|---|---|
|
|
@@ -35,36 +33,31 @@ Forge has three runtime coordination layers: Project, Stream, and Work Package.
|
|
|
35
33
|
| **Stream** | One active line of work: goal, branch/worktree, state, blockers, next action | `.forge/streams/{stream}.yml` + `brief.md` |
|
|
36
34
|
| **Work Package** | Delegated bounded task inside a stream | `.forge/streams/{stream}/packages/{id}.yml` |
|
|
37
35
|
|
|
38
|
-
|
|
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.
|
|
39
37
|
|
|
40
|
-
**Merge often and early.** Integrate ready work **as soon as it is ready**, not at milestone end
|
|
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.
|
|
41
39
|
|
|
42
40
|
### Stream Integration Checkpoints
|
|
43
41
|
|
|
44
|
-
|
|
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:
|
|
45
43
|
|
|
46
|
-
- **Checkpoints
|
|
47
|
-
- **Producer
|
|
48
|
-
- **
|
|
49
|
-
- **
|
|
50
|
-
- **Consumer — auto fast-forward, else prompt (worktrees *and* the primary main checkout).** `forge` boot checks the flag in **both** checkout kinds. In a **worktree**: flag set (main advanced past this worktree's merge-base) and no divergent local commits → **fast-forward automatically** (`git merge --ff-only main`); diverged → **surface a rebase prompt** (never auto-rebase). In the **primary main checkout**: the strand guard guarantees local main is a clean ff of the new `origin/main`, so boot **fast-forwards local main automatically** (`git merge --ff-only origin/main`) — this is what keeps the operator's canonical checkout in lockstep with origin after every checkpoint, instead of drifting behind until the next local commit diverges it. Flag not set → no fetch, no scan, continue boot.
|
|
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.
|
|
51
48
|
|
|
52
49
|
### Worktree Convention (base)
|
|
53
50
|
|
|
54
|
-
|
|
51
|
+
Where worktrees live and what they're named — single source of truth, base concern ([ADR-010](../docs/decisions/ADR-010-repo-scoped-worktree-root.md)). Chief/Streams uses plain `git worktree`.
|
|
55
52
|
|
|
56
53
|
| Element | Convention |
|
|
57
54
|
|---|---|
|
|
58
|
-
| **Root** | `orchestration.worktree_root` from `project.yml`;
|
|
59
|
-
| **Anchor** | `{milestone-id}-{session}` (e.g. `m-9-a1b2c3d4`)
|
|
60
|
-
| **Path** | `{worktree_root}/{anchor}` —
|
|
55
|
+
| **Root** | `orchestration.worktree_root` from `project.yml`; default `../<repo-basename>-worktrees/`. Relative paths resolve against the **repo root**; absolute / `~` honored verbatim. |
|
|
56
|
+
| **Anchor** | `{milestone-id}-{session}` (e.g. `m-9-a1b2c3d4`); milestone/stream id alone acceptable for a manual stream worktree. |
|
|
57
|
+
| **Path** | `{worktree_root}/{anchor}` — resolved **absolute**. |
|
|
61
58
|
| **Branch** | `forge/{anchor}`. |
|
|
62
59
|
|
|
63
|
-
**Recorded path is authoritative once set
|
|
64
|
-
|
|
65
|
-
**Fallback when no path was recorded.** A worktree created outside `orchestrating` (a manual `git worktree add`, an adopted stream) may have no recorded path. Resolve it from this convention — `{worktree_root}/{anchor}` — rather than assuming the experimental skill's internal default. Chief/Streams uses this fallback; `orchestrating` (when installed) implements the same scheme for the worktrees it creates.
|
|
66
|
-
|
|
67
|
-
**Validated against the convention (advisory).** "Authoritative" means *honored*, not *unchecked*: `forge` boot (Step 1 preflight) and `chief-of-staff` adoption compare a recorded path's parent dir to the resolved `worktree_root` and **warn** — never block, never move — when it sits outside. This catches a manual `git worktree add ../forge-worktrees/m115` or pre-convention state that the verbatim-trust rule would otherwise sail past (the convention was a *fallback resolver* only, never a *validator*). The warning honors an explicit `orchestration.worktree_root`. Fix with `git worktree move` + update the recorded path.
|
|
60
|
+
**Recorded path is authoritative once set** — `lifecycle.worktree_path` (milestone) / `runtime.worktree` (stream) is read verbatim, never re-derived; changing `worktree_root` affects only new worktrees; move a live worktree only with `git worktree move` + update the record. No recorded path → resolve from the convention. `forge` boot and `chief-of-staff` adoption **validate advisorily**: recorded path outside the resolved root → warn (never block, never move); an explicit `worktree_root` is honored.
|
|
68
61
|
|
|
69
62
|
## Workflow Tiers
|
|
70
63
|
|
|
@@ -73,7 +66,7 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
|
73
66
|
### Prototyping (minutes–hours, disposable)
|
|
74
67
|
**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
|
|
75
68
|
**Flow:** `prototyping` — establish flag → iterate ⟲ (render → react → adjust) → resolve (graduate→milestone | park | discard)
|
|
76
|
-
**No verify/review gate by design
|
|
69
|
+
**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).
|
|
77
70
|
|
|
78
71
|
### Quick (minutes)
|
|
79
72
|
**Triggers:** bug fix, typo, config, dep bump, <50 lines
|
|
@@ -85,7 +78,7 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
|
85
78
|
|
|
86
79
|
### Full (days)
|
|
87
80
|
**Triggers:** new project, major milestone, complex multi-system, architectural decisions
|
|
88
|
-
**Flow:**
|
|
81
|
+
**Flow:** Standard flow + `architecting` between discussing and planning
|
|
89
82
|
**Optional:** `designing` (UI), `securing` (auth/data/API), `debugging` (stuck), `testing` (e2e/integration/flake)
|
|
90
83
|
|
|
91
84
|
### Advisory (tier deferred)
|
|
@@ -103,13 +96,13 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
|
103
96
|
| Architectural decisions | `architecting` | Full |
|
|
104
97
|
| Break work into tasks with gates | `planning` | Standard, Full |
|
|
105
98
|
| Build with deviation rules + atomic commits | `executing` | All |
|
|
106
|
-
| Prove work delivers on goals (+ M9 e2e validation gate
|
|
107
|
-
| Audit health + catalog refactoring (+ M9 e2e
|
|
99
|
+
| Prove work delivers on goals (+ M9 e2e validation gate; captures the Human Verification Gate sign-off) | `verifying` | Standard, Full |
|
|
100
|
+
| Audit health + catalog refactoring (+ M9 e2e audits; hard-blocks completion on the Human Verification Gate) | `reviewing` | Standard, Full |
|
|
108
101
|
| Small scoped fix | `quick-tasking` | Quick |
|
|
109
102
|
| Rapid disposable UI mockup behind an alpha flag (no verify/review gate) | `prototyping` | Prototyping |
|
|
110
103
|
| UI with design system | `designing` | When UI |
|
|
111
104
|
| Security review | `securing` | When auth/data/API |
|
|
112
|
-
| E2E/integration tests + suite audit (+ M9 author-mode gate
|
|
105
|
+
| E2E/integration tests + suite audit (+ M9 author-mode gate) | `testing` | When UI/flows or flaky suite |
|
|
113
106
|
| Systematic debugging | `debugging` | When stuck |
|
|
114
107
|
| Upgrade Forge files | `upgrading` | On-demand |
|
|
115
108
|
| Cross-session memory | `beads-integration` | When Beads installed |
|
|
@@ -123,88 +116,47 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
|
123
116
|
### Size Gates
|
|
124
117
|
| Artifact | Max | Reason |
|
|
125
118
|
|----------|-----|--------|
|
|
119
|
+
| `FORGE.md` | 35 KB | Claude Code truncates memory files at 40k chars; routing-layer target ~28k |
|
|
126
120
|
| `project.yml` | 5 KB | Forces clarity |
|
|
127
121
|
| `requirements/m{N}.yml` | 50 KB/file | Prevents scope creep |
|
|
128
122
|
| `plan.md` | 30 KB | Keeps executor context <50% |
|
|
129
123
|
| `constitution.md` | 10 KB | Gates must be scannable |
|
|
130
124
|
| `context.md` | 12 KB | Active decisions only; history archives to `context-archive.md` |
|
|
131
|
-
| `refactor-backlog.yml` | 150 KB |
|
|
132
|
-
| `streams/active.yml` | 20 KB |
|
|
125
|
+
| `refactor-backlog.yml` | 150 KB | Terminal items archive to `refactor-backlog-archive.yml` (advisory) |
|
|
126
|
+
| `streams/active.yml` | 20 KB | Traffic map must stay cheap to load |
|
|
133
127
|
| `streams/{stream}.yml` | 15 KB | Stream state stays resumable without becoming history |
|
|
134
|
-
| `streams/{stream}/brief.md` | 8 KB |
|
|
128
|
+
| `streams/{stream}/brief.md` | 8 KB | Context packet must fit into active session context |
|
|
135
129
|
| `streams/{stream}/packages/{id}.yml` | 10 KB | Delegated work contract stays bounded |
|
|
136
|
-
| `reservations.yml` | 50 KB |
|
|
137
|
-
| `prototypes/{slug}.md` | 8 KB |
|
|
130
|
+
| `reservations.yml` | 50 KB | One short line per reserved id |
|
|
131
|
+
| `prototypes/{slug}.md` | 8 KB | Current question + terse iteration log; terminal items archive |
|
|
138
132
|
|
|
139
133
|
### Accumulating Artifacts
|
|
140
134
|
|
|
141
|
-
Every new accumulating artifact
|
|
142
|
-
`derived` vs source-of-truth status, and migration behavior. Defaults:
|
|
143
|
-
|
|
144
|
-
- `roadmap.yml`, `requirements/*.yml`, `releases.yml`, `reservations.yml` are
|
|
145
|
-
source-of-truth; load scoped slices, not whole history.
|
|
146
|
-
- `phases/`, `audits/`, `research/`, `archive/`, and `context-archive.md` are
|
|
147
|
-
historical; load only by milestone/stream/package/version.
|
|
148
|
-
- `prototypes/{slug}.md` is single-owner mutable while `status: exploring | parked`
|
|
149
|
-
(the driving session writes it); terminal statuses (`graduated`, `discarded`)
|
|
150
|
-
archive to `prototypes/archive/`. `forge` boot surfaces stale `parked` prototypes
|
|
151
|
-
(>30d). Not derived, not shared — a prototype has exactly one driver.
|
|
152
|
-
- Runtime/generated files (`.mcp-server/*.db*`, logs, spike DBs, and the
|
|
153
|
-
`.git/forge/*` machine-local files — the id-reservation ledger + integration
|
|
154
|
-
flag) are excluded from framework context and packages unless debugging them.
|
|
155
|
-
- The board (ADR-025): `.forge/notion/map.yml` is **derived** (owner: main/orchestrator
|
|
156
|
-
session; `forge-id → page-id` cache), **gitignored**, and rebuildable by query-self-heal
|
|
157
|
-
(ADR-020) — never committed, never hand-edited, no size gate. The board **config** is the
|
|
158
|
-
`board:` block in `project.yml` — **stable-shared**, governed by project.yml's 5 KB gate,
|
|
159
|
-
changes via `/upgrading`; migration is lazy (absent block / `enabled:false` ⇒ inert, zero
|
|
160
|
-
behavior change). The board itself accumulates nothing in-repo — it is a projection + inbox.
|
|
161
|
-
- Template copies sync mechanically; do not treat them as separate concepts.
|
|
135
|
+
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` are historical — load only by milestone/stream/package/version. `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.
|
|
162
136
|
|
|
163
137
|
### Fresh Agent Pattern
|
|
164
138
|
Task touches 20+ files or complex subsystem → spawn fresh executor with isolated context. Prevents context rot.
|
|
165
139
|
|
|
166
140
|
### Context Handoff
|
|
167
|
-
Each phase writes outputs to `.forge/` before completing. At phase boundaries, recommend `/clear
|
|
141
|
+
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.
|
|
168
142
|
|
|
169
143
|
### Lazy Loading
|
|
170
|
-
Skills load only when invoked. Active context is `.forge/context.md`; consult
|
|
171
|
-
`.forge/context-archive.md` only when older decisions matter. Skill details stay
|
|
172
|
-
on demand. Base context ~300 lines.
|
|
144
|
+
Skills load only when invoked. Active context is `.forge/context.md`; consult `.forge/context-archive.md` only when older decisions matter.
|
|
173
145
|
|
|
174
146
|
### Rules Layer (`.claude/rules/`)
|
|
175
|
-
Three policy weights, lightest-first (ADR-018):
|
|
176
|
-
- **`constitution.md`** — always-loaded architectural **gates** (heavy, project-wide, hard rules; size-gated 10 KB).
|
|
177
|
-
- **`.claude/rules/`** — lightweight ambient guidance. Always-on (no frontmatter, loads every session) or path-scoped (`paths:` glob frontmatter, auto-attaches only when editing a matching file — **zero context cost until you touch that code**).
|
|
178
|
-
- **Skills** — heavy, opt-in, loaded by task description.
|
|
179
|
-
|
|
180
|
-
Core ships one always-on rule: **`agent-discipline.md`** (the stack-agnostic AI failure-mode floor; restates the everyday version of the executor's Deviation Rules). **Stack-specific** path-scoped rules (Laravel/Vue/Python) and convention skills ship in the **opt-in `experimental/conventions/` pack**, not core — keeping the base stack-neutral. Authoring: keep each rule under ~20 lines, imperative-first; if it grows past ~25 lines it is a skill in disguise. See `.claude/rules/README.md`.
|
|
147
|
+
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).
|
|
181
148
|
|
|
182
149
|
## Model Routing
|
|
183
150
|
|
|
184
|
-
|
|
151
|
+
Configured in `project.yml` under `models:` — `default`, `parent_session` (advisory), `by_complexity.{trivial|standard|complex}` (per-task, M24), `skills.{name}` (per-skill).
|
|
185
152
|
|
|
186
|
-
|
|
187
|
-
models:
|
|
188
|
-
default: sonnet # fallback
|
|
189
|
-
parent_session: sonnet # advisory — warns on mismatch
|
|
190
|
-
by_complexity: # per-task complexity → model (M24). Overrides skills — see Precedence.
|
|
191
|
-
trivial: haiku
|
|
192
|
-
standard: sonnet
|
|
193
|
-
complex: opus
|
|
194
|
-
skills: # per-skill overrides
|
|
195
|
-
architecting: opus
|
|
196
|
-
planning: opus
|
|
197
|
-
verifying: haiku
|
|
198
|
-
quick-tasking: haiku
|
|
199
|
-
```
|
|
153
|
+
**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.
|
|
200
154
|
|
|
201
|
-
**
|
|
202
|
-
**Complexity overrides skill** (LOCKED, context.md § M24): when a task declares a `<complexity>`, its `by_complexity` resolution wins over `models.skills.{skill}`. WHY — the per-task signal is the granular one and the whole point of M24; letting the coarser skill-level setting win would make per-task routing inert on any project that already sets `models.skills.executing`. A task with **no** complexity resolves via the unchanged `skills → default → parent` chain — zero behavior change for untagged tasks.
|
|
203
|
-
**All advisory** — forge displays expected model at each transition, suggests `/model` on mismatch. Review gate logs model used. Cannot auto-switch.
|
|
155
|
+
**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.
|
|
204
156
|
|
|
205
|
-
**Subagent inheritance.**
|
|
157
|
+
**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.
|
|
206
158
|
|
|
207
|
-
**Spawn gate — predicate A (LOCKED, context.md § M24; refined
|
|
159
|
+
**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.
|
|
208
160
|
|
|
209
161
|
## Agents
|
|
210
162
|
|
|
@@ -215,12 +167,12 @@ models:
|
|
|
215
167
|
| `executor` | Building + deviation rules | All dev tools | Execution |
|
|
216
168
|
| `verifier` | Goal-backward verification | Read + Bash (tests) | Verification |
|
|
217
169
|
| `reviewer` | Security + architecture + refactoring (breadth pass, gates the health report) | Read, Bash, Grep, Glob | Reviewing |
|
|
218
|
-
| `tester` | E2E/integration authoring + suite analysis | Dual-mode: author (Write/Edit/Bash/git) · analyst (
|
|
219
|
-
| `security-reviewer` | Confidence-gated security depth (≥8, exploit-scenario required) | Read, Grep, Glob, Bash | Optional deep-dive
|
|
170
|
+
| `tester` | E2E/integration authoring + suite analysis | Dual-mode: author (Write/Edit/Bash/git) · analyst (read-only) | Testing skill |
|
|
171
|
+
| `security-reviewer` | Confidence-gated security depth (≥8, exploit-scenario required) | Read, Grep, Glob, Bash | Optional deep-dive |
|
|
220
172
|
| `performance-reviewer` | Real bottlenecks only (Impact = frequency × cost; ≥8 + ≥Medium) | Read, Grep, Glob, Bash | Optional deep-dive |
|
|
221
173
|
| `doc-reviewer` | Docs-vs-source accuracy (≥8; Blocker/Major/Minor) | Read, Grep, Glob, Bash | Optional deep-dive |
|
|
222
174
|
|
|
223
|
-
The three specialist reviewers
|
|
175
|
+
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.
|
|
224
176
|
|
|
225
177
|
## Project Init (First Run)
|
|
226
178
|
|
|
@@ -234,116 +186,75 @@ Quick tier skips init.
|
|
|
234
186
|
|
|
235
187
|
## State Management
|
|
236
188
|
|
|
237
|
-
State lives in `.forge
|
|
238
|
-
|
|
239
|
-
- `
|
|
240
|
-
- `
|
|
241
|
-
- `
|
|
242
|
-
- `
|
|
243
|
-
- `
|
|
244
|
-
-
|
|
245
|
-
- `
|
|
246
|
-
- `state/
|
|
247
|
-
- `
|
|
248
|
-
- `context
|
|
249
|
-
- `streams/active.yml` —
|
|
250
|
-
- `streams/{stream}.yml` —
|
|
251
|
-
- `
|
|
252
|
-
- `
|
|
253
|
-
- `
|
|
254
|
-
- `
|
|
255
|
-
- `
|
|
256
|
-
- `
|
|
257
|
-
- `
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
0. **Completed-stream auto-close sweep (source write, main checkout only — runs *before* the join).** A milestone-backed stream whose work has completed and landed on main should not linger as a `ready`/`merge_queue` row — that stale readiness is a **false** "ready to merge" nudge (the work is already on main; the stream is *closable, not mergeable*). Before the pure join, glob the stream files and for each with `stream.milestone: m-{id}` where the milestone's derived status (from the freshly-rolled `index.yml`) is `complete`, its stream `status` is **not** already `closed`, **and** it has no live worktree (`runtime.worktree` empty, or the path no longer resolves to a live `git worktree`) → **auto-close it**: set the stream file's `status: closed` and `merge.readiness: merged`, append a `merge.notes` line (*"auto-closed: milestone m-{id} complete + on main"*), refresh `updated_at`. Emit one line — *"auto-closed stale stream {id} — milestone m-{id} complete, already on main."* This is a legitimate source write (stream file = single-owner mutable; the milestone is done, so no live driver contends). **Guards:** a `deferred` linked milestone is **not** swept (its stream should pause, not close — Chief offers that interactively); a `complete` milestone **with a live worktree** is **not** swept here either — the forge-boot "Completed milestone + live worktree → finalize" path (SKILL Step 1) owns teardown, and closes the stream as part of it. Idempotent: an already-`closed` stream is skipped, so re-running the sweep is a no-op. No `streams/` dir, or nothing complete-and-open → the sweep is silent and the join runs unchanged.
|
|
267
|
-
1. Glob `streams/{stream}.yml`. Each → a row carrying its coordination state (`coordination` = the file's `status`), goal, runtime, ownership summary, `merge_readiness` (derived from the stream file's `merge.readiness`), `blocked_by`, `next_action` — all from the stream file.
|
|
268
|
-
2. For a stream with `stream.milestone: m-{id}`, read `phase`/activity from `milestone-{id}.yml` (`current.status`, `last_updated`) — **not** stored in the stream file. A linked milestone that is `deferred`/`complete`/absent → the row's `phase` reflects that.
|
|
269
|
-
3. Glob active milestones (from `index.yml`). Any active milestone with **no** stream file → emit a derived `stream: implicit` row (phase from the milestone, no coordination state) so coverage is guaranteed in the artifact — an active milestone can never be silently missing.
|
|
270
|
-
4. Derive `merge_queue:` — one entry per stream with `merge.readiness: ready`.
|
|
271
|
-
5. Write `active.yml` (`version`, `updated_at`, derived `streams:` sorted by id, derived `merge_queue:`). No hand-edited keys.
|
|
272
|
-
|
|
273
|
-
Because each field has exactly one source and coverage is computed, the two-registry drift class (issue #4) cannot occur — this **supersedes** the advisory Registry Drift Check shipped in 0.33.0.
|
|
274
|
-
**Format**: YAML for machine state, Markdown for human content.
|
|
275
|
-
**`current.status` is authoritative.** Complete only at `current.status == complete`. 100% tasks ≠ done — still needs verifying + reviewing + a recorded human sign-off (`current.human_verified` — see Verification Gates → Human Verification Gate).
|
|
189
|
+
State lives in `.forge/`. One line per artifact; protocol detail lives in the named ADRs and skills:
|
|
190
|
+
|
|
191
|
+
- `project.yml` — vision, stack, design system, verification, constraints (<5 KB)
|
|
192
|
+
- `constitution.md` — active architectural gates
|
|
193
|
+
- `design-system.md` — component mapping table
|
|
194
|
+
- `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`.
|
|
195
|
+
- `roadmap.yml` — phases, milestones, dependencies
|
|
196
|
+
- `state/index.yml` — DERIVED milestone registry, **git-ignored render-on-read cache** (0.53.0): regenerated at every boot by Rollup 1.0 (`forge` SKILL Step 1.0) from the milestone files; never committed, never hand-edited, never written by worktree agents; absent on a fresh clone (the project sentinel is `project.yml`). Rows carry the derived `release_state`.
|
|
197
|
+
- **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.
|
|
198
|
+
- `state/milestone-{id}.yml` — per-milestone cursor (**single source of truth**): position, decisions, blockers. One owner at a time.
|
|
199
|
+
- `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.
|
|
200
|
+
- `context.md` — active locked decisions + deferred ideas (≤12 KB); history archives to `context-archive.md`
|
|
201
|
+
- `streams/active.yml` — DERIVED Project Chief traffic map, git-ignored render-on-read cache — see Stream Rollup below ([ADR-015](../docs/decisions/ADR-015-derived-stream-registry.md))
|
|
202
|
+
- `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)
|
|
203
|
+
- `research/milestone-{id}.md` — dated immutable findings snapshot
|
|
204
|
+
- `phases/milestone-{id}/{phase}-{name}/plan-{NN}.md` — task plans with must_haves frontmatter (`{id}`=milestone, `{phase}`=phase# verbatim, `{name}`=kebab, `{NN}`=seq)
|
|
205
|
+
- `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
|
|
206
|
+
- `releases.yml` — append-only version-reservation registry (Version Reservation Protocol)
|
|
207
|
+
- `reservations.yml` — append-only id-reservation audit trail + cross-machine floor (ID Reservation Protocol)
|
|
208
|
+
- `archive/milestone-{id}/` — archived milestone artifacts (archive-delete)
|
|
209
|
+
- `prototypes/{slug}.md` — resumable disposable-mockup state (`exploring | parked | graduated | discarded`); terminal → `prototypes/archive/`. Single-owner, one driver. See `Skill(prototyping)`.
|
|
210
|
+
|
|
211
|
+
**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).
|
|
212
|
+
|
|
213
|
+
**Format:** YAML for machine state, Markdown for human content.
|
|
214
|
+
|
|
215
|
+
### Stream Rollup
|
|
216
|
+
|
|
217
|
+
`active.yml` is a pure projection — regenerated, never hand-edited — 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 — a done-and-merged milestone can never leave a zombie "ready to merge" row. Run by the main/orchestrator session at `forge` boot and `chief-of-staff` Show/Sync; worktrees never write it; milestone Rollup 1.0 runs **first** (the join reads the fresh `index.yml`). **Numbered procedure: the ADR-015 addendum.** Because each field has exactly one source and coverage is computed, two-registry drift cannot occur — supersedes the old advisory Registry Drift Check.
|
|
276
218
|
|
|
277
219
|
### State Commit Protocol
|
|
278
220
|
|
|
279
|
-
`.forge/` durable state is **committed**, not just written
|
|
221
|
+
`.forge/` durable state is **committed**, not just written — project state survives machine loss and pulls from any clone. At every phase **Handoff**, after writing state, the completing skill runs one scoped state-sync commit:
|
|
280
222
|
|
|
281
223
|
```
|
|
282
224
|
git add .forge/ # scoped — respects .gitignore; never `git add .`
|
|
283
225
|
git commit -m "chore(forge): sync state after {phase} — m{N} {phase-name}"
|
|
284
226
|
```
|
|
285
227
|
|
|
286
|
-
**In a worktree session, pin
|
|
287
|
-
|
|
288
|
-
State-sync commits are separate from per-task code commits (which stay atomic during executing).
|
|
228
|
+
**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).
|
|
289
229
|
|
|
290
230
|
### State Ownership (multi-worktree safety)
|
|
291
231
|
|
|
292
|
-
`.forge/` is code-like: it branches with the repo, syncs via git, and commits
|
|
293
|
-
with the work it describes. Every artifact has a sharing class:
|
|
232
|
+
`.forge/` is code-like: it branches with the repo, syncs via git, and commits with the work it describes. Every artifact has a sharing class (rationale: [ADR-011](../docs/decisions/ADR-011-shared-state-taxonomy.md) + addendum):
|
|
294
233
|
|
|
295
234
|
| Class | Files | Write rule |
|
|
296
235
|
|---|---|---|
|
|
297
|
-
| **Single-owner mutable** | `state/milestone-{id}.yml`, `phases/milestone-{id}/`, `research/milestone-{id}.md` | Exactly one writer at a time — the
|
|
298
|
-
| **Single-owner mutable (per stream)** | `streams/{stream}.yml`, `streams/{stream}/brief.md`, `streams/{stream}/packages/*.yml` | The stream's
|
|
299
|
-
| **Derived (git-ignored render-on-read cache)** | `state/index.yml`, `streams/active.yml`, the
|
|
300
|
-
| **Append-only shared** | `releases.yml
|
|
301
|
-
| **Machine-local runtime** | `.git/forge/id-reservations
|
|
302
|
-
| **Shared mutable** | `context.md`, `refactor-backlog.yml`, `requirements/m{N}.yml`
|
|
303
|
-
| **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md`, `.claude/skills/`, `.claude/agents/` | Rarely changes except via `/upgrading`. Canonical on main; worktrees lag until they rebase. An upgrade
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
the Live-Worktree Ownership Gate
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
explicit `lifecycle.ownership_override`. `discussing` and `reviewing` warn before
|
|
311
|
-
touching shared-mutable blocks; optional `forge.worktree_rebase_check` detects
|
|
312
|
-
stale shared files inside worktrees. See
|
|
313
|
-
[ADR-011](../docs/decisions/ADR-011-shared-state-taxonomy.md) for rationale.
|
|
314
|
-
|
|
315
|
-
### State Ownership rules (quick reference)
|
|
316
|
-
|
|
317
|
-
- `state/milestone-{id}.yml` is the **single source of truth**; exactly one agent owns it at a time. **Other worktrees never write it** — and from a main checkout this is **enforced**, not just advised: the Live-Worktree Ownership Gate (forge SKILL 1.1a) blocks milestone-owned writes from main while a live worktree owns the milestone, with a recorded `lifecycle.ownership_override` as the only (never-silent) bypass.
|
|
318
|
-
- Worktree / parallel agents write **only** their own milestone file and **append** desire-path files. They **never** write `index.yml`.
|
|
319
|
-
- `index.yml` is **regenerated by rollup** (read every `milestone-*.yml` → rewrite the registry) by the main/orchestrator session — on `forge` resume and at `orchestrating` teardown. The rollup is deterministic + idempotent, so it **is** the reconcile step — never a hand-merge.
|
|
320
|
-
- For shared-mutable files: write only your milestone's block; within a block, append-only (strike through, don't rewrite).
|
|
236
|
+
| **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). |
|
|
237
|
+
| **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. |
|
|
238
|
+
| **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`). |
|
|
239
|
+
| **Append-only shared** | `releases.yml`, `reservations.yml`, `state/desire-paths/*`, `deferred-issues/*` | Many writers OK; structure prevents collision (append-only entries / distinct filenames). |
|
|
240
|
+
| **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. |
|
|
241
|
+
| **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. |
|
|
242
|
+
| **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md`, `.claude/skills/`, `.claude/agents/` | Rarely changes except via `/upgrading`. 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. |
|
|
243
|
+
|
|
244
|
+
Ownership rules (quick reference):
|
|
245
|
+
|
|
246
|
+
- The milestone cursor has exactly one owner. From a main checkout this is **enforced**: the Live-Worktree Ownership Gate (`forge` SKILL 1.1a) blocks milestone-owned writes from main while a live worktree owns the milestone; a recorded `lifecycle.ownership_override` is the only — never-silent — bypass.
|
|
247
|
+
- Worktree/parallel agents write only their own milestone file and append desire-path files; they never write `index.yml` or `active.yml` — the rollup regenerates both and **is** the reconcile step, never a hand-merge.
|
|
248
|
+
- Cross-tree edits land on the current branch and are invisible to other worktrees until they pull/rebase; `forge` surfaces live worktrees at boot, and `discussing`/`reviewing` warn before touching shared-mutable blocks.
|
|
321
249
|
- Same-milestone parallel work needs Chief/Streams contracts; M10 file claims are optional defense-in-depth.
|
|
322
250
|
|
|
323
251
|
### Version Reservation Protocol
|
|
324
252
|
|
|
325
|
-
The project version + CHANGELOG slot are
|
|
326
|
-
|
|
327
|
-
- **Reserve early, at planning.** When a milestone's delivery will bump the version, the `planning` skill appends ONE entry to `.forge/releases.yml`: `{milestone, version, bump, reserved_at, summary}`. The reserved version = highest `version:` in the file bumped by the change's semver level (capability → minor; fix/doc → patch — see version-bump criteria below).
|
|
328
|
-
- **Append-only — never edit prior entries.** Distinct lines = no cross-session conflict. Commit + push the reservation BEFORE editing the version file, so a parallel session pulls and sees the number taken.
|
|
329
|
-
- **Delivery never invents a number.** The `executing`/delivery step writes only the version reserved in `releases.yml`, then its CHANGELOG entry. If no reservation exists (milestone planned before this file), it reserves at delivery: pull, take `max() + bump`, append, push, then write.
|
|
330
|
-
- **Race resolution.** Two near-simultaneous reservations: the second push rebases onto the first (append-only → clean), re-reads `max()`, takes the next number.
|
|
331
|
-
|
|
332
|
-
**Version-bump criteria (0.x projects):** patch (`0.x.y`) = bug fix, doc tweak, sync-only, refinement. Minor (`0.x.0`) = new skill/agent/routing-row/auto-trigger/state-artifact/capability. Major (`x.0.0`) = post-1.0 breaking change. Default to minor when in doubt — a capability addition shipped as a patch drifts the version away from truth.
|
|
253
|
+
The project version + CHANGELOG slot are shared resources — `.forge/releases.yml` (append-only) removes the number from per-milestone scope. **Reserve early, at planning**: append ONE `{milestone, version, bump, reserved_at, summary}` entry — the highest reserved version bumped by this change's semver level — 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.
|
|
333
254
|
|
|
334
255
|
### ID Reservation Protocol
|
|
335
256
|
|
|
336
|
-
Sequential
|
|
337
|
-
|
|
338
|
-
- **Reserve with the helper.** `forge-reserve <kind> --milestone <id> [--summary <text>]` (`.claude/hooks/forge-reserve.sh`, `kind ∈ {adr, def, fr, nfr, milestone, refactor}`) allocates the next number under a portable `mkdir` lock and prints it on stdout. Id formats differ per kind (ADR-023): `adr/def/fr/nfr` → `PREFIX-0NN` (hyphen, zero-padded); `milestone` → `M-NN` (hyphen, **unpadded** — ids are used bare, `milestone-26.yml`/`m-26`); `refactor` → `R0NN` (**no hyphen**, zero-padded — matches the backlog convention). It **dual-writes**: one TSV line to `.git/forge/id-reservations` (the machine-local coordination ledger) and one `{kind, id, milestone, reserved_at, summary}` block to the tracked `.forge/reservations.yml`. Neither is committed by the helper — **the caller commits `reservations.yml` with its work** (unchanged handoff). Reserve *before* creating the artifact; the printed id is the one to use.
|
|
339
|
-
- **Next number = `max(ledger ∪ in-tree ∪ main:reservations.yml) + 1` per kind.** Three inputs, unioned: the **ledger** (same-machine siblings, *including uncommitted* — the input ADR-016 could not see), the **in-tree** landed ids, and **`main:reservations.yml`** (the cross-machine / cold-start floor). The in-tree scan is per-kind: `adr` → `docs/decisions/ADR-NNN*`; `fr/nfr/def` → `.forge/requirements/*.yml`; `milestone` → live `state/milestone-*.yml` **∪ archived** `.forge/archive/milestone-*/`; `refactor` → `refactor-backlog.yml` **∪** `refactor-backlog-archive.yml` (ADR-023 — reading archives means a compacted/archived id is never reallocated). Taking all three inputs keeps it backward-compatible (landed & pre-ledger IDs respected) while giving the ledger authority for the same-machine hot path.
|
|
340
|
-
- **`reservations.yml` is now the durable audit trail + cross-machine floor**, not the coordination mechanism. Append-only, distinct lines → it unions cleanly at merge (it stops being a merge-conflict source). An optional `forge-reserve --verify` can diff ledger vs. `reservations.yml`.
|
|
341
|
-
- **Reserve points.** `architecting` reserves an `adr` before authoring it; `planning` reserves `fr`/`nfr`/`def` before writing them into requirements; the three milestone-id sites (`forge` Rollup, `discussing`, `prototyping`) reserve `milestone`; `reviewing` reserves `refactor` for a new backlog id — all via `forge-reserve` (ADR-023).
|
|
342
|
-
- **DI-NNN eliminated, not reserved (ADR-023).** `executing`'s deferred-*issue* ids used to be a scan-and-increment `DI-NNN` counter in a single `deferred-issues.md` — the same cross-worktree collision in kind. Rather than reserve them, deferred issues are now **counter-free per-issue files** under `.forge/deferred-issues/` (`{date}-{milestone}-{slug}.md`, the desire-path pattern): distinct filenames, no shared counter, nothing to collide on. Nothing cross-references a deferred issue by number, so the id density reservation buys is worthless here. Legacy `deferred-issues.md` is still read until migrated.
|
|
343
|
-
- **Cross-machine gap (accepted).** The ledger is machine-local (like `integration-pending`). Two *concurrent* worktrees on *different* laptops, both reserving before either merges, still fall back to merge-time renumber — bounded by the `main:reservations.yml` floor, so no worse than ADR-016.
|
|
344
|
-
- **Lazy migration.** No ledger ⇒ the helper creates it on first reserve, seeded by the `max()` (which reads in-tree + `main:reservations.yml`). Existing `reservations.yml` is untouched and still respected. Projects that never run concurrent worktrees see no behavior change.
|
|
345
|
-
|
|
346
|
-
This is the cross-worktree mechanism the FR/DEF/NFR "globally unique" rule (State Management, above) previously lacked, now made collision-safe for same-machine worktrees. Versions stay in `releases.yml` (separate semver/CHANGELOG semantics); everything else reserves through `forge-reserve`.
|
|
257
|
+
Sequential ids — `ADR-NNN`, `DEF-NNN`, `FR-`/`NFR-NNN`, milestone `M-NN`, refactor `R0NN` — 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`; id formats per [ADR-023](../docs/decisions/ADR-023-extend-id-reservation-to-milestone-refactor-ids.md)) 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), `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. Versions stay in `releases.yml` (separate semver/CHANGELOG semantics).
|
|
347
258
|
|
|
348
259
|
## Deviation Rules
|
|
349
260
|
|
|
@@ -373,34 +284,22 @@ verification:
|
|
|
373
284
|
max_retries: 2 # max attempts per command
|
|
374
285
|
```
|
|
375
286
|
|
|
376
|
-
|
|
377
|
-
- Advisory mode: pre-existing failures warn, don't block
|
|
378
|
-
- Auto-fix loop: read output → fix → amend → re-run (up to max_retries)
|
|
379
|
-
- 3-strike: retries count toward task limit
|
|
380
|
-
- Empty commands = no gate (opt-out)
|
|
381
|
-
- `verification.e2e_soft_cap` (default 10) — advisory cap on `e2e:true` stories per milestone surfaced by the `reviewing` skill. Soft — never blocks.
|
|
287
|
+
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.
|
|
382
288
|
|
|
383
289
|
### Truth checks (executable must_haves)
|
|
384
290
|
|
|
385
|
-
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
|
|
291
|
+
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.
|
|
386
292
|
|
|
387
293
|
### Human Verification Gate (close precondition)
|
|
388
294
|
|
|
389
|
-
**No milestone reaches `complete` and no orchestration worktree is torn down until a human has explicitly signed off** — recorded as `current.human_verified` in `milestone-{id}.yml`. Code-level verification (tests, lint,
|
|
390
|
-
|
|
391
|
-
- **Captured** by `verifying` — after the verdict it prompts for explicit sign-off and writes `current.human_verified: {at, method, notes}`. If the human can't verify yet (e.g. a device session is still pending), the field stays unset and downstream close blocks.
|
|
392
|
-
- **Enforced (hard block)** at both close points — `reviewing` refuses to set `current.status: complete`, and `orchestrating` Step 5 refuses teardown of **un-merged** work (see the teardown split below), unless `current.human_verified` is present.
|
|
393
|
-
- **Recorded override** is the only bypass. A human may explicitly close without verifying, but the skill writes `human_verified: {method: override, override: true, reason}` and surfaces it in the report. Silent close is impossible — an agent must **never** present milestone close / orchestration teardown as a peer alternative to "do the verification". The verification is a precondition, not an option.
|
|
394
|
-
|
|
395
|
-
Lazy migration: milestones with no `human_verified` field (pre-0.27.0) simply hit the prompt on their next close transition; already-`complete` milestones are never re-gated.
|
|
396
|
-
|
|
397
|
-
**Per-binding relocation (B5, operator-ratified 2026-07-15).** The gate above is the **`in_session_signoff`** binding — the default (`forge.validation_event` absent ⇒ this), preserved exactly. A repo that opts into **`validation_event: promotion_approval`** relocates the human gate to the **deploy boundary**: `complete` becomes the machine/code-verified state (`reviewing` closes without in-session sign-off, its health report noting *"human gate: at promotion (B5)"*), and the derived `release_state: validated` — computed by `forge-release-fold.sh` when a CI-signed promotion tag covers the unit — **is** the human gate (the full release_state ladder lands in State Management with phase 52). The mode is **not agent-flippable**: `validation_event`/`project.yml` sits on the step-2 **protected-paths** hold (F4/F5), so a diff flipping it blocks auto-merge for operator review.
|
|
398
|
-
|
|
399
|
-
**Teardown splits on merged-ness (operator ruling 2026-07-16 — binding-independent).** Worktree teardown auto-proceeds when the unit renders `merged`/`validated` via `forge-release-fold.sh` — the work is on main; removing the worktree loses nothing. The human gate applies only to **un-merged** teardown. The close gate is unaffected by this split — it keeps the per-binding rule above.
|
|
400
|
-
|
|
401
|
-
**Grandfather (legacy-complete marker).** A milestone already stored `current.status: complete` with **no** `signoff/<wu-id>` tag (the pre-M0 history — 26 milestones as of 0.53.0) is **grandfathered**: readers honor it as complete and it is **never re-gated** by any later sign-off convention. "Complete with no signoff tag" **is** the legacy-complete marker — no field is stamped onto those files. Only *new* completions going forward can be asked to carry a signature (that forward-gate is autonomous-lane and is **not** wired in the attended lane — see below).
|
|
295
|
+
**No milestone reaches `complete` and no un-merged orchestration worktree is torn down until a human has explicitly signed off** — recorded as `current.human_verified` in `milestone-{id}.yml`. Code-level verification (tests, lint, the 3-level goal-backward pass) is necessary but **never sufficient**.
|
|
402
296
|
|
|
403
|
-
|
|
297
|
+
- **Captured** by `verifying` — prompts for explicit sign-off after the verdict; if the human can't verify yet, the field stays unset and downstream close blocks.
|
|
298
|
+
- **Enforced (hard block)** at both close points — `reviewing` refuses `current.status: complete`, and `orchestrating` refuses teardown of un-merged work — unless the field is present.
|
|
299
|
+
- **Recorded override** is the only bypass (`human_verified: {method: override, override: true, reason}`), echoed in the report. Silent close is impossible; an agent must never present override as a peer alternative to doing the verification.
|
|
300
|
+
- **Teardown splits on merged-ness** (binding-independent): teardown auto-proceeds when the unit renders `merged`/`validated` via the fold — the work is on main, removal loses nothing; the human gate applies to **un-merged** teardown only. The close gate is unaffected by this split.
|
|
301
|
+
- **Bindings ([ADR-024](../docs/decisions/ADR-024-merged-validated-fold.md)):** default `in_session_signoff` preserves this gate exactly. `promotion_approval` relocates the human gate to the deploy boundary — `complete` becomes the machine-verified state and the derived `validated` (CI-signed promotion tag, verified offline) **is** the human gate. The mode is not agent-flippable (`validation_event` sits on protected paths).
|
|
302
|
+
- **Migration:** lazy — pre-gate milestones simply hit the prompt on their next close; milestones already `complete` with no `signoff/<wu-id>` tag are grandfathered, never re-gated. Where the M0 sign-off convention is adopted (`docs/sign-off-convention.md`), the authoritative predicate is `verify-signoff <wu-id>` exiting 0 — an SSH-signed tag an agent cannot forge; `current.human_verified` is then a derived echo, never the gate itself.
|
|
404
303
|
|
|
405
304
|
## Beads Integration (Optional)
|
|
406
305
|
|
|
@@ -408,7 +307,4 @@ With Beads installed: `bd prime` (session context), `bd ready` (unblocked tasks)
|
|
|
408
307
|
|
|
409
308
|
## Atomic Commits
|
|
410
309
|
|
|
411
|
-
One commit per task. Format: `{type}({scope}): {description}`
|
|
412
|
-
Types: `feat`, `fix`, `test`, `refactor`, `chore`, `docs`
|
|
413
|
-
Never `git add .` or `git add -A` — stage individually.
|
|
414
|
-
Phase handoffs additionally emit one scoped `chore(forge): sync state …` commit (see State Commit Protocol) so `.forge/` state never drifts out of git.
|
|
310
|
+
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.
|