forge-orkes 0.30.0 → 0.32.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.
@@ -3,6 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const readline = require('readline');
6
+ const { execSync } = require('child_process');
6
7
 
7
8
  const templateDir = path.join(__dirname, '..', 'template');
8
9
  const targetDir = process.cwd();
@@ -349,144 +350,117 @@ async function install() {
349
350
  }
350
351
 
351
352
  /**
352
- * Detect pre-0.10.0 requirements layouts (single top-level file, suffixed top-level,
353
- * or per-phase files). Returns array of legacy paths found, relative to project root.
353
+ * Extract the first fenced ```bash block under a guide's `## Detection` heading.
354
+ * Returns the script string, or null if the guide has no such block (e.g. a
355
+ * non-conformant guide). State-machine parse — no markdown dependency.
354
356
  */
355
- function detectLegacyRequirementsLayout() {
356
- const forgeDir = path.join(targetDir, '.forge');
357
- if (!fs.existsSync(forgeDir)) return [];
358
-
359
- const legacy = [];
360
-
361
- for (const entry of fs.readdirSync(forgeDir, { withFileTypes: true })) {
362
- if (!entry.isFile()) continue;
363
- if (entry.name === 'requirements.yml') {
364
- legacy.push(path.join('.forge', entry.name));
365
- } else if (/^requirements-m\d+\.yml$/.test(entry.name)) {
366
- legacy.push(path.join('.forge', entry.name));
357
+ function extractDetectionBlock(guideContent) {
358
+ const lines = guideContent.split('\n');
359
+ let inDetection = false;
360
+ let inCode = false;
361
+ const code = [];
362
+ for (const line of lines) {
363
+ if (!inDetection) {
364
+ if (/^##\s+Detection\b/.test(line)) inDetection = true;
365
+ continue;
367
366
  }
368
- }
369
-
370
- const phasesDir = path.join(forgeDir, 'phases');
371
- if (fs.existsSync(phasesDir)) {
372
- for (const phase of fs.readdirSync(phasesDir, { withFileTypes: true })) {
373
- if (!phase.isDirectory()) continue;
374
- const reqPath = path.join(phasesDir, phase.name, 'requirements.yml');
375
- if (fs.existsSync(reqPath)) {
376
- legacy.push(path.join('.forge', 'phases', phase.name, 'requirements.yml'));
377
- }
367
+ // Stop scanning if we hit the next top-level (## ...) heading before a block.
368
+ if (!inCode && /^##\s/.test(line) && !/^##\s+Detection\b/.test(line)) break;
369
+ if (!inCode) {
370
+ if (/^```bash\s*$/.test(line)) inCode = true;
371
+ continue;
378
372
  }
373
+ if (/^```/.test(line)) break; // closing fence
374
+ code.push(line);
379
375
  }
380
-
381
- return legacy;
376
+ return code.length ? code.join('\n') : null;
382
377
  }
383
378
 
384
379
  /**
385
- * Detect a pre-0.17.0 project.yml that has no `layers:` field. Cross-layer
386
- * contract detection (planning Step 6.1) reads `layers:`; without it the planner
387
- * falls back to a coarse top-level-directory heuristic. Returns true if the field
388
- * is absent and no contract index has been seeded. False if project.yml is missing
389
- * (not yet initialized) or already migrated.
380
+ * Data-driven post-upgrade migration check. Loops over the migration guides
381
+ * synced into the project this run (.forge/migrations/{v}-*.md), runs each
382
+ * guide's `## Detection` block, and on a `MIGRATE` stdout hit prints a warning
383
+ * with the exact guide pointer. There are NO per-version code branches: a new
384
+ * guide that ships with a conformant Detection block is auto-covered.
385
+ *
386
+ * Range: installed < v <= source. `installedVersion` is the project's
387
+ * settings.json forge.version captured BEFORE the version stamp; `source` is
388
+ * pkgVersion (this package's package.json) — never the template settings.json
389
+ * literal, which is a placeholder the installer stamps at write time. Non-
390
+ * interactive: the bin only warns and points at the guide; it never applies.
390
391
  */
391
- function detectMissingLayersConfig() {
392
- const projectYml = path.join(targetDir, '.forge', 'project.yml');
393
- if (!fs.existsSync(projectYml)) return false;
394
-
395
- let content;
396
- try {
397
- content = fs.readFileSync(projectYml, 'utf-8');
398
- } catch {
399
- return false;
400
- }
401
-
402
- // Already declared a layers: key (any value, including []) → migrated.
403
- if (/^layers:/m.test(content)) return false;
404
- // A seeded contract index implies layers were declared at init → migrated.
405
- if (fs.existsSync(path.join(targetDir, '.forge', 'contracts', 'index.yml'))) return false;
392
+ function runPostUpgradeMigrationChecks(installedVersion) {
393
+ const migrationsDir = path.join(targetDir, '.forge', 'migrations');
394
+ if (!fs.existsSync(migrationsDir)) return;
406
395
 
407
- return true;
408
- }
396
+ const installed =
397
+ installedVersion && installedVersion !== 'unknown' ? installedVersion : '0.0.0';
398
+ const source = pkgVersion;
409
399
 
410
- /**
411
- * Detect a pre-0.19.0 state/index.yml: 0.19.0 makes index.yml a thin derived
412
- * registry (regenerated by rollup) and moves desire_paths to append-only files.
413
- * A legacy index.yml still carries desire_paths:/metrics:/embedded narrative, or
414
- * is large. Returns true if index.yml exists and looks legacy; false if missing
415
- * (not yet initialized) or already a slim registry.
416
- */
417
- function detectLegacyStateIndex() {
418
- const indexYml = path.join(targetDir, '.forge', 'state', 'index.yml');
419
- if (!fs.existsSync(indexYml)) return false;
420
-
421
- let content;
400
+ // Select in-range guides: installed < v <= source. Parse {v} from the filename.
401
+ let guides;
422
402
  try {
423
- content = fs.readFileSync(indexYml, 'utf-8');
403
+ guides = fs
404
+ .readdirSync(migrationsDir)
405
+ .map((name) => {
406
+ const m = name.match(/^(\d+\.\d+\.\d+)-.*\.md$/);
407
+ return m ? { name, version: m[1] } : null;
408
+ })
409
+ .filter(Boolean)
410
+ .filter(
411
+ (g) =>
412
+ compareVersions(installed, g.version) < 0 &&
413
+ compareVersions(g.version, source) <= 0
414
+ )
415
+ .sort((a, b) => compareVersions(a.version, b.version));
424
416
  } catch {
425
- return false;
417
+ return;
426
418
  }
427
419
 
428
- // Legacy markers: shared accumulators or per-milestone narrative drifted in.
429
- if (/^\s*(desire_paths|metrics|current_status):/m.test(content)) return true;
430
- // A slim registry is small; KBs of index.yml means narrative crept in.
431
- if (Buffer.byteLength(content, 'utf-8') > 4096) return true;
420
+ for (const guide of guides) {
421
+ const guidePath = path.join(migrationsDir, guide.name);
422
+ let script;
423
+ try {
424
+ script = extractDetectionBlock(fs.readFileSync(guidePath, 'utf-8'));
425
+ } catch {
426
+ continue;
427
+ }
428
+ if (!script) continue; // no runnable Detection block → treat as no-op
429
+
430
+ let stdout = '';
431
+ try {
432
+ stdout = execSync(script, {
433
+ cwd: targetDir,
434
+ shell: '/bin/bash',
435
+ encoding: 'utf-8',
436
+ stdio: ['ignore', 'pipe', 'ignore'],
437
+ });
438
+ } catch {
439
+ // A non-zero exit or detection error is a no-op, not a failure — keep going.
440
+ continue;
441
+ }
442
+
443
+ if (!/MIGRATE/.test(stdout)) continue; // no-op
432
444
 
433
- return false;
434
- }
445
+ const reasonLine = stdout
446
+ .split('\n')
447
+ .find((l) => l.includes('MIGRATE'));
448
+ const reason = reasonLine
449
+ ? reasonLine.replace(/^.*MIGRATE\s*[—-]?\s*/, '').trim()
450
+ : '';
435
451
 
436
- /**
437
- * After upgrade, surface any detected legacy file layouts the new framework
438
- * version no longer writes, or new config fields older projects lack.
439
- * Non-interactive — prints a warning with a pointer to the migration guide.
440
- * Add new detection blocks here as future versions change layout.
441
- */
442
- function runPostUpgradeMigrationChecks() {
443
- const legacyReqs = detectLegacyRequirementsLayout();
444
- if (legacyReqs.length > 0) {
445
- console.log(' ⚠ Pre-0.10.0 requirements layout detected');
446
- console.log(' ─────────────────────────────────────────');
447
- console.log(' Found:');
448
- for (const p of legacyReqs) {
449
- console.log(` ${p}`);
450
- }
451
- console.log();
452
- console.log(' Forge 0.10.0+ uses per-milestone files at .forge/requirements/m{N}.yml.');
453
- console.log(' Migration guide: .forge/migrations/0.10.0-per-milestone-requirements.md');
452
+ console.log(` ⚠ ${guide.version} migration available${reason ? ` — ${reason}` : ''}`);
453
+ console.log(' ─────────────────────────────────────────────────────────────');
454
+ console.log(` Guide: .forge/migrations/${guide.name}`);
455
+ console.log(
456
+ ` (canonical: https://github.com/Attuned-Media/forge/blob/main/docs/migrations/${guide.name})`
457
+ );
454
458
  console.log();
455
- console.log(' Run the migration before your next planning cycle. In Claude Code:');
459
+ console.log(' Migrations are never applied automatically. In Claude Code:');
456
460
  console.log(' /forge then hand the guide to quick-tasking, or invoke Skill(quick-tasking)');
457
461
  console.log(' with the guide path as the task definition.');
458
462
  console.log();
459
463
  }
460
-
461
- if (detectMissingLayersConfig()) {
462
- console.log(' ⚠ Cross-layer contracts: project.yml has no `layers:` field (Forge 0.17.0)');
463
- console.log(' ──────────────────────────────────────────────────────────────────────');
464
- console.log(' Forge 0.17.0 added cross-layer contract detection (planning Step 6.1),');
465
- console.log(' which reads `layers:` from .forge/project.yml. Your project.yml predates');
466
- console.log(' this field, so planning falls back to a coarse top-level-directory heuristic.');
467
- console.log();
468
- console.log(' Migration guide: .forge/migrations/0.17.0-cross-layer-contracts.md');
469
- console.log();
470
- console.log(' Quick fix: add a `layers:` list to .forge/project.yml — or `layers: []`');
471
- console.log(' for a single-layer project to silence this notice. In Claude Code:');
472
- console.log(' /forge then hand the guide to quick-tasking.');
473
- console.log();
474
- }
475
-
476
- if (detectLegacyStateIndex()) {
477
- console.log(' ⚠ Worktree-safe state: legacy state/index.yml detected (Forge 0.19.0)');
478
- console.log(' ────────────────────────────────────────────────────────────────────');
479
- console.log(' Forge 0.19.0 makes index.yml a derived registry (regenerated by rollup),');
480
- console.log(' moves desire_paths to append-only files, and commits .forge/ state at every');
481
- console.log(' phase handoff. Your index.yml predates this — it still carries desire_paths/');
482
- console.log(' metrics or embedded narrative, which conflicts across git worktrees.');
483
- console.log();
484
- console.log(' Migration guide: .forge/migrations/0.19.0-worktree-safe-state.md');
485
- console.log();
486
- console.log(' This migration edits user-owned state, so it is guided — never automatic.');
487
- console.log(' In Claude Code: /forge then hand the guide to quick-tasking.');
488
- console.log();
489
- }
490
464
  }
491
465
 
492
466
  async function upgrade() {
@@ -656,7 +630,9 @@ async function upgrade() {
656
630
 
657
631
  console.log(` Upgraded to v${pkgVersion}\n`);
658
632
 
659
- runPostUpgradeMigrationChecks();
633
+ // Pass the version captured BEFORE upgradeSettings() stamped the new one, so the
634
+ // migration range is (installed, source] against the freshly-synced guides.
635
+ runPostUpgradeMigrationChecks(installedVersion);
660
636
  }
661
637
 
662
638
  // --- Entry point ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-orkes",
3
- "version": "0.30.0",
3
+ "version": "0.32.0",
4
4
  "description": "Set up the Forge meta-prompting framework for Claude Code in your project",
5
5
  "bin": {
6
6
  "create-forge": "./bin/create-forge.js"
@@ -0,0 +1,238 @@
1
+ ---
2
+ name: chief-of-staff
3
+ description: "Coordinate multiple active Forge streams. Use for explicit stream intents, mid-flow pivots, delegated work, cross-stream conflict checks, and merge ordering."
4
+ ---
5
+
6
+ # Chief Of Staff
7
+
8
+ Project-level traffic control for concurrent Forge work. The Chief owns the
9
+ project stream registry, stream lifecycle, conflict checks, context switching,
10
+ delegation, merge order, and closeout.
11
+
12
+ Use this skill when the user explicitly asks about streams, Chief of Staff, or
13
+ parallel application work. Do not route ordinary single-feature work here by
14
+ default. Inside each stream, continue to use Forge's Quick, Standard, and Full
15
+ tiers for actual execution.
16
+
17
+ ## Operating Model
18
+
19
+ Forge has three coordination layers:
20
+
21
+ | Layer | Owner | Purpose | Default context |
22
+ |-------|-------|---------|-----------------|
23
+ | Project | Project Chief | Active streams, conflicts, pivots, merge order | `.forge/streams/active.yml` |
24
+ | Stream | Stream Chief or lead session | One coherent line of application work | `.forge/streams/{stream}.yml` + `brief.md` |
25
+ | Work Package | Worker session | Delegated bounded task | `.forge/streams/{stream}/packages/{id}.yml` |
26
+
27
+ Workers never coordinate laterally. A worker reports to its stream chief or the
28
+ Project Chief. Scope expansion, shared-surface edits, and cross-stream conflict
29
+ questions return to the Chief before work continues.
30
+
31
+ ## Stream States
32
+
33
+ - `draft` - described but not ready for active work
34
+ - `active` - currently being driven in this session
35
+ - `paused` - safe to resume later; context snapshot is current
36
+ - `delegated` - worker session or external session is carrying the stream
37
+ - `blocked` - cannot proceed until a dependency, decision, or conflict clears
38
+ - `ready` - implementation is ready for merge or verification
39
+ - `merged` - stream work has landed in the integration branch
40
+ - `closed` - final outcome recorded; no active coordination remains
41
+
42
+ ## Context Loading
43
+
44
+ 1. Read `.forge/streams/active.yml` first.
45
+ 2. If missing, create it from `.forge/templates/streams/active.yml`.
46
+ 3. Load only the selected stream's `.forge/streams/{stream}.yml`.
47
+ 4. Load the selected stream's `brief.md` when the user needs status, handoff,
48
+ conflict context, or resume context.
49
+ 5. Load work packages only when delegating, checking worker status, or closing
50
+ a stream.
51
+
52
+ Keep summaries in the registry short. Deep history belongs in stream briefs,
53
+ packages, plans, verification reports, commits, and archived artifacts.
54
+
55
+ ## Supported Intents
56
+
57
+ | Intent | Examples | Action |
58
+ |--------|----------|--------|
59
+ | Show | "show streams", "active streams", "what is running?" | Summarize registry without loading all deep history |
60
+ | Start | "start stream X", "new stream for billing" | Snapshot current stream, create stream files, register stream |
61
+ | Pause | "pause stream X" | Update brief, mark paused, keep next action explicit |
62
+ | Resume | "resume stream X" | Load stream context, set active, surface blockers and ownership |
63
+ | Delegate | "delegate stream X", "farm this out" | Create or update a work package and handoff prompt |
64
+ | Adopt M10 | "adopt existing M10 worktrees", "migrate active orchestrating sessions" | Wrap live M10 worktrees as streams without teardown |
65
+ | Sync | "sync streams" | Refresh registry summaries from active stream briefs |
66
+ | Detect Conflicts | "detect conflicts", "check stream conflicts" | Compare ownership and dependencies |
67
+ | Merge Safe | "merge safe?", "what can land?" | Identify ready streams with no blocking conflicts |
68
+ | Close | "close stream X" | Record final status, archive/mark closed, clear active pointer if needed |
69
+
70
+ ## Start Stream Flow
71
+
72
+ 1. Read the registry.
73
+ 2. If another stream is active, snapshot its current state:
74
+ - update `.forge/streams/{stream}/brief.md`
75
+ - set `next_action`
76
+ - mark it `paused`, `delegated`, or leave `active` only if work continues
77
+ 3. Create a stable stream id from the goal, such as `billing-webhooks`.
78
+ 4. Create:
79
+ - `.forge/streams/{id}.yml` from `.forge/templates/streams/stream.yml`
80
+ - `.forge/streams/{id}/brief.md` from `.forge/templates/streams/brief.md`
81
+ - `.forge/streams/{id}/packages/`
82
+ 5. Add a compact entry to `.forge/streams/active.yml`.
83
+ 6. Declare ownership:
84
+ - `owned_surfaces` for files or areas the stream may edit
85
+ - `shared_surfaces` for contracts, APIs, schemas, or docs touched with care
86
+ - `read_only_surfaces` for context only
87
+ - `forbidden_surfaces` for explicit exclusions
88
+ 7. If ownership is uncertain, start read-only and ask for a narrower boundary.
89
+ 8. Run conflict detection before making edits.
90
+
91
+ ## Adopt Existing M10 Worktrees Flow
92
+
93
+ Use this when a repo already has `orchestrating` / M10 worktrees running and the
94
+ user asks to move to Chief/Streams. Do not teardown, merge, rebase, or remove
95
+ worktrees as part of adoption. Adoption only creates stream metadata around
96
+ existing M10 state.
97
+
98
+ 1. Read or create `.forge/streams/active.yml`.
99
+ 2. Discover live M10 worktrees from both sources:
100
+ - `git worktree list --porcelain` branches matching `refs/heads/forge/m-*`
101
+ - `.forge/state/milestone-*.yml` with
102
+ `lifecycle.worktree_mode: active` or `degraded`
103
+ 3. For each discovered worktree, read its milestone state when available:
104
+ - milestone id and name
105
+ - `current.status`, `current.phase`, `current.phase_name`
106
+ - `lifecycle.worktree_path`
107
+ - `lifecycle.worktree_branch`
108
+ - `lifecycle.worktree_anchor`
109
+ - `lifecycle.session_id`
110
+ - `lifecycle.claim_session_id`
111
+ - blockers or refused/degraded reason
112
+ 4. Create a stable stream id. Prefer a slug from milestone id + name, for
113
+ example `m16-chief-streams`. If only the branch is known, derive from the
114
+ branch suffix.
115
+ 5. For each adopted stream, create if missing:
116
+ - `.forge/streams/{id}.yml`
117
+ - `.forge/streams/{id}/brief.md`
118
+ - `.forge/streams/{id}/packages/`
119
+ 6. Populate the stream file:
120
+ - `stream.id`, `goal`, `status`, `tier`
121
+ - `runtime.branch` from `lifecycle.worktree_branch`
122
+ - `runtime.worktree` from `lifecycle.worktree_path`
123
+ - `runtime.worker_sessions` with the M10 session / claim ids
124
+ - `ownership.owned_surfaces`, `shared_surfaces`, and `read_only_surfaces`
125
+ as empty lists if unknown
126
+ - `blockers` from milestone blockers or degraded/refused notes
127
+ - `context.milestone` pointing at `.forge/state/milestone-{id}.yml`
128
+ 7. Populate the stream brief with:
129
+ - current milestone/phase/status
130
+ - worktree path and branch
131
+ - known blockers
132
+ - unknown ownership surfaces marked as needing declaration
133
+ - next action from milestone state or "declare ownership and sync"
134
+ 8. Add or update the compact entry in `.forge/streams/active.yml`.
135
+ 9. Run conflict detection. Missing ownership is a conflict until clarified, but
136
+ it does not block adoption.
137
+ 10. Ask before changing `.forge/project.yml`:
138
+ - If the user confirms Chief should be the front door, set
139
+ `orchestration.auto: false`.
140
+ - If not confirmed, leave legacy M10 auto-routing unchanged.
141
+
142
+ Adoption is idempotent. If a stream already references the same worktree branch
143
+ or path, update its summary and brief instead of creating a duplicate stream.
144
+
145
+ ## Pause And Resume Flow
146
+
147
+ Pause:
148
+ 1. Update the stream brief with current state, decisions, blockers, and next
149
+ action.
150
+ 2. Set registry status to `paused`, unless work was handed to another session
151
+ and should be `delegated`.
152
+ 3. Clear `current_stream` only if no stream remains active in this session.
153
+
154
+ Resume:
155
+ 1. Load registry, stream file, and brief.
156
+ 2. Surface status, blockers, owned surfaces, shared surfaces, and next action.
157
+ 3. Set the stream to `active`.
158
+ 4. Run conflict detection before continuing.
159
+
160
+ ## Delegate Flow
161
+
162
+ 1. Confirm the stream has a clear goal and ownership boundary.
163
+ 2. Copy `.forge/templates/streams/work-package.yml` to
164
+ `.forge/streams/{stream}/packages/{id}.yml`.
165
+ 3. Include goal, owned/read-only/forbidden surfaces, deliverables, verification
166
+ commands, stop conditions, and reporting target.
167
+ 4. Mark the stream `delegated` if the worker owns the next action.
168
+ 5. Tell the worker to report back to the Chief, not to other workers.
169
+ 6. If the worker finds conflicts, missing contracts, blocked verification, or
170
+ scope expansion, they stop and report back before editing outside package
171
+ scope.
172
+
173
+ If the work-package template is not present yet, create the smallest package
174
+ shape that preserves goal, surfaces, deliverables, stop conditions, and next
175
+ reporting step. Phase 25 upgrades this to the full schema.
176
+
177
+ Delegation prompt must name the package path and the reporting target:
178
+
179
+ ```text
180
+ Work from `.forge/streams/{stream}/packages/{id}.yml`.
181
+ Edit only `scope.owns`.
182
+ Read `scope.may_read` for context.
183
+ Do not touch `scope.must_not_touch`.
184
+ Report conflicts, missing contracts, blocked verification, or scope expansion
185
+ back to the Chief. Do not coordinate directly with other workers.
186
+ ```
187
+
188
+ ## Detect Conflicts
189
+
190
+ Compare all `active`, `delegated`, and `ready` streams:
191
+
192
+ - overlapping `owned_surfaces` means serialize, split, or block one stream
193
+ - `owned_surfaces` overlapping another stream's `shared_surfaces` requires a
194
+ reservation, contract, or explicit merge order
195
+ - overlapping `shared_surfaces` requires a named contract owner
196
+ - overlapping `read_only_surfaces` is safe
197
+ - missing ownership is a conflict until clarified
198
+
199
+ Record conflicts in both the registry and the affected stream files. Do not let
200
+ workers resolve cross-stream conflicts directly.
201
+
202
+ ## Merge Safe Flow
203
+
204
+ Use "merge safe" to identify streams that can land:
205
+
206
+ 1. Candidate stream status must be `ready`.
207
+ 2. No blockers may be open.
208
+ 3. Owned surfaces must not overlap another active or ready stream.
209
+ 4. Shared surfaces must have a contract owner and documented validation.
210
+ 5. Verification commands or manual validation must be listed.
211
+ 6. Merge order must be explicit when more than one stream is ready.
212
+
213
+ If any condition fails, mark the stream blocked or keep it ready with a named
214
+ reason it cannot merge yet.
215
+
216
+ ## Close Flow
217
+
218
+ 1. Confirm final status: merged, intentionally abandoned, superseded, or split.
219
+ 2. Record final outcome in the stream brief.
220
+ 3. Update registry status to `closed`.
221
+ 4. Clear `current_stream` if this was the active stream.
222
+ 5. Keep closed stream history available until a later archive/compaction pass.
223
+
224
+ ## Output Shape
225
+
226
+ Keep Chief responses short and operational:
227
+
228
+ ```text
229
+ Streams:
230
+ - billing-webhooks — active — owns api/billing, shared db/schema — next: verify webhook retries
231
+ - settings-ui — paused — owns app/settings — next: resume form validation
232
+
233
+ Conflicts:
234
+ - billing-webhooks and reporting-export both touch db/schema. Contract owner needed before either merges.
235
+
236
+ Next:
237
+ - Continue billing-webhooks, or start a new stream with read-only ownership until boundaries are declared.
238
+ ```
@@ -45,10 +45,12 @@ Never accumulate decisions in working memory. Never batch writes to convergence.
45
45
  `context.md` is **shared mutable** state per FORGE.md State Ownership — writes follow two structural rules:
46
46
  - **Scope to your milestone's block.** Different milestone blocks → git merges cleanly across worktrees.
47
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
+ - **Keep active context active.** Write current/open decisions to `.forge/context.md`. Do not rehydrate old milestone blocks from `.forge/context-archive.md` unless the user is amending that historical decision.
48
49
 
49
50
  **On first decision of the session:**
50
51
  - Check if `.forge/context.md` exists. If not → create it from `.forge/templates/context.md`
51
52
  - Add a milestone heading inside `## Locked Decisions`: `### M{id} — {name} (drafting)` (use "M?" if no milestone yet)
53
+ - If the needed historical decision is archived, cite the archive in the new active decision instead of copying the whole block back.
52
54
  - **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.
53
55
 
54
56
  **On each confirmed decision:**
@@ -163,7 +163,12 @@ No `project.yml` + Standard/Full → **Step 2A**. State exists → **Step 2B**.
163
163
 
164
164
  ## Step 1.5: Lifecycle Operations
165
165
 
166
- Before tier detection, check if user request matches lifecycle patterns:
166
+ Before tier detection, check if user request matches stream or lifecycle patterns:
167
+ - "show streams" / "active streams" / "what streams are active" / "stream status" → **Show Streams**
168
+ - "start stream {name}" / "new stream {name}" / "create stream {name}" / "pivot to {work}" → **Start Stream**
169
+ - "pause stream {id}" / "resume stream {id}" / "delegate stream {id}" / "sync streams" → **Manage Streams**
170
+ - "detect conflicts" / "check stream conflicts" / "merge safe" / "close stream {id}" → **Manage Streams**
171
+ - "Chief of Staff" / "Project Chief" / "use streams" / "parallel workstreams" → **Chief**
167
172
  - "defer milestone {id}" / "defer {id}" / "pause milestone {id}" → **Defer**
168
173
  - "resume milestone {id}" / "undefer {id}" / "reactivate milestone {id}" → **Resume**
169
174
  - "delete milestone {id}" / "archive milestone {id}" / "remove milestone {id}" → **Delete** (see below)
@@ -171,6 +176,22 @@ Before tier detection, check if user request matches lifecycle patterns:
171
176
 
172
177
  No match → fall through to Step 2B (tier detection).
173
178
 
179
+ ### Chief / Stream Operations
180
+
181
+ 1. Invoke `Skill(chief-of-staff)` directly.
182
+ 2. Do not enter tier detection. The Chief is project-level traffic control, not
183
+ a replacement for Forge's Quick, Standard, or Full tiers.
184
+ 3. Use Chief only for explicit stream intents, concurrent application work,
185
+ mid-flow pivots, delegated work, conflict detection, merge ordering, or
186
+ closing streams.
187
+ 4. Ordinary single-stream feature work still follows normal tier detection.
188
+ Once inside a stream, the stream uses Quick/Standard/Full for execution.
189
+
190
+ Examples:
191
+ - "show streams" → `Skill(chief-of-staff)` summarizes `.forge/streams/active.yml`
192
+ - "start stream settings cleanup" → `Skill(chief-of-staff)` snapshots current stream, creates a new stream, and checks conflicts
193
+ - "merge safe?" → `Skill(chief-of-staff)` lists ready streams that can land without blocking conflicts
194
+
174
195
  ### Show Deferred
175
196
 
176
197
  1. Invoke `Skill(deferred)` directly.
@@ -262,13 +283,17 @@ Tier + state → invoke via `Skill` tool. All phases use `Skill()`.
262
283
 
263
284
  **CRITICAL: NEVER `EnterPlanMode`.** "Planning" = `Skill(planning)`. Native plan mode writes wrong format, bypasses gates + state.
264
285
 
265
- **Experimental — M10 orchestration (auto-routes when installed).** Installing M10 *is* the consent: `forge` then auto-routes Standard/Full work through `orchestrating` **before** `executing` — no separate invocation to remember. Route through `Skill(orchestrating)` first when **all** hold:
286
+ **Experimental — M10 orchestration backend.** Chief/Streams is the preferred
287
+ user-facing orchestration model. M10 remains an optional backend for streams
288
+ that need worktree isolation, merge-queue discipline, or experimental file
289
+ claims. Route through `Skill(orchestrating)` first when **all** hold:
290
+ - **Selected:** Project Chief chooses M10 for a stream, user explicitly asks for multi-agent/worktree mode, or legacy `orchestration.auto` is enabled.
266
291
  - **Installed:** `.claude/skills/orchestrating/` present + `forge-orchestrator` in `.mcp.json` + `.claude/hooks/forge-claim-check.sh` present.
267
- - **Not opted out:** `orchestration.auto` in `project.yml` ≠ `false` (absent = on; install = consent per ADR-001).
292
+ - **Not opted out:** `orchestration.auto` in `project.yml` ≠ `false` for legacy auto-routing; explicit Project Chief selection can still use M10 when installed.
268
293
  - **Tier is Standard or Full.** Quick never auto-orchestrates (a worktree per typo is the wrong trade).
269
294
  - **Not already in a session:** active milestone has no `lifecycle.worktree_mode: active|degraded` (don't re-bootstrap inside a live session).
270
295
 
271
- `orchestrating` bootstrap stays the safety net — incompatible repo → it refuses, writes `worktree_mode: refused`, and `forge` continues single-agent. Absent install → standard routing. Manual `Skill(orchestrating)` still works for explicit control; set `orchestration.auto: false` in `project.yml` to opt back out.
296
+ `orchestrating` bootstrap stays the safety net — incompatible repo → it refuses, writes `worktree_mode: refused`, and `forge` continues single-agent. Absent install → standard routing. Manual `Skill(orchestrating)` still works for explicit backend control; set `orchestration.auto: false` in `project.yml` to opt out of legacy auto-routing.
272
297
 
273
298
  ### Auto-Routing (Always Deterministic)
274
299
 
@@ -307,6 +332,7 @@ Where `{source}` = `skills.{name}` | `models.default` | `parent session`. Suppre
307
332
  | discussing | sonnet | Conversation |
308
333
  | testing | sonnet | Code gen (author) + audit judgment (analyst) — matches executing/reviewing. M9: author-mode refuses e2e without `e2e:true` + `validated:true`. |
309
334
  | deferred | haiku | Read + format only |
335
+ | chief-of-staff | sonnet | Cross-stream coordination and conflict judgment |
310
336
 
311
337
  | `current.status` | Route To |
312
338
  |-------------------|----------|
@@ -322,6 +348,7 @@ Where `{source}` = `skills.{name}` | `models.default` | `parent session`. Suppre
322
348
  | `deferred` | Milestone frozen. *"Resume milestone {id}" to reactivate.* |
323
349
  | `quick-tasking` | `Skill(quick-tasking)` |
324
350
  | (keyword: `deferred` / "show deferred") | `Skill(deferred)` — read-only aggregator |
351
+ | (keyword: `show streams` / `start stream` / `merge safe` / `Chief of Staff`) | `Skill(chief-of-staff)` — project stream coordination |
325
352
 
326
353
  ### Status Advancement Check
327
354
 
@@ -32,6 +32,11 @@ If you find yourself writing a plan that only touches `src/models/`, `src/db/`,
32
32
  Read `.forge/context.md` **Needs Resolution**. If unchecked `- [ ]` items:
33
33
  *"{N} items need input: [list]. For each: lock, defer, fix, or drop?"*
34
34
 
35
+ Load `.forge/context.md` as the active decision set. Consult
36
+ `.forge/context-archive.md` only when the current milestone, stream, or
37
+ requirement cites an older milestone decision (for example M9 e2e policy or M14
38
+ backlog lifecycle). Do not load archived decision blocks wholesale.
39
+
35
40
  | Choice | Action |
36
41
  |--------|--------|
37
42
  | Lock | Record in Locked Decisions |
@@ -61,6 +66,10 @@ If missing, create `.forge/context.md` from template:
61
66
 
62
67
  Must complete BEFORE plans. Plans reference context.md.
63
68
 
69
+ If a plan depends on an archived decision, cite the archive section in the plan
70
+ or active context summary; do not copy the historical block back into
71
+ `.forge/context.md`.
72
+
64
73
  ## Step 4: Structure Requirements
65
74
 
66
75
  Resolve current milestone ID from `.forge/state/index.yml` (active milestone) or invocation context. Target file: `.forge/requirements/m{N}.yml`.