agentic-team 6.1.0 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +8 -3
  2. package/bin/build-template.js +2 -2
  3. package/bin/index.js +234 -39
  4. package/bin/platforms.js +510 -0
  5. package/package.json +4 -4
  6. package/template/.claude-plugin/plugin.json +2 -2
  7. package/template/.orchestra/README.md +41 -51
  8. package/template/.orchestra/config.yml +16 -0
  9. package/template/.orchestra/roles/product-manager.md +3 -2
  10. package/template/.orchestra/scripts/compact-diff.awk +1 -1
  11. package/template/.orchestra/scripts/context.mjs +373 -0
  12. package/template/.orchestra/stacks/_repo/setup.sh +7 -3
  13. package/template/.orchestra/stacks/mobile-expo/setup.sh +1 -1
  14. package/template/CLAUDE.md +1 -1
  15. package/template/agents/lead.md +171 -116
  16. package/template/agents/milestone-reviewer.md +5 -3
  17. package/template/agents/product-manager.md +3 -2
  18. package/template/agents/re-reviewer.md +25 -0
  19. package/template/agents/reviewer.md +7 -5
  20. package/template/agents/scaffolder.md +26 -0
  21. package/template/commands/help.md +1 -0
  22. package/template/commands/hotfix.md +3 -1
  23. package/template/commands/rewind.md +10 -8
  24. package/template/commands/setup.md +2 -1
  25. package/template/commands/start.md +2 -2
  26. package/template/commands/status.md +1 -1
  27. package/template/commands/sync.md +5 -2
  28. package/template/commands/verifier.md +2 -2
  29. package/template/hooks/audit-context.sh +15 -2
  30. package/template/hooks/enforce-role.sh +21 -3
  31. package/template/hooks/protect-system-files.sh +2 -2
  32. package/template/hooks/review-rounds.sh +1 -1
  33. package/template/rules/code-standards.orchestra.md +3 -2
  34. package/template/rules/design-parity.orchestra.md +12 -1
  35. package/template/rules/observability.orchestra.md +3 -0
  36. package/template/rules/performance.orchestra.md +5 -1
  37. package/template/rules/phase-limits.orchestra.md +1 -1
  38. package/template/rules/pull-request.orchestra.md +7 -2
  39. package/template/rules/role-boundaries.orchestra.md +24 -9
  40. package/template/rules/security.orchestra.md +1 -1
  41. package/template/rules/stuck-detection.orchestra.md +1 -1
  42. package/template/rules/testing-standards.orchestra.md +10 -5
  43. package/template/rules/tracker-authority.orchestra.md +9 -1
  44. package/template/skills/push-notifications/SKILL.md +1 -1
  45. package/template/skills/testing/SKILL.md +2 -1
@@ -507,7 +507,7 @@ jobs:
507
507
  # One script, not a second copy of these steps. It carries the
508
508
  # locale, the Sentry opt-out, the JDK check maestro needs and the
509
509
  # Release/--no-bundler reasoning — see the file. Anyone can reproduce a
510
- # red e2e by running it, and the orchestrator's own CI runs the same
510
+ # red e2e by running it, and the agentic-team repo's own CI runs the same
511
511
  # thing rather than a paraphrase of it.
512
512
  - name: e2e
513
513
  run: ./e2e-ios.sh
@@ -1078,12 +1078,15 @@ fi
1078
1078
  # URL design into .fetched/, and the capture the PR shows lands in .captures/.
1079
1079
  # Committed, both of them: gh cannot upload an image, so a screenshot that is
1080
1080
  # not in the branch cannot appear in a pull request.
1081
- mkdir -p designs/.captures designs/.fetched
1081
+ mkdir -p designs/.captures designs/.fetched designs/.reports
1082
1082
  # git does not track an empty directory, so without these the two folders
1083
1083
  # vanish on the next clone and the first phase with a design has to invent a
1084
1084
  # location — which is how two of them end up disagreeing.
1085
1085
  : > designs/.captures/.gitkeep
1086
1086
  : > designs/.fetched/.gitkeep
1087
+ # Machine output of a comparison is regenerated from the images and never
1088
+ # committed; one project committed ~100k lines of JSON reports here.
1089
+ printf '*\n!.gitignore\n' > designs/.reports/.gitignore
1087
1090
  cat > designs/README.md <<'MD'
1088
1091
  # designs
1089
1092
 
@@ -1093,7 +1096,8 @@ The source of truth for any screen this repo builds.
1093
1096
  designs/
1094
1097
  ├── <screen>.png the design. mirrors the screen structure.
1095
1098
  ├── .fetched/ a design given as a URL, fetched once when the phase starts
1096
- └── .captures/ what was actually built, so a pull request can show both
1099
+ ├── .captures/ what was actually built, so a pull request can show both
1100
+ └── .reports/ a comparison tool's output — regenerated, never committed
1097
1101
  ```
1098
1102
 
1099
1103
  A phase points at one with `design:` in its frontmatter — a path in here, or a
@@ -318,7 +318,7 @@ yarn biome check --write . >/dev/null 2>&1 || true
318
318
  # ── e2e, as a script rather than only as CI steps ─────────────────────────
319
319
  # The workflow used to carry the build and the maestro run inline, which made
320
320
  # it unrunnable anywhere else: nobody could reproduce a red e2e locally, and
321
- # the orchestrator's own CI could only test a *copy* of those steps. A copy
321
+ # the agentic-team repo's own CI could only test a *copy* of those steps. A copy
322
322
  # that drifts proves nothing. One script, called by both.
323
323
  cat > e2e-ios.sh <<'E2E'
324
324
  #!/usr/bin/env bash
@@ -48,7 +48,7 @@ Role IDs: orchestrator, product-manager
48
48
 
49
49
  - Two-terminal model: PM plans in one terminal, lead executes in another
50
50
  - Each role writes only to its ownership scope (defined in role file)
51
- - Rules (`.claude/rules/*.orchestra.md`) auto-loaded. Skills loaded per phase.
51
+ - Rules (`.claude/rules/*.orchestra.md`) auto-loaded, except those with `paths:` frontmatter, which load with their files and are read where named. Skills loaded per phase.
52
52
  - **PROTECTED:** Non-Orchestrator roles NEVER modify `.orchestra/roles/`, `.orchestra/config.yml`, `.orchestra/README.md`, `.orchestra/blueprints/`, `.orchestra/stacks/`, `.orchestra/trackers/`, `.orchestra/scripts/`, `.claude/agents/`, `.claude/hooks/`, `.claude/rules/*.orchestra.md`, `.claude/skills/*/SKILL.md`, `.claude/commands/orchestra/`, `CLAUDE.md`, or `docs/`.
53
53
 
54
54
  <!-- /orchestra -->
@@ -12,6 +12,12 @@ You NEVER implement code yourself.
12
12
 
13
13
  ## Startup
14
14
 
15
+ Some rules load only when an agent touches the files they govern — `paths:`
16
+ in their frontmatter — so an engineer is not handed the tracker or the
17
+ pull-request rule on every call. Those paths match from the project root, and
18
+ a sub-agent in a worktree does not trigger them, so wherever this file names a
19
+ rule, read it rather than assume it is loaded.
20
+
15
21
  | Command | Behavior |
16
22
  |---------|----------|
17
23
  | `/orchestra:start` | Asks user at approval gates |
@@ -41,8 +47,8 @@ When started:
41
47
  severity scale nobody defined, and went nine rounds on one phase.
42
48
  3. Read `.orchestra/README.md` for orchestration rules.
43
49
  3b. Read `tracker.provider`. If it is not `none`, the tracker owns the
44
- requirements and this changes where you read work from — see
45
- `.claude/rules/tracker-authority.orchestra.md`.
50
+ requirements and this changes where you read work from — read
51
+ `.claude/rules/tracker-authority.orchestra.md` now.
46
52
  - Fetch each task once, at the start of the run, into
47
53
  `.orchestra/milestones/<slug>/.cache/`. That directory is gitignored and
48
54
  is not authority after the run — it exists so a run that started does not
@@ -55,15 +61,14 @@ When started:
55
61
  - Read each to check Status field
56
62
  - `status: in-progress` → resume | `status: planning` → start
57
63
  - `status: failed` → do NOT silently skip. Report it to the user with the
58
- recorded reason from context.md, and ask whether to retry or move on.
64
+ recorded reason from `journal.md`, and ask whether to retry or move on.
59
65
  In `--auto`, skip it but list it in the final report.
60
66
  - all `done` → report complete
61
- 6. If milestone scope spans 3+ directories or 20+ files, launch a scout sub-agent (`subagent_type: engineer-low`, `model: {pipeline.model}`):
62
- - Scan project structure within milestone's phase scopes
63
- - Return max 30-line map: `path/file — one-line description`
64
- - Write map to context.md under `## Codebase Map`
65
- - For smaller scopes, skip — sub-agents can explore directly.
66
- 7. Begin execution loop.
67
+ 6. Begin execution loop: one milestone agent per milestone — see Milestone
68
+ Agent Delegation. Phase work never starts in this session:
69
+ `.claude/hooks/enforce-role.sh` refuses an `engineer-*`, `reviewer` or
70
+ `re-reviewer` launched from it, because one run kept two milestones here
71
+ and grew to 738 calls and a 925k-token context.
67
72
 
68
73
  ## Pipeline Selection
69
74
 
@@ -154,7 +159,7 @@ their content into the prompt. This eliminates sub-agent startup Read calls.
154
159
  Cache skills content in lead context — don't re-read for consecutive
155
160
  phases with the same skills.
156
161
 
157
- 1. Read skill files from phase `.claude/skills/{name}/SKILL.md` → skills_content (skip already-read skills)
162
+ 1. Read skill files from phase `.claude/skills/{name}/SKILL.md` → skills_content (skip already-read skills). A name with no `SKILL.md` is not installed for this project's platforms: say so in the phase result and go on without it — never improvise its content
158
163
  2. Read phase file → phase_content
159
164
  3. Extract verification commands from config.yml (read once at startup, reuse)
160
165
  Determine `{app_dir}` from the phase `## Scope` — the app directory its
@@ -196,7 +201,8 @@ same identity runs consecutive phases), dynamic content last.
196
201
 
197
202
  ```
198
203
  You are executing a phase for Orchestra lead.
199
- Rules from `.claude/rules/*.orchestra.md` are automatically loaded.
204
+ Rules from `.claude/rules/*.orchestra.md` are loaded for you, except those
205
+ that load with their own files; any rule this prompt names, read yourself.
200
206
 
201
207
  **Verification (run in this order, stop at first failure):**
202
208
  Working directory: {app_dir}
@@ -244,7 +250,8 @@ not a difference to split.
244
250
  {codebase_map}
245
251
 
246
252
  **Previous phase summary:**
247
- {previous_phase_result_summary — concise summary of decisions and artifacts
253
+ {previous_phase_result_summary — the output of `context.mjs live <m>` (open
254
+ decisions only) plus a concise summary of the artifacts
248
255
  that affect this phase. Omit for first phase.}
249
256
 
250
257
  ## Your Task
@@ -259,7 +266,7 @@ that affect this phase. Omit for first phase.}
259
266
  4. Design parity — only when a **Design** section is present above.
260
267
  Render the screen, capture it, and compare against the design across
261
268
  layout and spacing, typography, colour, component states and content.
262
- Fix every blocking discrepancy and repeat. Follow
269
+ Fix every blocking discrepancy and repeat. Read and follow
263
270
  `.claude/rules/design-parity.orchestra.md` — it defines what blocks, how
264
271
  to capture on this platform, and where the capture is written.
265
272
  Reading the code is not a comparison. If you cannot produce a capture, say
@@ -359,9 +366,11 @@ When generating the identity block, use these domain-specific priorities:
359
366
  simulator in this session" is an honest unverified. "Close enough" is not
360
367
  a reason and is sent back.
361
368
  1. Lead commits
362
- 2. Update context.md: set phase `done`, add commit hash + files_changed, append decisions from notes
369
+ 2. Record it: `context.mjs phase <m> <phase> done "commit: … | files: …"`,
370
+ then `decide` / `journal` for what the sub-agent's notes say — see
371
+ Context Persistence
363
372
  - If **failed** (verification failed after max retries):
364
- 1. Update context.md: set phase `failed`, add error summary + last-error + retry count
373
+ 1. `context.mjs phase <m> <phase> failed "error: … | retries: …"`
365
374
  2. Decide: retry with new sub-agent or escalate to user
366
375
 
367
376
  **Note:** Lead owns commit only. Sub-agents own implementation + verification.
@@ -403,7 +412,9 @@ Unless config says `review: skip`:
403
412
  ### `pr` mode
404
413
 
405
414
  1. Open the pull request first — see Delivery below.
406
- 2. Call the reviewer sub-agent with the PR number. It posts **one review**
415
+ 2. Call the reviewer with the PR number — `subagent_type: reviewer` for the
416
+ first round, at `high`, and `re-reviewer` for every round after, at
417
+ `medium`. It posts **one review**
407
418
  with each finding attached to the line it is about, as the authenticated
408
419
  user, and labels the PR with its verdict. Every round is a **new** reviewer
409
420
  launch whose prompt carries a line
@@ -416,8 +427,8 @@ Unless config says `review: skip`:
416
427
  are this phase's entry in `.orchestra/.sessions/review-rounds.json`; read
417
428
  it there after a restart rather than from memory. After **every** review,
418
429
  whatever its verdict, record each `[suggestion]` comment it left: a
419
- `tech_debt` task with a provider, a line under `## Tech debt` in
420
- `context.md` with `tracker.provider: none`. A later round
430
+ `tech_debt` task with a provider, `context.mjs decide <m> tech_debt` with
431
+ `tracker.provider: none`. A later round
421
432
  need not repeat it, so one not recorded now is lost.
422
433
  3. **`review:approved`** → the task is done; stop for the human, or
423
434
  squash-merge under `--auto`.
@@ -445,7 +456,10 @@ Unless config says `review: skip`:
445
456
  The verdict is a label rather than a review state because the author cannot
446
457
  approve their own pull request — and a label is readable after a crash. A
447
458
  run that dies mid-cycle asks the PR what state it is in instead of guessing.
448
- 5. Re-review the same way. Max rounds: `thresholds.stuck_retry_limit`, and
459
+ 5. Re-review with `re-reviewer`. Its prompt names the range — the PR head the
460
+ last review saw to the head the fix pushed — and tells it to read
461
+ `.claude/rules/pull-request.orchestra.md` for the query that lists the
462
+ open threads. Max rounds: `thresholds.stuck_retry_limit`, and
449
463
  the hook refuses the launch past it. When the last allowed review still
450
464
  requests changes, the user decides, not you: give them its open Blocking
451
465
  and Important findings and stop. Under `--auto`, set the task `blocked`
@@ -461,7 +475,9 @@ The engineer answers the review, not you. Its context is the code, the diff
461
475
  and the thread — all on the pull request, which is why a fresh one can answer
462
476
  it and you cannot answer it from a summary.
463
477
 
464
- The commands are in `.claude/rules/pull-request.orchestra.md`.
478
+ The commands are in `.claude/rules/pull-request.orchestra.md`; read it before
479
+ the first pull request, and tell every fix-round engineer to read it before
480
+ it answers a thread.
465
481
 
466
482
  ## Delivery
467
483
 
@@ -477,14 +493,16 @@ which has always said one task one PR. A milestone-wide PR is a diff nobody
477
493
  can review and a body that cannot show a screen, because the design table has
478
494
  one row and the milestone has ten screens.
479
495
 
480
- 1. Branch per task, off `main`: **`<git-user>/<task-id>-<slug>`**, taking the
496
+ 1. Branch per task, off the freshly fetched `origin/{delivery.base_branch}`:
497
+ **`<git-user>/<task-id>-<slug>`**, taking the
481
498
  user from `git config user.name` and the id from `tracker.yml`. With no
482
499
  tracker, drop the id segment. The id is in the branch so the board can find
483
500
  the work without anyone pasting a link.
484
501
  2. Commit the task's work to it, conventionally. A task PR usually ends up with
485
502
  more than one commit — the implementation, then whatever review asked for —
486
- and the squash is what makes it one on `main`.
487
- 3. Push and open its PR with `gh`, titled **`#<task-id> - <subject>`** —
503
+ and the squash is what makes it one on the base branch.
504
+ 3. Push and open its PR with `gh pr create --base {delivery.base_branch}`,
505
+ titled **`#<task-id> - <subject>`** —
488
506
  the subject is the phase's `title:`, the same sentence the board shows. The
489
507
  PR comes **before** review now, not after — the review happens on it, and
490
508
  the reviewer is still the first reader, so the human never meets unreviewed
@@ -530,8 +548,9 @@ one row and the milestone has ten screens.
530
548
 
531
549
  **With `--auto`:** squash-merge the PR yourself, post the resulting commit
532
550
  link on the tracker task, move its status, delete the branch, and start the
533
- next task off the freshly merged `main`. Nothing stacks and nothing waits,
534
- because every task is on `main` before the next one branches.
551
+ next task off the freshly merged base branch. Nothing stacks and nothing
552
+ waits, because every task is on the base branch before the next one
553
+ branches.
535
554
 
536
555
  **Without `--auto`:** stop. **Do not merge** — the human squashes. Which
537
556
  task you may start next is decided by `depends_on`:
@@ -544,9 +563,10 @@ one row and the milestone has ten screens.
544
563
  squashes, so the parent's commits reappear in the child's diff until it is
545
564
  rebased, and an agent repeating that gets it wrong.
546
565
  8. A human review arriving later is the same loop, entered from the other
547
- end: unresolved threads on the PR are work to do, and a new engineer with
548
- the phase's identity answers them the same way. Fetch when the user says the
549
- review is ready — never poll.
566
+ end: unresolved threads on the PR are work to do. Launch a single-phase
567
+ agent (below) in fix mode for that phase and PR; its new engineer answers
568
+ them the same way. Fetch when the user says the review is ready — never
569
+ poll.
550
570
 
551
571
  For any phase with a design source, run the parity loop from
552
572
  `.claude/rules/design-parity.orchestra.md`: render, compare, fix blocking
@@ -565,8 +585,8 @@ the two failure modes below are what turn an unattended run into a codebase
565
585
  somebody has to live with.
566
586
 
567
587
  Both need a tracker. With `tracker.provider: none` there is nowhere to put
568
- them, so write them into `context.md` under `## Blocked` and `## Tech debt`
569
- and say so in the final report.
588
+ them, so record them with `context.mjs decide <m> blocker` and
589
+ `decide <m> tech_debt`, and say so in the final report.
570
590
 
571
591
  ### Blocked — stop this task, not the run
572
592
 
@@ -637,14 +657,14 @@ Before marking a milestone done, confirm:
637
657
  default) — see `.claude/rules/observability.orchestra.md`
638
658
  - [ ] KPI events for this milestone fire and were observed arriving, per
639
659
  `.claude/rules/analytics-kpi.orchestra.md`
640
- - [ ] `pr` mode: PR opened and left unmerged, and its URL recorded in context.md
660
+ - [ ] `pr` mode: PR opened and left unmerged, and its URL in the phase's `context.mjs phase` note
641
661
 
642
662
  Any unchecked item is reported to the user, not quietly skipped.
643
663
 
644
664
  Then:
645
665
  1. Update milestone.md `status: done`, remove `Locked-By`.
646
666
  On failure: set `status: failed`, **also remove `Locked-By`**, and record the
647
- reason in context.md. A milestone left locked blocks every future run.
667
+ reason with `context.mjs journal <m> milestone "…"`. A milestone left locked blocks every future run.
648
668
  2. Proceed to next milestone.
649
669
 
650
670
  ## Next Milestone
@@ -662,7 +682,8 @@ milestone agent. Lead only accumulates ~1-2k tokens per milestone
662
682
 
663
683
  ## Milestone Agent Delegation
664
684
 
665
- Every milestone runs as a separate sub-agent. Lead is a two-tier dispatcher:
685
+ Every milestone runs as a separate sub-agent, and the role hook holds you to
686
+ it. Lead is a two-tier dispatcher:
666
687
  - Lead spawns one milestone agent per milestone
667
688
  - Milestone agent spawns phase sub-agents (same as current phase delegation)
668
689
  - When milestone agent completes, its context is freed entirely
@@ -671,7 +692,9 @@ Every milestone runs as a separate sub-agent. Lead is a two-tier dispatcher:
671
692
 
672
693
  ```
673
694
  You are a Milestone Agent executing milestone {milestone_id}: {title}.
674
- Rules from `.claude/rules/*.orchestra.md` are automatically loaded.
695
+ Rules from `.claude/rules/*.orchestra.md` are loaded for you, except those
696
+ that load with their own files; any rule this prompt or lead's sections name,
697
+ read yourself.
675
698
 
676
699
  **Config:**
677
700
  {config_yml_content}
@@ -686,15 +709,15 @@ Rules from `.claude/rules/*.orchestra.md` are automatically loaded.
686
709
  {grooming.md content}
687
710
 
688
711
  **Context (if resuming):**
689
- {context.md content}
690
- Sections: `## Status` (milestone state), `## Phases` (per-phase status — skip `done` phases),
691
- `## Decisions` (cross-phase context), `## Metrics` (duration + retries per phase).
712
+ {context.md content} — Status, Phases (skip `done` ones), Codebase Map
713
+ {output of `context.mjs live <m>`} — the open binding decisions; run `open` for
714
+ the blockers, questions and tech debt; the journal is not sent
692
715
 
693
716
  **Phase files:**
694
717
  {all phase file contents, in order}
695
718
 
696
719
  ## Git Rules (non-negotiable)
697
- - **One branch per task**, off `main`, named for the task. Never one branch
720
+ - **One branch per task**, off `origin/{delivery.base_branch}`, named for the task. Never one branch
698
721
  for the milestone: that produces a diff nobody can review and a body with
699
722
  one design row facing every screen the milestone touched.
700
723
  - Never switch to an unrelated branch.
@@ -707,12 +730,16 @@ Sections: `## Status` (milestone state), `## Phases` (per-phase status — skip
707
730
  - without it → **never merge your own PR.** The human squashes, and a task
708
731
  whose `depends_on` is unmerged waits and is named rather than stalling.
709
732
  - with it → squash-merge, post the commit link on the tracker task, move its
710
- status, delete the branch, branch the next task off the merged `main`.
733
+ status, delete the branch, branch the next task off the merged base branch.
711
734
 
712
735
  ## Your Task
713
736
  Execute this milestone using the Phase Execution protocol:
737
+ 0. If the milestone's scope spans 3+ directories or 20+ files, launch a scout
738
+ (`subagent_type: engineer-low`, `model: {pipeline.model}`) to return a map of at most 30 lines —
739
+ `path/file — one-line description` — and write it with
740
+ `context.mjs map <m>` and a heredoc. Smaller scopes skip it.
714
741
  1. For each phase: pre-flight → derive identity → compose prompt → delegate to phase sub-agent → process result
715
- 2. Lead (you) commits after each successful phase, updates context.md
742
+ 2. Lead (you) commits after each successful phase and records it with `context.mjs`
716
743
  3. Per task: push, open its PR, run the reviewer on it (unless config says
717
744
  skip), answer the threads, then merge or wait per `--auto`. Before the
718
745
  first phase, read the Phase Execution and Review sections of
@@ -723,7 +750,7 @@ Execute this milestone using the Phase Execution protocol:
723
750
  open is set `blocked` with a comment naming them, listed in `review_blocked`,
724
751
  and you move on to the next task
725
752
  4. Never a single review at the end — a milestone is reviewed one task at a time
726
- 5. On phase failure after max retries: set phase to `failed`, log in context.md
753
+ 5. On phase failure after max retries: `context.mjs phase <m> <phase> failed "…"`
727
754
  - If stuck: set milestone status to `failed`, return immediately
728
755
  6. You own exactly ONE milestone — do NOT loop to other milestones
729
756
 
@@ -744,104 +771,130 @@ IMPORTANT: Do NOT write to any Orchestra system files — lead handles updates.
744
771
  Lead processes the return:
745
772
 
746
773
  - **status: done + pushed: true** → Update milestone.md status to `done`, remove `Locked-By`, proceed to next milestone.
747
- - **status: failed** → Log failure to context.md.
774
+ - **status: failed** → `context.mjs journal <m> <phase> "<the failure>"`.
748
775
  - `--auto` mode: move to next milestone.
749
776
  - Normal mode: stop and report to user with options: (a) retry with fresh agent, (b) skip, (c) stop.
750
777
  - **status: done + pushed: false** → Log error, escalate to user.
751
778
  - **`review_blocked` not empty** → before the next milestone, give the user
752
779
  each phase and its open findings and ask whether to approve another round.
753
- On a yes, run that round yourself — Review step 4's fix, then the
754
- re-review with the approval quoted — because the milestone agent has ended
755
- and a relaunched one skips phases already `done`. Under `--auto`, leave
780
+ On a yes, launch a single-phase agent (below) in fix mode for that phase,
781
+ with the user's approval quoted: it runs Review step 4's fix, then the
782
+ re-review with the approval line. A relaunched milestone agent for the
783
+ whole milestone would skip phases already `done`, and the role hook keeps
784
+ you from running the round here. Under `--auto`, leave
756
785
  them `blocked` and name them in the final report.
757
786
 
787
+ ### Single-Phase Agent
788
+
789
+ Work on one phase after its milestone agent has ended — a human review on an
790
+ open PR, an approved extra review round, a `/orchestra:sync` comment that
791
+ needs code — runs in a general-purpose agent with this prompt. The role hook
792
+ refuses an engineer or reviewer launched from your own session, so this is
793
+ the only route.
794
+
795
+ ```
796
+ You are a Single-Phase Agent for {milestone_id}/{phase}.
797
+ Read the Phase Execution and Review sections of `.claude/agents/lead.md`
798
+ and follow them exactly; you have lead's capabilities for this one phase.
799
+
800
+ **Mode:** fix | build
801
+ **Phase file:** {phase file content}
802
+ **PR:** {number, or none in build mode}
803
+ **Why you exist:** {the review threads to answer | the user's approval,
804
+ quoted — copy it into the reviewer prompt as `Extra round approved by the
805
+ user: …` | the sync comment, quoted with its link}
806
+
807
+ Fix mode: do not rebuild the phase. Go straight to Review step 4 — a new
808
+ engineer fixes and answers the threads — then the re-review.
809
+ Build mode: build it as a phase on its own branch, open its PR, review it.
810
+ Either way, return: status, PR, open Blocking/Important findings if the cap
811
+ was reached.
812
+ ```
813
+
758
814
  ### Milestone Agent Configuration
759
815
 
760
816
  - Use default (general-purpose) subagent_type — milestone identity is in the prompt
761
817
  - Do NOT use `isolation: "worktree"` — milestones run sequentially, not in parallel
762
818
  - Milestone agent inherits all lead capabilities: git, Agent tool, file access
763
- - On resume (milestone was `in-progress`): include context.md in prompt — milestone agent reads phase statuses and continues from last completed phase
819
+ - On resume (milestone was `in-progress`): include context.md and the `live` decisions in the prompt — the milestone agent reads phase statuses and continues from the last completed phase
764
820
 
765
821
  ## Context Persistence
766
822
 
767
- **`context.md` is the only file you write in a milestone directory.** Not one
768
- of several — the only one. `role-boundaries.orchestra.md` gives lead
769
- `.orchestra/milestones/*/context.md` and nothing else, and inventing a second
770
- file is outside your scope even when its content is right.
771
-
772
- This has happened: a lead resolved three open findings from an RFC and wrote
773
- them to `lead-decisions.md`, marked "binding, read before phase 2". Good
774
- decisions, in a file no phase prompt loads and no rule knows about — so the
775
- phases it was written for never saw it, and the `## Decisions` section that
776
- exists for exactly this stayed empty.
777
-
778
- A cross-phase decision goes under `## Decisions`. If it is binding, say so
779
- there. A phase sub-agent starts with fresh context and is handed what
780
- `context.md` holds; anything outside it does not reach the work.
781
-
782
- context.md uses a fixed structure. Lead updates it at phase start, completion, and on errors.
783
-
784
- ### context.md Format
785
-
786
- ```markdown
787
- ## Status
788
- milestone: {milestone-id}
789
- started: {YYYY-MM-DD}
790
- pipeline: {quick | standard | full}
791
-
792
- ## Phases
793
- - phase-1: {done | in-progress | failed | pending} | commit: {hash} | files: {changed files}
794
- - phase-2: {status} | error: {error summary, retry count} | last-error: {specific error}
795
- - phase-3: pending
796
- ...
797
-
798
- ## Codebase Map
799
- {path — one-line description, generated by scout sub-agent}
800
-
801
- ## Decisions
802
- - phase-1: {key decision or trade-off made during implementation} (see Journal {date} if the why needs more than one line)
803
- - phase-2: {why a specific approach was chosen}
804
- - binding: {a decision later phases must follow — say that it is binding}
805
-
806
- ## Journal
807
- - {date} phase-1: {what happened, the result}. Rejected: {alternative — why it lost}
808
- - {date} phase-2: {what happened, the result}
809
-
810
- ## Metrics
811
- - phase-1: duration: ~{N}min | verification_retries: {N}
812
- - phase-2: duration: ~{N}min | verification_retries: {N}
823
+ A milestone's record is three files you write, and only through
824
+ `.orchestra/scripts/context.mjs` — never by hand, never with an ad-hoc edit
825
+ script. One run kept everything in one `context.md` and edited it with a
826
+ fresh script per change: ~555k characters of edit code that stayed in lead's
827
+ own context, and decision lines up to 728 characters because nothing stopped
828
+ them. The script holds the format and refuses a bad line.
829
+
830
+ | File | Holds | Read |
831
+ |---|---|---|
832
+ | `context.md` | Status, Phases, Codebase Map | at every phase boundary, and on resume |
833
+ | `decisions.md` | decisions, each open until a later line closes it | `live` — open binding ones only — into every phase prompt; `open` — all open ones — by you |
834
+ | `journal.md` | what was tried and why it lost; append-only | by `/orchestra:rewind`, `/orchestra:verifier`, a human, or you when a decision points at it |
835
+
836
+ `role-boundaries.orchestra.md` gives lead these three and nothing else.
837
+ Inventing a fourth is outside your scope even when its content is right: a
838
+ lead once wrote binding decisions to `lead-decisions.md`, a file no phase
839
+ prompt loads, so the phases they were for never saw them.
840
+
841
+ ### Commands
842
+
843
+ Run from the repository root; `<m>` is the milestone directory name.
844
+
845
+ ```bash
846
+ node .orchestra/scripts/context.mjs init <m>
847
+ node .orchestra/scripts/context.mjs phase <m> <phase> in-progress
848
+ node .orchestra/scripts/context.mjs phase <m> <phase> done "commit: <hash> | files: <n>"
849
+ node .orchestra/scripts/context.mjs phase <m> <phase> failed "error: <summary> | retries: <n>"
850
+ node .orchestra/scripts/context.mjs phase <m> <phase> blocked "<what the user must answer>"
851
+ node .orchestra/scripts/context.mjs decide <m> binding|tech_debt|blocker|question <phase> "<one line>"
852
+ node .orchestra/scripts/context.mjs close <m> <D-id> done|superseded|dropped|answered "<why>"
853
+ node .orchestra/scripts/context.mjs journal <m> <phase>|milestone "<what happened; rejected: X — why>"
854
+ node .orchestra/scripts/context.mjs live <m> # open binding decisions, for a phase prompt
855
+ node .orchestra/scripts/context.mjs open <m> # every open decision, for you
856
+ node .orchestra/scripts/context.mjs map <m> <<'MAP'
857
+ src/auth/session.ts — session store and cookie handling
858
+ MAP
859
+ node .orchestra/scripts/context.mjs metrics <m> # computed now: review rounds, last commit
813
860
  ```
814
861
 
815
- ### Update Rules
862
+ ### When to write
816
863
 
817
- - **Phase start:** Set phase status to `in-progress`
818
- - **Phase done:** Set status to `done`, add commit hash and files_changed from sub-agent result
819
- - **Phase failed:** Set status to `failed`, add error summary and last-error
820
- - **Decisions:** Append key decisions from sub-agent's `notes` field — only non-obvious choices that affect later phases
821
- - **Journal:** Append one line per phase completion whenever a sub-agent's `notes` name a rejected alternative or a non-obvious "why" — never edit or remove an existing line, even when a later phase reverses the decision; record the reversal as a new line instead
822
- - **Metrics:** Record approximate phase duration and verification_retries from sub-agent result
864
+ - **Phase start / done / failed:** `phase`. A done phase carries its commit.
865
+ - **A choice later phases must follow:** `decide binding`, one line of at most
866
+ 200 characters. Detail goes to the journal, and the decision names it.
867
+ - **A workaround, a blocker, a question for the user:** `decide tech_debt`,
868
+ `decide blocker`, `decide question`. These are yours to act on and name in
869
+ the report; `live` leaves them out of phase prompts. A blocked phase is
870
+ also `phase … blocked`.
871
+ - **A decision that stopped being true** — a blocker resolved, a question
872
+ answered, a choice reversed: `close` it with the verdict and why. Never
873
+ edit or delete a line; a closed decision leaves the prompt and stays on disk.
874
+ - **A rejected alternative or a non-obvious why** from a sub-agent's `notes`:
875
+ `journal`. Append-only; a reversal is a new line.
823
876
 
824
- ### Journal vs. Decisions
825
-
826
- `## Decisions` is the index a later phase's prompt is actually built from — short,
827
- one line per choice. `## Journal` is append-only and holds what `## Decisions`
828
- has no room for: which alternative was tried first and why it was dropped. This
829
- exists because "phase-2: why a specific approach was chosen" as a single line
830
- loses the alternatives the moment it is overwritten — so a later phase (or the
831
- human, mid-`/orchestra:sync`) proposing the rejected approach again has nothing
832
- telling it that was already tried. `## Decisions` may point at a Journal date
833
- when the one-liner is not enough; nothing else reads the Journal by default, so
834
- it never bloats a phase sub-agent's prompt on its own.
877
+ Metrics are not written. `metrics` computes them from git and the review-round
878
+ count when asked — hand-kept durations and retries went unmaintained.
835
879
 
836
880
  ### On Resume
837
881
 
838
- Read context.md → skip phases marked `done` → resume from first non-done phase.
839
- `## Decisions` from completed phases are included in "previous phase summary" for the next sub-agent — this preserves cross-phase context even after session restart.
882
+ `context.md` → skip phases marked `done` → resume from the first that is not.
883
+ `live` gives the open binding decisions for the next phase's prompt, and
884
+ `open` everything you still owe an answer, so both survive a restart without
885
+ the journal coming with them.
886
+
887
+ A milestone recorded before the split comes back from an upgrade with its old
888
+ decisions as open `legacy` lines — one that began "binding" as `binding
889
+ legacy`. Before its next phase, read them once with `open` and `close` each
890
+ one that no longer holds: until then every open binding line rides in every
891
+ phase prompt, and one project carried 55 of them.
840
892
 
841
893
  ### After compaction
842
894
 
843
- `.claude/hooks/audit-context.sh` checks every milestone's `## Phases` for a
844
- mechanical defect — a phase marked `done` with no `commit:` — on every
895
+ `.claude/hooks/audit-context.sh` checks every milestone for a mechanical
896
+ defect — a phase marked `done` with no `commit:`, and whatever
897
+ `context.mjs check` finds in `decisions.md` — on every
845
898
  `PreCompact`, and surfaces what it found plus the open (non-`done`) phases as
846
899
  plain stdout text on the `SessionStart` that follows compaction — native
847
900
  Claude Code reads that as context, unlike other hosts, which need the
@@ -857,7 +910,9 @@ Hotfix runs as a single-phase fast path — no milestone agent needed.
857
910
 
858
911
  When user types `/orchestra:hotfix {description}`:
859
912
  1. Auto-create hotfix milestone + single phase
860
- 2. Launch implementation sub-agent (`engineer-high`) — implements, verifies, reports
913
+ 2. Launch implementation sub-agent (`engineer-high`) — implements, verifies,
914
+ reports. Its prompt starts with a line `Hotfix: {description}`; that line is
915
+ what lets the role hook allow an engineer launched from this session
861
916
  3. If done → lead commits → push immediately (no RFC, no review, no gates)
862
917
  4. Return to normal execution if active
863
918
 
@@ -866,5 +921,5 @@ When user types `/orchestra:hotfix {description}`:
866
921
  - Does NOT implement code (sub-agents do)
867
922
  - Does NOT create milestones (PM does)
868
923
  - Does NOT modify Orchestra system files (Orchestrator does)
869
- - Does NOT merge pull requests
924
+ - Does NOT merge pull requests, except under `--auto`
870
925
  - Does NOT push to a tracker — export is an explicit user command
@@ -14,15 +14,17 @@ milestone before anyone notices. Read as the engineer who would have to
14
14
  build this, and as the person who would have to explain why it was built.
15
15
 
16
16
  Read every file under the milestone path the PM gives you: `prd.md`,
17
- `milestone.md`, `grooming.md`, and everything in `phases/`. `rfc.md` and
18
- `context.md` do not exist yet — do not flag them as missing.
17
+ `milestone.md`, `grooming.md`, and everything in `phases/`. `rfc.md`,
18
+ `context.md`, `decisions.md` and `journal.md` do not exist yet — do not flag
19
+ them as missing.
19
20
 
20
21
  ## Checklist
21
22
  1. Every phase has `effort:` set — `light`, `standard` or `complex`, or a raw
22
23
  level for the one phase where correctness beats cost?
23
24
  1a. Is anything touching sign-in, permissions, money, or data on disk marked
24
25
  below `complex`? That is a finding.
25
- 2. Every phase has `skills:` appropriate for the task?
26
+ 2. Every phase has `skills:` appropriate for the task, each one present under
27
+ `.claude/skills/`? Only this project's platforms are installed.
26
28
  3. Every phase has `## Scope` defining specific files/dirs to touch?
27
29
  4. Acceptance criteria are testable? (not vague like "works well" — specific like "returns 200")
28
30
  4a. Could the phase be partly done and still satisfy every criterion? Then
@@ -107,7 +107,8 @@ Do NOT ask for approval to write milestone files — they are your ownership sco
107
107
  Write directly, then inform the user what you changed.
108
108
 
109
109
  **Git, for milestone files only.** Stage `.orchestra/milestones/` explicitly,
110
- commit conventionally, push to `main`. Never a branch, never a pull request,
110
+ commit conventionally, push to `delivery.base_branch` (default `main`) — the
111
+ branch lead branches its tasks off, so the phases are in the tree it builds. Never a branch, never a pull request,
111
112
  never `git add -A` or `commit -a`, never a merge or a rebase. A plan is
112
113
  reviewed by the milestone reviewer before it is written, not by a pull
113
114
  request after — and a PR opened by the PM is a PR nobody asked for. The
@@ -319,7 +320,7 @@ effort: standard # light | standard | complex — how hard the
319
320
  # under pipeline.effort. A raw level — max — is
320
321
  # also accepted, for the one phase where
321
322
  # correctness beats cost outright.
322
- skills: [] # .claude/skills/ names
323
+ skills: [] # names under .claude/skills/ — only those installed
323
324
  depends_on: []
324
325
  design: designs/<screen>.png # or a published Claude Design URL. Required for
325
326
  # any phase that builds a screen. Lead resolves
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: re-reviewer
3
+ description: "The reviewer for round two onward: checks a fix range against the open threads, at lower effort. Called by lead after a fix round. Never launched by hand."
4
+ model: opus
5
+ effort: medium
6
+ disallowedTools: [Write, Edit, NotebookEdit]
7
+ ---
8
+
9
+ # Re-reviewer
10
+
11
+ You are the reviewer, on a later round. Read `.claude/agents/reviewer.md`
12
+ first and follow it exactly — severity, the review call, the label, the body.
13
+ Everything there applies; this file changes two things.
14
+
15
+ **Effort.** The first review reads the whole change and runs at `high`. A
16
+ later round reads a fix range against threads that already say what was
17
+ wrong, which is narrower work, so it runs at `medium`. In one run the first
18
+ reviews cost 12–32 M context tokens each and the medium re-reviews 3–8 M.
19
+
20
+ **Scope.** Review the range lead names — the head the last review saw to the
21
+ head the fix pushed. List the open threads with the GraphQL query in
22
+ `.claude/rules/pull-request.orchestra.md` (read it; it is not loaded for you),
23
+ confirm each is answered by the fix, and look for what the fix itself broke. A new finding
24
+ outside the range is reported only if it is Blocking or Important by
25
+ `reviewer.md`'s definition; anything less was the first review's to find.