forge-orkes 0.26.0 → 0.29.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/.claude/skills/discussing/SKILL.md +10 -0
- package/template/.claude/skills/forge/SKILL.md +27 -0
- package/template/.claude/skills/initializing/SKILL.md +32 -1
- package/template/.claude/skills/researching/SKILL.md +1 -0
- package/template/.claude/skills/reviewing/SKILL.md +13 -6
- package/template/.claude/skills/testing/SKILL.md +2 -0
- package/template/.claude/skills/upgrading/SKILL.md +41 -0
- package/template/.claude/skills/verifying/SKILL.md +18 -4
- package/template/.forge/FORGE.md +45 -4
- package/template/.forge/migrations/0.28.0-worktree-root.md +168 -0
- package/template/.forge/migrations/0.29.0-shared-state-taxonomy.md +68 -0
- package/template/.forge/templates/project.yml +10 -0
- package/template/.forge/templates/state/milestone.yml +15 -0
package/package.json
CHANGED
|
@@ -42,13 +42,23 @@ Never accumulate decisions in working memory. Never batch writes to convergence.
|
|
|
42
42
|
|
|
43
43
|
### Write Protocol
|
|
44
44
|
|
|
45
|
+
`context.md` is **shared mutable** state per FORGE.md State Ownership — writes follow two structural rules:
|
|
46
|
+
- **Scope to your milestone's block.** Different milestone blocks → git merges cleanly across worktrees.
|
|
47
|
+
- **Append-only within a block.** When superseding an older decision, *strike through* (`~~old decision~~`) and append the new line below — never rewrite in place. Same-line concurrent edits become impossible by construction; reading the history of a decision becomes possible by inspection.
|
|
48
|
+
|
|
45
49
|
**On first decision of the session:**
|
|
46
50
|
- Check if `.forge/context.md` exists. If not → create it from `.forge/templates/context.md`
|
|
47
51
|
- Add a milestone heading inside `## Locked Decisions`: `### M{id} — {name} (drafting)` (use "M?" if no milestone yet)
|
|
52
|
+
- **Cross-tree liveness check (informational).** If editing an existing block for milestone `{id}`, run `git worktree list --porcelain | awk '/^branch / && $2 ~ /refs\/heads\/forge\/m-'"$id"'(-|$)/ {print}'`. Any hit means m{id} is **live in another worktree** — surface one line: *"m{id} is live in worktree at `{path}`. Edits land cleanly on main but won't be visible to that worktree until it rebases or pulls."* Proceed with the write — main is often the canonical author of `context.md`, this is a heads-up, not a block.
|
|
48
53
|
|
|
49
54
|
**On each confirmed decision:**
|
|
50
55
|
- Append under the milestone heading: `- **[Topic]**: [Decision]. Reason: [Why]`
|
|
51
56
|
|
|
57
|
+
**On superseding a prior decision (in your own milestone's block):**
|
|
58
|
+
- Find the original line. Wrap it in `~~ ~~` (markdown strikethrough). DO NOT delete it.
|
|
59
|
+
- Append the new decision on a new line below it: `- **[Topic]**: [Decision]. Reason: [Why]. Supersedes ~~prior on {date}~~.`
|
|
60
|
+
- Why: shared-mutable append-only rule (FORGE.md State Ownership). Decisions stay readable as history; concurrent writes from another worktree on a different bullet can't conflict with this one.
|
|
61
|
+
|
|
52
62
|
**On deferred ideas** (user says "not now" / "later" / "skip"):
|
|
53
63
|
- Append to `## Deferred Ideas` immediately: `- [Idea] — Deferred because: [reason]`
|
|
54
64
|
|
|
@@ -9,6 +9,33 @@ Entry point. Detect tier, route skills, manage transitions. New projects → ini
|
|
|
9
9
|
|
|
10
10
|
## Step 1: Read State
|
|
11
11
|
|
|
12
|
+
**Preflight (multi-tree visibility) — run before everything in this section.**
|
|
13
|
+
|
|
14
|
+
The presence of live Forge worktrees changes the meaning of "which milestone am I editing" — the operator needs to see the picture before any state edit. Cheap to compute, free if there's nothing to show.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# This session's checkout — main or a worktree? --git-dir == --git-common-dir → main; differ → linked worktree.
|
|
18
|
+
this_dir=$(git rev-parse --git-dir 2>/dev/null) || exit 0
|
|
19
|
+
common_dir=$(git rev-parse --git-common-dir)
|
|
20
|
+
in_main_checkout=$([ "$this_dir" = "$common_dir" ] && echo true || echo false)
|
|
21
|
+
|
|
22
|
+
# Forge worktrees = branch matches forge/m-*
|
|
23
|
+
git worktree list --porcelain 2>/dev/null \
|
|
24
|
+
| awk '
|
|
25
|
+
/^worktree / { path=$2 }
|
|
26
|
+
/^branch / { br=$2; if (br ~ /refs\/heads\/forge\/m-/) print path " " br }
|
|
27
|
+
'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**If `in_main_checkout: true`** AND any Forge worktrees are reported:
|
|
31
|
+
- Surface them at the top of the boot output, one line each: *"m{id} is live in worktree `{path}` on branch `{branch}`. Edits to its milestone state belong there; shared-doc edits here (`context.md`, `refactor-backlog.yml`) won't be visible to it until it rebases or pulls."*
|
|
32
|
+
- This is informational — `forge` continues to Rollup + selection. The operator now knows. (See FORGE.md State Ownership for the full taxonomy.)
|
|
33
|
+
|
|
34
|
+
**If `in_main_checkout: false`** (this session is itself a worktree) AND `forge.worktree_rebase_check: true` in `.forge/project.yml` (default `false` — opt-in):
|
|
35
|
+
- Diff `.forge/` between this worktree's `HEAD` and `origin/main` (or `main` if no remote), restricted to the **shared-mutable** + **stable-shared** files per the FORGE.md taxonomy (`context.md`, `refactor-backlog.yml`, `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `requirements/m{N}.yml`).
|
|
36
|
+
- Any differ → surface: *"`{file}` has changed on main since this worktree branched. Pull just this file (`git restore --source main -- {file}`), rebase, or skip?"* — operator decides.
|
|
37
|
+
- Setting absent or `false` → no-op.
|
|
38
|
+
|
|
12
39
|
### 1.0 State Rollup (index.yml is derived)
|
|
13
40
|
|
|
14
41
|
`index.yml` is a **derived registry** — regenerate it from the milestone files before reading, and after any milestone CRUD (promote/defer/resume/delete). **Never hand-edit `index.yml`.**
|
|
@@ -355,7 +355,38 @@ User selects per stack.
|
|
|
355
355
|
- `.forge/state/index.yml` — regenerate via the `forge` **Rollup** from the milestone file (do not hand-write the registry). It will derive `status: not_started` for milestone 1.
|
|
356
356
|
- `.forge/state/desire-paths/` — create the (empty) directory for append-only observations.
|
|
357
357
|
6. Templates as needed
|
|
358
|
-
7. **
|
|
358
|
+
7. **Track Forge product files in `.gitignore`.** Forge installs into `.claude/` (skills, agents, hooks, `settings.json`) — these are *product files*, not per-machine config, and **must be tracked in git** for two reasons: (a) `/forge` commands only exist in checkouts that have `.claude/skills/`, so a git worktree with `.claude/` fully ignored has no `/forge`; (b) M10 worktrees inherit hooks via tracked files (`.claude/hooks/*.sh`) — an ignored `.claude/` silently disables them (see ADR-007 + ADR-010 "related concerns").
|
|
359
|
+
|
|
360
|
+
Detect the failure mode + apply the carve-out:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
if grep -qE '^[[:space:]]*\.claude/?[[:space:]]*$' .gitignore 2>/dev/null && \
|
|
364
|
+
! grep -qE '^![[:space:]]*\.claude/(skills|agents|hooks)' .gitignore; then
|
|
365
|
+
echo "[Forge] .gitignore ignores .claude/ wholesale — Forge worktrees won't have /forge."
|
|
366
|
+
fi
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Then **replace** any bare `.claude/` rule (or **append** if no `.gitignore` exists) with the recommended carve-out:
|
|
370
|
+
|
|
371
|
+
```gitignore
|
|
372
|
+
# Claude Code — track Forge product files, ignore per-machine + scratch
|
|
373
|
+
.claude/*
|
|
374
|
+
.claude/.DS_Store
|
|
375
|
+
!.claude/settings.json
|
|
376
|
+
!.claude/skills/
|
|
377
|
+
!.claude/agents/
|
|
378
|
+
!.claude/hooks/
|
|
379
|
+
!.claude/commands/
|
|
380
|
+
.claude/settings.local.json
|
|
381
|
+
.claude/projects/
|
|
382
|
+
.claude/worktrees/
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
`settings.local.json` (per-machine permission allowlists), `projects/` (Claude Code conversation transcripts), and `worktrees/` (app-managed scratch) **must stay ignored** — they're private/per-machine, not product.
|
|
386
|
+
|
|
387
|
+
**Confirm with the user first** in brownfield (this edits a user-owned file). In greenfield with no existing `.gitignore`, write it directly. Re-run is idempotent — the carve-out lines `grep` to themselves.
|
|
388
|
+
|
|
389
|
+
8. **State-sync commit**: `git add .gitignore .claude/settings.json .claude/skills/ .claude/agents/ .claude/hooks/ .forge/` then `git commit -m "chore(forge): initialize forge state + track product files"` (scoped; never `git add .`) — so the new project's state and Forge product files are both in git from the start.
|
|
359
390
|
|
|
360
391
|
*"Initialized. Ready?"*
|
|
361
392
|
|
|
@@ -79,6 +79,7 @@ Tag every finding:
|
|
|
79
79
|
|
|
80
80
|
For independent topics, research simultaneously:
|
|
81
81
|
- Spawn separate research agents per topic with focused scope
|
|
82
|
+
- **Pass `model` param** from `project.yml` model routing (`models.skills.researching` → `models.default` → parent). Display: *"Spawning researchers with model: {model} (from {source})"*. Subagents don't inherit skill routing — without the param they run on the parent (often opus), defeating the cost intent.
|
|
82
83
|
- Collect and synthesize results
|
|
83
84
|
|
|
84
85
|
Never research sequentially when topics are independent.
|
|
@@ -312,6 +312,12 @@ Deferred issues triage: If `.forge/deferred-issues.md` has `status: pending` ite
|
|
|
312
312
|
|
|
313
313
|
### Backlog
|
|
314
314
|
|
|
315
|
+
`refactor-backlog.yml` is **shared mutable** state per FORGE.md State Ownership — many milestones append over time. Two rules apply:
|
|
316
|
+
- **Items carry `milestone:` scoping** (already enforced by the schema below) — concurrent appends from different milestones touch different items, so git merges cleanly.
|
|
317
|
+
- **Existing items are append-only** in spirit: change `status:` and add `completed:`/`deferred_at:` rather than rewriting the item's body. Compaction-on-write (below) handles physical relocation of terminal items.
|
|
318
|
+
|
|
319
|
+
**Cross-tree liveness check (informational).** Before writing, run `git worktree list --porcelain | awk '/^branch / && $2 ~ /refs\/heads\/forge\/m-/ {print}'`. Any non-empty output means another milestone is live in a worktree — surface one line: *"{N} other Forge milestone(s) live in worktrees ({list}). Backlog appends here land cleanly on main but won't be visible to those worktrees until they rebase."* Proceed with the write — reviewing on main is the canonical author. (Two reviewing sessions writing in parallel from different worktrees rely on the milestone-scoped append rule above, not on this check.)
|
|
320
|
+
|
|
315
321
|
Read `.forge/refactor-backlog.yml`. Next ID = max + 1. Append:
|
|
316
322
|
|
|
317
323
|
```yaml
|
|
@@ -350,7 +356,7 @@ Idempotent: a backlog with no terminal items and all-canonical statuses is left
|
|
|
350
356
|
|
|
351
357
|
### Route
|
|
352
358
|
|
|
353
|
-
**HEALTHY/WARNINGS (accepted):** set `current.status: complete` in `milestone-{id}.yml
|
|
359
|
+
**HEALTHY/WARNINGS (accepted):** set `current.status: complete` in `milestone-{id}.yml` (only after the Human Verification Gate in Phase Handoff is satisfied), then regenerate `index.yml` via the `forge` **Rollup** (do not hand-edit index). *"Milestone [{name}] complete. {N} backlog items."* Beads: `bd complete`.
|
|
354
360
|
|
|
355
361
|
**CRITICAL:** Don't complete. A) Fix->`planning` fix mode->re-verify->re-review. B) Accept risk->doc in report->complete.
|
|
356
362
|
|
|
@@ -400,8 +406,9 @@ If the milestone's phases produced `contract.md` files (planning Step 6.1 Tier 1
|
|
|
400
406
|
## Phase Handoff
|
|
401
407
|
|
|
402
408
|
1. Confirm report + backlog
|
|
403
|
-
2. **
|
|
404
|
-
3. **Run
|
|
405
|
-
4.
|
|
406
|
-
5.
|
|
407
|
-
6.
|
|
409
|
+
2. **Human Verification Gate (hard block)** — Read `current.human_verified` from `milestone-{id}.yml`. If **absent/null** → **do not complete the milestone.** Code-clean + review-clean is not enough to close (FORGE.md → Human Verification Gate). The milestone needs an explicit human sign-off, normally captured by `verifying`. Either route the user back to verify (then re-review) or capture the sign-off / recorded override here and write `current.human_verified` before proceeding. A recorded override (`method: override`) satisfies this check but **must** be surfaced in the health report. Never silently complete past an unset gate.
|
|
410
|
+
3. **Run promoted-milestone completion hook** (above) if `milestone.origin` set
|
|
411
|
+
4. **Run Contract Landing** (above) for any cross-layer phases — fold ratified contracts into their ADRs
|
|
412
|
+
5. Set `current.status: complete` and `current.completed_at: "<ISO 8601 timestamp>"` in `milestone-{id}.yml`, then regenerate `index.yml` via the `forge` **Rollup**
|
|
413
|
+
6. **State-sync commit** (State Commit Protocol): `git add .forge/` then `git commit -m "chore(forge): sync state after reviewing — m{N} complete"` (scoped; never `git add .`).
|
|
414
|
+
7. *"Milestone [{name}] complete. Report: `.forge/audits/milestone-{id}-health-report.md`. {N} backlog items. `/forge` or backlog."*
|
|
@@ -42,6 +42,7 @@ Read: .github/workflows/* → CI config (ci-check mode, analyst CI sub-check)
|
|
|
42
42
|
|
|
43
43
|
1. Spawn tester agent via Agent tool, mode = `analyst`:
|
|
44
44
|
- Pass: milestone id + name, scope paths, stack summary from project.yml
|
|
45
|
+
- **Pass `model` param** from `project.yml` model routing (`models.skills.testing` → `models.default` → parent). Display: *"Spawning tester (analyst) with model: {model} (from {source})"*
|
|
45
46
|
- Agent scans test files, runs suite with traces/retries, greps anti-patterns
|
|
46
47
|
2. Agent writes `.forge/testing/suite-health.md`:
|
|
47
48
|
- **Coverage Gaps** — untested surfaces, missing layers
|
|
@@ -106,6 +107,7 @@ Refusal message wording is contract (NFR-009 requires story ID + exact missing f
|
|
|
106
107
|
- If project has existing test runner, match it. Don't introduce a second.
|
|
107
108
|
3. Spawn tester agent via Agent tool, mode = `author`:
|
|
108
109
|
- Pass: milestone id + name, layer, runner, scope paths, stack summary
|
|
110
|
+
- **Pass `model` param** from `project.yml` model routing (`models.skills.testing` → `models.default` → parent). Display: *"Spawning tester (author) with model: {model} (from {source})"*
|
|
109
111
|
- Agent scaffolds tests following baked flake-resistant rules (see tester.md)
|
|
110
112
|
4. Agent commits atomically per executor conventions.
|
|
111
113
|
|
|
@@ -266,6 +266,47 @@ No-op guarantee: detection exits clean (no prompt) when the backlog is absent, u
|
|
|
266
266
|
|
|
267
267
|
`upgrading` never edits the backlog directly — migration runs via `quick-tasking`.
|
|
268
268
|
|
|
269
|
+
### Pre-0.28.0 fully-ignored `.claude/`
|
|
270
|
+
|
|
271
|
+
Run from project root:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
F=.gitignore
|
|
275
|
+
[ -f "$F" ] || exit 0
|
|
276
|
+
# bare ".claude/" or ".claude" rule (no negation lines un-ignoring product files)
|
|
277
|
+
if grep -qE '^[[:space:]]*\.claude/?[[:space:]]*$' "$F" \
|
|
278
|
+
&& ! grep -qE '^![[:space:]]*\.claude/(skills|agents|hooks|settings\.json)' "$F"; then
|
|
279
|
+
echo "broad-ignore"
|
|
280
|
+
fi
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
If the script prints `broad-ignore`, surface:
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
.claude/ fully ignored — Forge worktrees + hooks silently break (Forge 0.28.0)
|
|
287
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
288
|
+
Your .gitignore ignores all of `.claude/` without a carve-out. That means:
|
|
289
|
+
• git worktrees (Forge or the app's) have no `.claude/skills/`, so `/forge`
|
|
290
|
+
is missing — typing `/forge` in a worktree prints "Unknown command".
|
|
291
|
+
• M10 worktrees come up with no hooks (forge-claim-check, branch-guard,
|
|
292
|
+
session-id) — coordination + ADR-008 protection are silently disabled.
|
|
293
|
+
|
|
294
|
+
These are PRODUCT files, not per-machine config. The fix is a narrow
|
|
295
|
+
carve-out: track skills/agents/hooks/settings.json; keep settings.local.json,
|
|
296
|
+
projects/, worktrees/ ignored.
|
|
297
|
+
|
|
298
|
+
A migration guide is available at: .forge/migrations/0.28.0-worktree-root.md
|
|
299
|
+
(canonical: https://github.com/Attuned-Media/forge/blob/main/docs/migrations/0.28.0-worktree-root.md)
|
|
300
|
+
|
|
301
|
+
Apply the carve-out now? (yes/no/show guide)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
- **yes** → invoke `quick-tasking` skill with the migration guide as the task (edit `.gitignore` in place, `git rm -r --cached .claude/` to clear the ignore-cache, stage `.gitignore` + the four product trees, commit `chore(forge): track .claude/ product files`). The skill MUST confirm with the user before staging anything outside the four product trees.
|
|
305
|
+
- **show guide** → read and display the file, then re-ask
|
|
306
|
+
- **no** → note in upgrade report. The framework keeps working in the main checkout but worktree-mode sessions (M10 / Claude Desktop folder-open) will be missing `/forge` and Forge hooks until migrated.
|
|
307
|
+
|
|
308
|
+
This is a Forge-product-tracking concern, not a state migration — `upgrading` never edits user `.gitignore` directly. Migration runs via `quick-tasking`.
|
|
309
|
+
|
|
269
310
|
### Future migrations
|
|
270
311
|
|
|
271
312
|
Add new detection blocks here for each Forge version that changes file layout. Pattern:
|
|
@@ -236,6 +236,19 @@ Items that can't be verified automatically (visual appearance, real-time behavio
|
|
|
236
236
|
3. [ ] External: Email sends correctly via SendGrid
|
|
237
237
|
```
|
|
238
238
|
|
|
239
|
+
## Human Verification Gate (close precondition)
|
|
240
|
+
|
|
241
|
+
Code-level PASS is necessary but **not sufficient** to close a milestone. Before handing off, capture an explicit human sign-off — this is the hard gate that `reviewing`-complete and `orchestrating`-teardown both check (see FORGE.md → Human Verification Gate). It is a precondition, not a peer option: never present milestone close / teardown as an alternative to running this.
|
|
242
|
+
|
|
243
|
+
Run on a PASSED verdict (and after any **HUMAN VERIFICATION NEEDED** items are resolved):
|
|
244
|
+
|
|
245
|
+
1. Surface what the human should confirm — the Observable Truths, any "Human Verification Items", and any milestone-specific manual check (device session, visual pass, real-device / e2e walk).
|
|
246
|
+
2. Prompt explicitly: *"Code verification passed. Have you verified the work yourself (device session / visual / e2e walk)? This is required before the milestone can close. [verified | not yet | close without verifying]"*
|
|
247
|
+
3. Record the response in `current.human_verified` in `.forge/state/milestone-{id}.yml`:
|
|
248
|
+
- **verified** → `{at: "<ISO 8601>", method: "<how they verified>", notes: "<optional>"}`
|
|
249
|
+
- **not yet** → leave `human_verified` unset. **Do NOT route to reviewing** — the milestone cannot close. Tell the human what's outstanding and stop. Re-run this gate after they've done it.
|
|
250
|
+
- **close without verifying** → recorded override: `{at: "<ISO 8601>", method: "override", override: true, reason: "<required free text>"}`. Note the override in the verification report. Satisfies the gate but is flagged downstream.
|
|
251
|
+
|
|
239
252
|
## Re-Verification Mode
|
|
240
253
|
|
|
241
254
|
After gap closure:
|
|
@@ -289,9 +302,10 @@ Only suggest at 3+ occurrences. One-off issues are noise.
|
|
|
289
302
|
|
|
290
303
|
After PASSED verdict:
|
|
291
304
|
|
|
292
|
-
1. **
|
|
293
|
-
2. **
|
|
294
|
-
3. **
|
|
295
|
-
4. **
|
|
305
|
+
1. **Human Verification Gate** — capture explicit sign-off and write `current.human_verified` (see "Human Verification Gate" above). If the human answers **not yet** → STOP here; do not advance to reviewing. The milestone stays open until sign-off (or a recorded override) exists.
|
|
306
|
+
2. **Persist** — Confirm verification report documented, desire-path files written to `.forge/state/desire-paths/`
|
|
307
|
+
3. **Update state** — Set `current.status` to `reviewing` in `.forge/state/milestone-{id}.yml`
|
|
308
|
+
4. **State-sync commit** (State Commit Protocol): `git add .forge/` then `git commit -m "chore(forge): sync state after verifying — m{N} {phase-name}"` (scoped; never `git add .`).
|
|
309
|
+
5. **Recommend clear:** *"State synced. `/clear` then `/forge` for reviewing."*
|
|
296
310
|
|
|
297
311
|
If GAPS found, route back to planning in gap-closure mode. Context clear applies after re-verified PASSED verdict.
|
package/template/.forge/FORGE.md
CHANGED
|
@@ -51,8 +51,8 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
|
51
51
|
| Architectural decisions | `architecting` | Full |
|
|
52
52
|
| Break work into tasks with gates | `planning` | Standard, Full |
|
|
53
53
|
| Build with deviation rules + atomic commits | `executing` | All |
|
|
54
|
-
| Prove work delivers on goals (+ M9 e2e validation gate when `e2e:true` stories present) | `verifying` | Standard, Full |
|
|
55
|
-
| Audit health + catalog refactoring (+ M9 e2e soft-cap, orphan-test, flake-rate audits) | `reviewing` | Standard, Full |
|
|
54
|
+
| Prove work delivers on goals (+ M9 e2e validation gate when `e2e:true` stories present; captures the Human Verification Gate sign-off) | `verifying` | Standard, Full |
|
|
55
|
+
| Audit health + catalog refactoring (+ M9 e2e soft-cap, orphan-test, flake-rate audits; hard-blocks completion on the Human Verification Gate) | `reviewing` | Standard, Full |
|
|
56
56
|
| Small scoped fix | `quick-tasking` | Quick |
|
|
57
57
|
| UI with design system | `designing` | When UI |
|
|
58
58
|
| Security review | `securing` | When auth/data/API |
|
|
@@ -102,6 +102,8 @@ models:
|
|
|
102
102
|
**Precedence:** `skills.X` → `default` → parent model.
|
|
103
103
|
**All advisory** — forge displays expected model at each transition, suggests `/model` on mismatch. Review gate logs model used. Cannot auto-switch.
|
|
104
104
|
|
|
105
|
+
**Subagent inheritance.** When a skill spawns subagents via the Agent tool (parallel research, fresh-context reviewers, executor fan-out, tester author/analyst, etc.), the skill MUST pass the resolved `model` param explicitly. Subagents do NOT inherit skill-level routing automatically — without the param they run on the parent session's model, defeating the routing intent. Resolve using the same precedence chain (`models.skills.{skill}` → `models.default` → parent) and surface it: *"Spawning {role} with model: {model} (from {source})"*.
|
|
106
|
+
|
|
105
107
|
## Agents
|
|
106
108
|
|
|
107
109
|
| Agent | Role | Tools | When |
|
|
@@ -145,7 +147,7 @@ State lives in `.forge/`:
|
|
|
145
147
|
**Milestones** group phases into concurrent streams. Own state file — no conflicts across sessions. Can be deferred (frozen in place) or archive-deleted.
|
|
146
148
|
`index.yml status` gates routing: `not_started | active | deferred | complete`.
|
|
147
149
|
**Format**: YAML for machine state, Markdown for human content.
|
|
148
|
-
**`current.status` is authoritative.** Complete only at `current.status == complete`. 100% tasks ≠ done — still needs verifying + reviewing.
|
|
150
|
+
**`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).
|
|
149
151
|
|
|
150
152
|
### State Commit Protocol
|
|
151
153
|
|
|
@@ -160,9 +162,38 @@ State-sync commits are separate from per-task code commits (which stay atomic du
|
|
|
160
162
|
|
|
161
163
|
### State Ownership (multi-worktree safety)
|
|
162
164
|
|
|
163
|
-
|
|
165
|
+
`.forge/` is **code-like**: it branches with the repo, syncs via git, atomic-commits with the work it describes. Worktrees get their own `.forge/` checkout by construction — that's not configuration, that's git. The framework's job is to specify how each *kind* of `.forge/` file behaves under that model.
|
|
166
|
+
|
|
167
|
+
**Every `.forge/` artifact falls into one of five sharing classes.** The class determines the write rule across worktrees:
|
|
168
|
+
|
|
169
|
+
| Class | Files | Write rule |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| **Single-owner mutable** | `state/milestone-{id}.yml`, `phases/milestone-{id}/`, `research/milestone-{id}.md` | Exactly one writer at a time — the worktree (or main session) currently driving that milestone. **Other worktrees never touch it**, not even to read-then-write — they pull from main if they need it. |
|
|
172
|
+
| **Derived** | `state/index.yml` | Never hand-edited. Regenerated by Rollup 1.0 from `milestone-*.yml`. Only the main/orchestrator session runs rollup. |
|
|
173
|
+
| **Append-only shared** | `releases.yml` (version reservations), `state/desire-paths/*` (one file per observation) | Many writers OK; structure prevents collision. `releases.yml` uses the Version Reservation Protocol (append + commit + push before depending on the slot); desire-paths use distinct filenames so two writers never touch the same file. |
|
|
174
|
+
| **Shared mutable** | `context.md`, `refactor-backlog.yml`, `requirements/m{N}.yml` (ID space `FR-`/`DEF-`/`NFR-` is globally shared even though each milestone owns its file) | Two rules: **(a) Write only to YOUR milestone's block.** Different milestone blocks → git merges cleanly. **(b) Within a block, append-only.** Locked decisions get *struck through* (`~~old~~`) rather than rewritten in place; new sub-bullets appended below existing ones. Same-line concurrent edits become impossible by construction. |
|
|
175
|
+
| **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md` | Rarely changes after init. Canonical on main. Worktrees lag and pull on rebase. No special protocol — git handles it because the conflict surface is tiny. |
|
|
176
|
+
|
|
177
|
+
**Cross-tree write awareness.** When a session edits a shared-mutable file's block whose milestone is **live in a different worktree** (e.g. main writes to `context.md`'s `## M9` block while m9 is running in a worktree), the edit lands cleanly on main but is **invisible to the worktree until it pulls/rebases**. This is identical to how `src/foo.ts` works under branches — there's nothing pathological about it; it's branch divergence. The framework surfaces the situation so the operator can decide:
|
|
178
|
+
|
|
179
|
+
- **`forge` Step 1** in main checks `git worktree list` and surfaces live Forge worktrees at boot — *"m9 is live in worktree X at e94b6bb. Edits to m9 state belong there; shared docs edited here need a sync."*
|
|
180
|
+
- **`discussing`** (before writing to `context.md`'s milestone block) and **`reviewing`** (before writing to `refactor-backlog.yml`) emit a one-line warning when the target block's milestone is live elsewhere. The warning informs, never blocks — main is often the canonical author of these files.
|
|
181
|
+
- **Worktree-side rebase check** (opt-in via `forge.worktree_rebase_check: true` in `project.yml`) — when `forge` boots inside a worktree, it diffs `.forge/` between the worktree's HEAD and `main`; if shared-mutable files have changed on main, it offers `git restore --source main -- <files>` or a rebase.
|
|
182
|
+
|
|
183
|
+
**Why not global `.forge/`?** A common instinct is "make `.forge/` shared so context propagates automatically." It breaks four load-bearing invariants:
|
|
184
|
+
1. **Decisions are contracts** — they're versioned with the code they govern; severing them from branches breaks the contract.
|
|
185
|
+
2. **State survives machine loss** — the multi-laptop pull-from-any-clone story depends on `.forge/` being in git.
|
|
186
|
+
3. **History time-travel** — `git checkout` an old commit and you see the plan/decisions as they were; global state makes that impossible.
|
|
187
|
+
4. **Git is the concurrency detector** — without it, two sessions writing the same field becomes silent last-write-wins.
|
|
188
|
+
|
|
189
|
+
Per-worktree `.forge/` with a sharing taxonomy is the model. See [ADR-011](../docs/decisions/ADR-011-shared-state-taxonomy.md) for the longer version.
|
|
190
|
+
|
|
191
|
+
### State Ownership rules (quick reference)
|
|
192
|
+
|
|
193
|
+
- `state/milestone-{id}.yml` is the **single source of truth**; exactly one agent owns it at a time. **Other worktrees never write it** — promoted from advice to explicit rule, because catching yourself before the first wrong edit is the part the framework can help with.
|
|
164
194
|
- Worktree / parallel agents write **only** their own milestone file and **append** desire-path files. They **never** write `index.yml`.
|
|
165
195
|
- `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.
|
|
196
|
+
- For shared-mutable files: write only your milestone's block; within a block, append-only (strike through, don't rewrite).
|
|
166
197
|
- Same-milestone parallel work is out of scope, guarded by the M10 claim layer.
|
|
167
198
|
|
|
168
199
|
### Version Reservation Protocol
|
|
@@ -211,6 +242,16 @@ verification:
|
|
|
211
242
|
- Empty commands = no gate (opt-out)
|
|
212
243
|
- `verification.e2e_soft_cap` (default 10) — advisory cap on `e2e:true` stories per milestone surfaced by the `reviewing` skill. Soft — never blocks.
|
|
213
244
|
|
|
245
|
+
### Human Verification Gate (close precondition)
|
|
246
|
+
|
|
247
|
+
**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, type-check, the 3-level goal-backward pass) is necessary but **never sufficient** to close a milestone. A human must confirm the work in whatever form fits the milestone — device session, visual check, e2e walk, smoke test ("of some sorts").
|
|
248
|
+
|
|
249
|
+
- **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.
|
|
250
|
+
- **Enforced (hard block)** at both close points — `reviewing` refuses to set `current.status: complete`, and `orchestrating` Step 5 refuses teardown, unless `current.human_verified` is present.
|
|
251
|
+
- **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.
|
|
252
|
+
|
|
253
|
+
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.
|
|
254
|
+
|
|
214
255
|
## Beads Integration (Optional)
|
|
215
256
|
|
|
216
257
|
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.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Migration Guide: Repo-scoped worktree root (Forge 0.28.0)
|
|
2
|
+
|
|
3
|
+
Applies to projects using M10 orchestration (experimental). Two related concerns ship under one version:
|
|
4
|
+
|
|
5
|
+
1. **Worktree dir default changes** from a shared `../forge-worktrees/` to a per-repo `../<repo>-worktrees/` (see [ADR-010](../decisions/ADR-010-repo-scoped-worktree-root.md)). Live worktrees keep working; only new ones use the new default.
|
|
6
|
+
2. **`.gitignore` carve-out for Forge product files** — repos that ignore `.claude/` wholesale silently break worktree mode (`/forge` is "Unknown command" inside any worktree). 0.28.0 ships detection + a guided fix.
|
|
7
|
+
|
|
8
|
+
If you don't use M10, the worktree-dir change has no effect. If your `.gitignore` is broadly ignoring `.claude/`, the second part still applies (the same gap also affects Claude Desktop's native worktree switcher).
|
|
9
|
+
|
|
10
|
+
## Part 1 — Worktree dir default
|
|
11
|
+
|
|
12
|
+
### What changed
|
|
13
|
+
|
|
14
|
+
Before:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git worktree add ../forge-worktrees/${anchor} main # shared, cwd-resolved
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
After:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# orchestration.worktree_root from .forge/project.yml, default ../<repo>-worktrees
|
|
24
|
+
# Relative paths resolve against the REPO ROOT (not shell cwd). Absolute + leading ~ honored.
|
|
25
|
+
git worktree add ${wt_root}/${anchor} main
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The resolved absolute path is recorded in `lifecycle.worktree_path` and read verbatim by teardown + crash-recovery — so the config knob is forward-looking, not retroactive.
|
|
29
|
+
|
|
30
|
+
### Detection
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Are any of your active milestones pointing at the old shared dir?
|
|
34
|
+
grep -rE '^\s*worktree_path:.*forge-worktrees' .forge/state/ 2>/dev/null | head
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Matches = pre-0.28.0 worktrees still in flight. **Leave them alone** — they keep working off their recorded path. Only **new** worktrees pick up the new default.
|
|
38
|
+
|
|
39
|
+
### Migration
|
|
40
|
+
|
|
41
|
+
**Do nothing.** This is a new-worktree-only change. Future orchestration runs in this repo will create their worktrees in `../<repo>-worktrees/<anchor>` instead of `../forge-worktrees/<anchor>`. Existing worktrees keep functioning; their `lifecycle.worktree_path` is honored.
|
|
42
|
+
|
|
43
|
+
### Opting back into the old layout
|
|
44
|
+
|
|
45
|
+
If you want the old behavior (shared dir, e.g. because you've already got tooling pointed at `../forge-worktrees/`), set in `.forge/project.yml`:
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
orchestration:
|
|
49
|
+
worktree_root: "../forge-worktrees" # relative to repo root
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Other layout choices the new key enables
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
orchestration:
|
|
56
|
+
worktree_root: "~/.forge/worktrees/<this-repo>" # central home dir
|
|
57
|
+
# or
|
|
58
|
+
worktree_root: "../wt/<this-repo>" # shared dir, repo-namespaced subfolder
|
|
59
|
+
# or
|
|
60
|
+
worktree_root: "/abs/path/to/somewhere" # absolute
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Do not** point this inside the working tree (e.g. `.worktrees/`) — file watchers, language-server indexers, test discovery, and bundlers commonly recurse into the second checkout regardless of `.gitignore`. ADR-010 has the longer analysis.
|
|
64
|
+
|
|
65
|
+
### Relocating a live worktree (only if you really need to)
|
|
66
|
+
|
|
67
|
+
Use `git worktree move` — it updates the gitdir pointer. A bare `mv` leaves the pointer stale and the worktree unusable.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# from the repo root
|
|
71
|
+
git worktree move ../forge-worktrees/m-9-abc12345 ../<repo>-worktrees/m-9-abc12345
|
|
72
|
+
# then update the recorded path in milestone state:
|
|
73
|
+
# .forge/state/milestone-9.yml → lifecycle.worktree_path
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Confirm the worktree opens cleanly (`cd <new-path> && git status`) before editing state. **Don't relocate a worktree that's an active orchestration run** without checking with the running session first — its claim state references that path.
|
|
77
|
+
|
|
78
|
+
## Part 2 — `.gitignore` carve-out for Forge product files
|
|
79
|
+
|
|
80
|
+
### Why this matters
|
|
81
|
+
|
|
82
|
+
Forge installs into `.claude/` (skills, agents, hooks, `settings.json`). Many Claude Code starters add `.claude/` to `.gitignore` wholesale. Consequences:
|
|
83
|
+
|
|
84
|
+
- **`/forge` is "Unknown command:" in any git worktree.** Worktrees only check out *tracked* files. With `.claude/` fully ignored, `.claude/skills/forge/` doesn't exist in worktrees, so the slash command isn't loaded. Same applies to Claude Desktop's native worktree switcher.
|
|
85
|
+
- **M10 worktrees come up with no hooks.** `forge-claim-check.sh`, `forge-branch-guard.sh`, `forge-session-id.sh` all live in `.claude/hooks/` — ignored = absent = silently disabled. ADR-007 / ADR-008 protection are off.
|
|
86
|
+
|
|
87
|
+
The fix: track product files, keep per-machine/scratch files ignored.
|
|
88
|
+
|
|
89
|
+
### Detection
|
|
90
|
+
|
|
91
|
+
`upgrading` runs this automatically; you can run it by hand too:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
F=.gitignore
|
|
95
|
+
[ -f "$F" ] || exit 0
|
|
96
|
+
if grep -qE '^[[:space:]]*\.claude/?[[:space:]]*$' "$F" \
|
|
97
|
+
&& ! grep -qE '^![[:space:]]*\.claude/(skills|agents|hooks|settings\.json)' "$F"; then
|
|
98
|
+
echo "broad-ignore — apply the carve-out below"
|
|
99
|
+
fi
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Migration
|
|
103
|
+
|
|
104
|
+
Replace any bare `.claude/` rule with this carve-out:
|
|
105
|
+
|
|
106
|
+
```gitignore
|
|
107
|
+
# Claude Code — track Forge product files, ignore per-machine + scratch
|
|
108
|
+
.claude/*
|
|
109
|
+
.claude/.DS_Store
|
|
110
|
+
!.claude/settings.json
|
|
111
|
+
!.claude/skills/
|
|
112
|
+
!.claude/agents/
|
|
113
|
+
!.claude/hooks/
|
|
114
|
+
!.claude/commands/
|
|
115
|
+
.claude/settings.local.json
|
|
116
|
+
.claude/projects/
|
|
117
|
+
.claude/worktrees/
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Then refresh git's view of the directory:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
git rm -r --cached .claude/ 2>/dev/null # drop the wholesale-ignored cache
|
|
124
|
+
git status .claude/ # eyeball what's now untracked
|
|
125
|
+
|
|
126
|
+
# Stage only the four product trees — explicitly, never `git add .claude/`
|
|
127
|
+
git add .gitignore \
|
|
128
|
+
.claude/settings.json \
|
|
129
|
+
.claude/skills/ \
|
|
130
|
+
.claude/agents/ \
|
|
131
|
+
.claude/hooks/
|
|
132
|
+
|
|
133
|
+
# Sanity check — no per-machine files snuck in
|
|
134
|
+
git status # settings.local.json, projects/, worktrees/ should still be untracked-and-ignored
|
|
135
|
+
git diff --cached --stat | head
|
|
136
|
+
|
|
137
|
+
git commit -m "chore(forge): track .claude/ product files (skills, agents, hooks, settings)"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
After the commit lands on `main`, every **new** worktree (Forge's or the app's) inherits `/forge` and the hooks. Existing worktrees will see them on their next pull/rebase.
|
|
141
|
+
|
|
142
|
+
### What stays ignored, and why
|
|
143
|
+
|
|
144
|
+
| Path | Why it stays ignored |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `.claude/settings.local.json` | Per-machine permission allowlists. Build-specific. |
|
|
147
|
+
| `.claude/projects/` | Claude Code conversation transcripts — privacy + repo bloat. |
|
|
148
|
+
| `.claude/worktrees/` | App-managed scratch worktrees — per-machine ephemera. |
|
|
149
|
+
| `.claude/.DS_Store` | macOS metadata. |
|
|
150
|
+
| (project-local) `.mcp.json` if you already ignore it | Per-machine MCP wiring. |
|
|
151
|
+
|
|
152
|
+
### One-shot vs guided
|
|
153
|
+
|
|
154
|
+
`upgrading` detects this pattern and offers a `quick-tasking` migration that applies the change above for you. Either path works — by-hand is fine if you want to eyeball each step. The migration is **never auto-applied**; `.gitignore` is user-owned.
|
|
155
|
+
|
|
156
|
+
## Validation
|
|
157
|
+
|
|
158
|
+
After the worktree-root change ships and you've reopened a session:
|
|
159
|
+
|
|
160
|
+
- `cat .forge/project.yml` includes the `orchestration:` block (uncomment `worktree_root` only if you want a non-default value).
|
|
161
|
+
- Run an M10 milestone — confirm the new worktree appears at `../<your-repo>-worktrees/m-{id}-{session_id}/`.
|
|
162
|
+
- `cat .forge/state/milestone-{id}.yml | grep worktree_path` shows an **absolute** path, not the relative input.
|
|
163
|
+
|
|
164
|
+
After the gitignore migration:
|
|
165
|
+
|
|
166
|
+
- `git ls-files .claude/skills/forge/SKILL.md` returns the file.
|
|
167
|
+
- Open or create a worktree, `cd` into it, run `/forge` — the command exists.
|
|
168
|
+
- (If M10) Open a new orchestrating session in the worktree — `.session-id` is written, hooks fire.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Migration Guide: Shared-state taxonomy (Forge 0.29.0)
|
|
2
|
+
|
|
3
|
+
Applies to any Forge project that uses git worktrees (M10 or hand-rolled). This is a **documentation + skill-behavior** change, not a state-file change — there is nothing in `.forge/` to migrate. Read this once, then the new skill behavior catches the situations.
|
|
4
|
+
|
|
5
|
+
## What changed and why
|
|
6
|
+
|
|
7
|
+
Forge's `State Ownership (multi-worktree safety)` section in `FORGE.md` previously documented two file classes — `state/milestone-{id}.yml` (single-owner) and `state/index.yml` (derived) — and was silent on every other file in `.forge/`. In practice three more classes exist, and the riskiest one (shared mutable — `context.md`, `refactor-backlog.yml`) had no rule.
|
|
8
|
+
|
|
9
|
+
A worked example from canvaz on 2026-06-15: a main-session edit to `context.md`'s `## M9` block was invisible to the live m9 worktree, because the worktree was branched off main earlier and reads `.forge/` from its own checkout. The operator had to deduce the sync gap from first principles, and nearly committed `milestone-9.yml` edits from main on the first attempt before catching themselves.
|
|
10
|
+
|
|
11
|
+
0.29.0 closes the gap with **taxonomy + visibility + structural rules**, not with a state migration. See [ADR-011](../decisions/ADR-011-shared-state-taxonomy.md) for the longer version (including why a "global `.forge/`" approach is wrong).
|
|
12
|
+
|
|
13
|
+
## The 5-class taxonomy (read this once)
|
|
14
|
+
|
|
15
|
+
| Class | Examples | Write rule |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| **Single-owner mutable** | `state/milestone-{id}.yml`, `phases/milestone-{id}/`, `research/milestone-{id}.md` | One writer at a time; other worktrees **never** touch it. Explicit rule. |
|
|
18
|
+
| **Derived** | `state/index.yml` | Never hand-edited; regenerated by Rollup 1.0. Only main/orchestrator runs rollup. |
|
|
19
|
+
| **Append-only shared** | `releases.yml`, `state/desire-paths/*` | Many writers OK; structure prevents collision. Append + commit + push before depending on the slot. |
|
|
20
|
+
| **Shared mutable** | `context.md`, `refactor-backlog.yml`, `requirements/m{N}.yml` | (a) Write only to YOUR milestone's block. (b) Within a block, append-only — strike through (`~~old~~`) superseded decisions instead of rewriting in place. |
|
|
21
|
+
| **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md` | Rarely changes after init; canonical on main; worktrees lag and pull on rebase. No protocol — git handles it. |
|
|
22
|
+
|
|
23
|
+
The full canonical version lives in `FORGE.md` → `State Ownership`.
|
|
24
|
+
|
|
25
|
+
## What the framework now does automatically
|
|
26
|
+
|
|
27
|
+
After upgrading to 0.29.0:
|
|
28
|
+
|
|
29
|
+
- **`forge` Step 1 preflight (main checkout):** before Rollup, surfaces any live Forge worktrees and their owning milestones — *"m9 is live in worktree X at e94b6bb. Edits to its milestone state belong there; shared docs edited here need a sync."* No prescription, just visibility.
|
|
30
|
+
- **`discussing`** emits a one-line warning before writing to `context.md`'s milestone block if that milestone is live in another worktree.
|
|
31
|
+
- **`reviewing`** emits the same warning before appending to `refactor-backlog.yml` if any milestone is live in a worktree.
|
|
32
|
+
- **`discussing`** also documents the supersede protocol (strike-through old decisions, append new ones below) so concurrent edits across worktrees stay mergeable.
|
|
33
|
+
|
|
34
|
+
## Optional: enable the worktree-side rebase check
|
|
35
|
+
|
|
36
|
+
Opt-in; default off. When enabled, `forge` boot **inside a worktree** diffs `.forge/` against `main` and offers to pull individual shared-mutable / stable-shared files when they've moved.
|
|
37
|
+
|
|
38
|
+
Add to `.forge/project.yml`:
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
forge:
|
|
42
|
+
worktree_rebase_check: true
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Trade-off: adds one git diff per `forge` boot inside worktrees. Worth it for projects that frequently update `context.md` / `constitution.md` on main while worktrees are mid-flight; overkill for projects where the main checkout is mostly read-only.
|
|
46
|
+
|
|
47
|
+
## Existing decisions in context.md — do nothing
|
|
48
|
+
|
|
49
|
+
The taxonomy is descriptive: every existing decision in `context.md` already fits the new rules (it lives under a milestone heading, was append-only in practice). No rewrite needed. **New** writes follow the protocol (use strike-through to supersede).
|
|
50
|
+
|
|
51
|
+
If a past edit broke the rule (decision rewritten in place), don't go back and reconstruct strike-throughs — the history is in git. Just follow the rule going forward.
|
|
52
|
+
|
|
53
|
+
## Detection (none needed)
|
|
54
|
+
|
|
55
|
+
There's nothing to detect on disk. The framework changes are in skills and `FORGE.md`. Upgrade and you have them.
|
|
56
|
+
|
|
57
|
+
## Validation
|
|
58
|
+
|
|
59
|
+
After `npx forge-orkes upgrade`:
|
|
60
|
+
|
|
61
|
+
- `grep "5-class\|sharing classes" .forge/FORGE.md` returns hits in the `State Ownership` section.
|
|
62
|
+
- `grep "cross-tree liveness\|append-only" .claude/skills/discussing/SKILL.md` returns the Write Protocol additions.
|
|
63
|
+
- `grep "worktree-liveness\|worktree_rebase_check" .claude/skills/forge/SKILL.md` returns the Step 1 preflight.
|
|
64
|
+
|
|
65
|
+
Then, if you have a worktree active:
|
|
66
|
+
|
|
67
|
+
- `forge` in the main checkout surfaces the live worktree at the top of its boot output.
|
|
68
|
+
- Begin a discussion in main that touches a worktree-live milestone → `discussing` emits the cross-tree warning before its first write.
|
|
@@ -91,6 +91,16 @@ models:
|
|
|
91
91
|
debugging: sonnet # Investigation needs solid reasoning
|
|
92
92
|
discussing: sonnet # Conversation needs natural fluency
|
|
93
93
|
|
|
94
|
+
orchestration: # M10 multi-agent orchestration (experimental). Only consulted when M10 is installed.
|
|
95
|
+
# auto: true # false = never auto-route Standard/Full through orchestrating (install = consent; set false to opt out).
|
|
96
|
+
# worktree_root: "../<repo>-worktrees" # Where Forge worktrees live. Default: ../<repo-basename>-worktrees (per-repo sibling — see ADR-010).
|
|
97
|
+
# Relative paths resolve against the REPO ROOT (not shell cwd). Absolute paths and a leading ~ are honored.
|
|
98
|
+
# Editing only affects newly created worktrees; live worktrees keep their recorded lifecycle.worktree_path.
|
|
99
|
+
# Common overrides:
|
|
100
|
+
# ~/.forge/worktrees/<repo> — central home dir, keeps the parent dir of the repo clutter-free
|
|
101
|
+
# ../wt/<repo> — shared dir with per-repo subfolder
|
|
102
|
+
# Do NOT point this inside the repo working tree (file watchers + indexers will recurse into the worktree).
|
|
103
|
+
|
|
94
104
|
risks: # What could go wrong?
|
|
95
105
|
- risk: ""
|
|
96
106
|
mitigation: ""
|
|
@@ -22,6 +22,21 @@ current:
|
|
|
22
22
|
status: not_started # not_started | researching | discussing | planning | executing | verifying | reviewing | complete
|
|
23
23
|
completed_at: null # ISO 8601 timestamp — set when status transitions to complete
|
|
24
24
|
last_updated: null # ISO 8601 — set at each transition; rolled up into index.yml registry for resume ordering
|
|
25
|
+
human_verified: null # Human Verification Gate record — REQUIRED before status can become `complete`
|
|
26
|
+
# or an orchestration worktree can be torn down (FORGE.md → Human Verification Gate).
|
|
27
|
+
# Code-level PASS is necessary but never sufficient. Set by the `verifying` skill
|
|
28
|
+
# when a human signs off (device session, visual check, e2e walk — form is open).
|
|
29
|
+
# Shape when set:
|
|
30
|
+
# human_verified:
|
|
31
|
+
# at: "<ISO 8601>" # when the human confirmed
|
|
32
|
+
# method: "device-session" # free text: how they verified
|
|
33
|
+
# notes: "" # optional free text
|
|
34
|
+
# Recorded-override escape hatch (satisfies the gate, but flagged downstream):
|
|
35
|
+
# human_verified:
|
|
36
|
+
# at: "<ISO 8601>"
|
|
37
|
+
# method: "override"
|
|
38
|
+
# override: true
|
|
39
|
+
# reason: "headless milestone — no human-observable surface"
|
|
25
40
|
|
|
26
41
|
# NO stored progress block. Progress percent is DERIVED on read, never stored.
|
|
27
42
|
# The forge skill computes it from genuinely-maintained signals:
|