@ikon85/agent-workflow-kit 0.32.1 → 0.34.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 (89) hide show
  1. package/.agents/skills/ask-matt/SKILL.md +4 -3
  2. package/.agents/skills/audit-skills/SKILL.md +6 -0
  3. package/.agents/skills/board-to-waves/SKILL.md +6 -2
  4. package/.agents/skills/code-review/SKILL.md +6 -0
  5. package/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +11 -1
  6. package/.agents/skills/codex-adapter-sync/SKILL.md +23 -19
  7. package/.agents/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +6 -0
  8. package/.agents/skills/improve-codebase-architecture/SKILL.md +10 -1
  9. package/.agents/skills/kit-update/SKILL.md +13 -0
  10. package/.agents/skills/orchestrate-wave/SKILL.md +54 -54
  11. package/.agents/skills/orchestrate-wave/references/builder-contract.md +16 -3
  12. package/.agents/skills/orchestrate-wave/references/dispatch-subagents.md +91 -0
  13. package/.agents/skills/orchestrate-wave/references/dispatch-workflow.md +66 -0
  14. package/.agents/skills/orchestrate-wave/references/report-contracts.md +42 -0
  15. package/.agents/skills/research/SKILL.md +6 -0
  16. package/.agents/skills/scale-check/SKILL.md +9 -7
  17. package/.agents/skills/setup-workflow/SKILL.md +47 -1
  18. package/.agents/skills/setup-workflow/board-sync.md +7 -2
  19. package/.agents/skills/setup-workflow/workflow-overview.md +1 -2
  20. package/.agents/skills/to-issues/SKILL.md +66 -8
  21. package/.agents/skills/to-waves/SKILL.md +24 -12
  22. package/.claude/skills/ask-matt/SKILL.md +4 -3
  23. package/.claude/skills/audit-skills/SKILL.md +6 -0
  24. package/.claude/skills/board-to-waves/SKILL.md +6 -2
  25. package/.claude/skills/code-review/SKILL.md +6 -0
  26. package/.claude/skills/codebase-design/DESIGN-IT-TWICE.md +8 -0
  27. package/.claude/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +6 -0
  28. package/.claude/skills/improve-codebase-architecture/SKILL.md +6 -0
  29. package/.claude/skills/kit-update/SKILL.md +13 -0
  30. package/.claude/skills/orchestrate-wave/SKILL.md +54 -54
  31. package/.claude/skills/orchestrate-wave/references/builder-contract.md +16 -3
  32. package/.claude/skills/orchestrate-wave/references/dispatch-subagents.md +91 -0
  33. package/.claude/skills/orchestrate-wave/references/dispatch-workflow.md +66 -0
  34. package/.claude/skills/orchestrate-wave/references/report-contracts.md +42 -0
  35. package/.claude/skills/research/SKILL.md +6 -0
  36. package/.claude/skills/scale-check/SKILL.md +9 -7
  37. package/.claude/skills/setup-workflow/SKILL.md +47 -1
  38. package/.claude/skills/setup-workflow/board-sync.md +7 -2
  39. package/.claude/skills/setup-workflow/workflow-overview.md +1 -2
  40. package/.claude/skills/to-issues/SKILL.md +66 -8
  41. package/.claude/skills/to-waves/SKILL.md +24 -12
  42. package/README.md +126 -11
  43. package/agent-workflow-kit.package.json +291 -39
  44. package/docs/adr/0002-capability-gated-orchestration.md +70 -0
  45. package/docs/adr/0005-to-issues-is-the-planning-facade.md +42 -0
  46. package/docs/adr/0006-routing-knowledge-access-and-policy-are-separate.md +91 -0
  47. package/docs/agents/skills/local-ci.md +89 -0
  48. package/docs/agents/wave-anchor-template.md +2 -2
  49. package/docs/methodology.html +1 -1
  50. package/docs/methodology.svg +1 -1
  51. package/docs/workflow.html +2 -2
  52. package/docs/workflow.png +0 -0
  53. package/package.json +1 -1
  54. package/scripts/codex-exec.sh +47 -8
  55. package/scripts/codex-exec.test.mjs +56 -0
  56. package/scripts/test_codex_adapter_sync_contract.py +30 -15
  57. package/scripts/test_orchestrate_wave_contract.py +209 -0
  58. package/scripts/test_program_planning_contract.py +70 -0
  59. package/scripts/test_skill_portability_lint.py +54 -0
  60. package/scripts/test_worktree_setup_base_guard.py +140 -0
  61. package/scripts/worktree-lifecycle/setup.py +40 -0
  62. package/src/cli.mjs +109 -2
  63. package/src/commands/init.mjs +17 -1
  64. package/src/commands/routing-policy-update.mjs +204 -0
  65. package/src/commands/update.mjs +22 -0
  66. package/src/lib/agentSurfaceRegistry.mjs +60 -0
  67. package/src/lib/bundle.mjs +34 -0
  68. package/src/lib/capabilityMatrix.mjs +179 -0
  69. package/src/lib/dispatchReceipt.mjs +162 -0
  70. package/src/lib/frontendWorkloads.mjs +170 -0
  71. package/src/lib/reconcileReconReports.mjs +111 -0
  72. package/src/lib/reportValidator.mjs +186 -0
  73. package/src/lib/routeDispatcher.mjs +158 -0
  74. package/src/lib/routingAccessGraph.mjs +105 -0
  75. package/src/lib/routingAdapters/claude.mjs +62 -0
  76. package/src/lib/routingAdapters/codex.mjs +136 -0
  77. package/src/lib/routingCatalog.mjs +123 -0
  78. package/src/lib/routingEvidenceCache.mjs +222 -0
  79. package/src/lib/routingIntent.mjs +93 -0
  80. package/src/lib/routingPolicy.mjs +67 -0
  81. package/src/lib/routingProfile.mjs +334 -0
  82. package/src/lib/routingResolver.mjs +176 -0
  83. package/src/lib/routingSources/artificialAnalysis.mjs +129 -0
  84. package/src/lib/routingSources/benchlm.mjs +151 -0
  85. package/src/lib/routingSources/codeArena.mjs +162 -0
  86. package/src/lib/routingSources/deepswe.mjs +106 -0
  87. package/src/lib/routingSources/openhands.mjs +102 -0
  88. package/src/lib/routingSources/openhandsFrontend.mjs +135 -0
  89. package/src/lib/waveClaim.mjs +134 -0
@@ -49,7 +49,8 @@ Prefer the smallest depth that produces a clear next action.
49
49
  undertaking, several independently-shippable stages. Run `/scale-check`
50
50
  first (it owns the altitude criteria catalog — this router only names it);
51
51
  two or more criteria tripped routes to a program grill → `/to-prd` →
52
- `/to-waves`.
52
+ `/to-issues`. The explicit Program identity makes the Planning facade select
53
+ its internal graph engine; the user never chooses that engine.
53
54
  - **Deep:** `/grill-with-docs` followed by `/to-prd` and `/to-issues` when
54
55
  terminology, contracts, rollout order, or ownership are still uncertain.
55
56
  - **Medium:** `/to-issues` for a ready artefact that needs slicing.
@@ -73,9 +74,9 @@ A starting situation that generates work, then merges onto the main flow.
73
74
 
74
75
  - **Bugs and requests piling up** → **`/triage`**. Moves issues through triage and produces agent-ready issues that `/implement` later picks up. Only for issues **you didn't create** — `/to-issues` output is already agent-ready, don't triage it.
75
76
  - **Something's broken** → **`/diagnose`**. For the hard ones: the bug that resists a first glance, the intermittent flake, the regression between two known-good states. Refuses to theorise until it has a **tight feedback loop** — one command that already goes red on *this* bug — then fixes with a regression test. Its post-mortem hands off to **`/improve-codebase-architecture`** when the finding is that there's no good seam.
76
- - **A huge, foggy effort too big for one agent session** — a greenfield build or a sprawling feature where the way from here to the destination isn't yet visible, and it's still **pre-spec** (before any grill or PRD) → **`/wayfinder`** (user-invoked). It charts a **shared map** of investigation slices on the tracker and resolves them one at a time — producing **decisions, not deliverables** — until the fog lifts and the route is clear, then merges onto the main flow at **`/to-prd`** (or, if the effort turned out small enough, straight to **`/implement`**). Where `/grill-with-docs` sharpens an idea you can hold in one session, wayfinder is for the one you can't. Once an undertaking has already resolved into several independently-shippable waves, `/scale-check` → `/to-waves` stays the primary route.
77
+ - **A huge, foggy effort too big for one agent session** — a greenfield build or a sprawling feature where the way from here to the destination isn't yet visible, and it's still **pre-spec** (before any grill or PRD) → **`/wayfinder`** (user-invoked). It charts a **shared map** of investigation slices on the tracker and resolves them one at a time — producing **decisions, not deliverables** — until the fog lifts and the route is clear, then merges onto the main flow at **`/to-prd`** (or, if the effort turned out small enough, straight to **`/implement`**). Where `/grill-with-docs` sharpens an idea you can hold in one session, wayfinder is for the one you can't. Once an undertaking has already resolved into several independently-shippable waves, `/scale-check` → `/to-issues` stays the primary route.
77
78
  - **A backlog to cluster** → **`/board-to-waves`**. Groups an existing board into themed waves when you need to *find* the next wave rather than start fresh.
78
- - **A whole wave to LAND** → **`/orchestrate-wave`**. When a wave anchor (file-disjoint slices, specs already locked) is ready to build, verify and land end-to-end — often AFK: it dispatches an implementer per slice in its own worktree, integrates serially, verifies centrally, and lands the wave. The execute-and-land node of the wave ladder (`scale-check` → `to-waves`/`board-to-waves` → `orchestrate-wave`). A single slice just goes to `/implement`.
79
+ - **A whole wave to LAND** → **`/orchestrate-wave`**. When a wave anchor (file-disjoint slices, specs already locked) is ready to build, verify and land end-to-end — often AFK: it dispatches an implementer per slice in its own worktree, integrates serially, verifies centrally, and lands the wave. The execute-and-land node of the wave ladder (`scale-check` → `to-issues`/`board-to-waves` → `orchestrate-wave`). A single slice just goes to `/implement`.
79
80
 
80
81
  ## Cross-model review (Codex)
81
82
 
@@ -114,6 +114,12 @@ otherwise stay invisible.
114
114
 
115
115
  ### 2. Audit in parallel — one subagent per skill
116
116
 
117
+ Before dispatch, resolve a provider-neutral Routing intent through
118
+ `src/lib/routeDispatcher.mjs` and require a Dispatch receipt from the shared
119
+ spawn guard. A detected transport is not authorization; AFK dispatch stops
120
+ unless requested/applied route, model/effort enforcement, environment
121
+ precedence, and catalog/access/policy revisions are proved.
122
+
117
123
  Run **one read-only research subagent per skill** — several in parallel in a
118
124
  SINGLE message (they are independent and read-only, so they don't contend for the
119
125
  git index). Per subagent prompt:
@@ -36,7 +36,11 @@ to-issues slices + promotes (sets type:cluster + Wave at ≥2 slices)
36
36
 
37
37
  **Stops at stubs.** No slice plan, no PRD, no sub-issue link, no promotion. Whether/when a stub becomes a real wave = separate step (`to-prd → to-issues`), <maintainer>'s call.
38
38
 
39
- **S4 exit — no stub at all.** A candidate that trips the `scale-check` altitude criteria (Splitter S4 below) skips the stub step entirely — it is reported as an escalation, pointing at `scale-check` (→ a program grill → `to-prd` program mode → `to-waves`), never at `to-prd`/`to-issues` directly. Still <maintainer>'s call, still no board write here.
39
+ **S4 exit — no stub at all.** A candidate that trips the `scale-check` altitude
40
+ criteria (Splitter S4 below) skips the stub step entirely — it is reported as
41
+ an escalation, pointing at `scale-check` (→ a program grill → `to-prd` Program
42
+ mode → `to-issues`), never straight into ordinary Feature decomposition. Still
43
+ <maintainer>'s call, still no board write here.
40
44
 
41
45
  Model: **strongest available reasoning model for board-wide judgment calls** (survey/plan/brainstorm — cross-board judgment, <maintainer>'s table).
42
46
 
@@ -64,7 +68,7 @@ Model: **strongest available reasoning model for board-wide judgment calls** (su
64
68
  - **S1 Too big** — > ~7 slices / not shippable in a manageable sequence → split into two waves.
65
69
  - **S2 Foreign parent** — issue already hangs under another wave (GitHub 1-parent; `to-issues` link check is the final word).
66
70
  - **S3 "Same type alone" ≠ wave** — type is a booster, never a gate. Otherwise "all refactors" becomes a junk drawer.
67
- - **S4 Programm-Verdacht** — the candidate trips the `scale-check` altitude criteria (`.claude/skills/scale-check/SKILL.md` § "Altitude criteria (the single source of truth)" — referenced here, **never** re-forked; e.g. staged delivery + several subsystems that each stand on their own) → **escalate to the Program route instead of creating a candidate stub**: report it in the candidate list (§3/§5) pointing at `scale-check` (grill once into a Program-PRD with a Wellenplan, then `to-waves` unfolds it), not `to-prd`/`to-issues`. The bottom-up Wave-stamping rule above is unaffected — an escalated candidate is still just a proposal, not yet a committed wave, exactly like any other candidate.
71
+ - **S4 Programm-Verdacht** — the candidate trips the `scale-check` altitude criteria (`.claude/skills/scale-check/SKILL.md` § "Altitude criteria (the single source of truth)" — referenced here, **never** re-forked; e.g. staged delivery + several subsystems that each stand on their own) → **escalate to the Program route instead of creating a candidate stub**: report it in the candidate list (§3/§5) pointing at `scale-check` (grill once into a Program-PRD with a Wellenplan, then `to-issues` selects the Program graph path from that explicit identity), not directly to a hidden engine. The bottom-up Wave-stamping rule above is unaffected — an escalated candidate is still just a proposal, not yet a committed wave, exactly like any other candidate.
68
72
 
69
73
  **Rule:** issue → candidate X if **Gate(X) satisfied AND ≥1 booster fires** and no splitter applies. Otherwise: own candidate or leftover bucket "unclustered / standalone issue".
70
74
 
@@ -73,6 +73,12 @@ When `projectEnrichment` is active, read `docs/agents/code-review.md` first. App
73
73
 
74
74
  ## Execution
75
75
 
76
+ Before dispatch, resolve a provider-neutral Routing intent through
77
+ `src/lib/routeDispatcher.mjs` and require a Dispatch receipt from the shared
78
+ spawn guard. A detected transport is not authorization; AFK dispatch stops
79
+ unless requested/applied route, model/effort enforcement, environment
80
+ precedence, and catalog/access/policy revisions are proved.
81
+
76
82
  - Run both axes as **parallel sub-agents** — separate context each, so neither poisons the other's read. Give the Standards sub-agent the Standards sources **plus** the full Fowler baseline in its prompt; it has no other way to see the baseline.
77
83
  - Report **side by side**, under `## Standards` and `## Spec` headers, verbatim or lightly cleaned — never merge or re-rank the two into one combined verdict.
78
84
  - Cap each sub-agent's report under 400 words — findings, not padding.
@@ -18,7 +18,17 @@ Show this to the user, then immediately proceed to Step 2. The user reads and th
18
18
 
19
19
  ### 2. Spawn sub-agents
20
20
 
21
- Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a **radically different** interface for the deepened module.
21
+ Before dispatch, resolve a provider-neutral Routing intent through
22
+ `src/lib/routeDispatcher.mjs` and require a Dispatch receipt from the shared
23
+ spawn guard. A detected transport is not authorization; AFK dispatch stops
24
+ unless requested/applied route, model/effort enforcement, environment
25
+ precedence, and catalog/access/policy revisions are proved.
26
+
27
+ <!-- mirror-xform:start codex-parallel-subagent-dispatch -->
28
+ When the user has authorized subagent delegation, make 3+ parallel
29
+ `spawn_agent` calls using only `task_name`, `message`, and `fork_turns`. Each
30
+ must produce a **radically different** interface for the deepened module.
31
+ <!-- mirror-xform:end -->
22
32
 
23
33
  Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
24
34
 
@@ -22,23 +22,27 @@ correct issue or slice worktree before the first edit. Never apply adapter
22
22
  changes on `main`; move any accidental main-checkout diff into the worktree and
23
23
  leave the main checkout clean.
24
24
 
25
- ## Model routing
26
-
27
- Default to inherited parent model configuration. Do not pin a model merely
28
- because the source workflow delegates, and do not invent model or role fields
29
- on a spawn call. The supported built-in agent names are `default`, `worker`, and
30
- `explorer`; custom agents declare overrides in their TOML files.
31
-
32
- When an explicit custom-agent model is genuinely justified, route by task
33
- shape:
34
-
35
- - `gpt-5.6-sol` for complex, open-ended judgment work.
36
- - `gpt-5.6-terra` for everyday tool-using development.
37
- - `gpt-5.6-luna` for clear, repeatable, high-volume work.
38
-
39
- Use `model_reasoning_effort` for a supported reasoning override. The family
40
- name `gpt-5.6` describes the family and is not a fourth concrete variant in
41
- this routing table. Keep user gates, security judgment, and approval decisions
25
+ ## Routing intent
26
+
27
+ Durable issues and handoffs describe task shape with provider-neutral
28
+ `routing-intent` and `reasoning-intent` values. Never persist a provider model
29
+ identifier or copy a resolved route back into shared work. The supported
30
+ built-in agent names remain `default`, `worker`, and `explorer`.
31
+
32
+ At dispatch time, resolve the intent by comparing the Kit-owned Evidence
33
+ catalog with the user-local Access graph and Routing policy. Keep those
34
+ contracts separate: catalog facts include inaccessible models, the Access graph
35
+ attests available paths and enforcement, and personal policy filters facts
36
+ without changing them. Report the best overall route separately from the best
37
+ currently executable route. Unknown transports and stale capability evidence
38
+ block; missing routing infrastructure may fall back only through explicit
39
+ `inherit`.
40
+
41
+ Apply any selected provider route only through the active surface's verified
42
+ adapter. An AFK dispatch must prove its requested and applied route plus model
43
+ and effort enforcement in a one-execution Dispatch receipt. Credentials,
44
+ personal access state, and personal policy stay outside repositories and
45
+ package-owned files. Keep user gates, security judgment, and approval decisions
42
46
  in the main thread.
43
47
 
44
48
  ## Scope
@@ -148,8 +152,8 @@ Run validation from the repository root and keep the evidence in the report:
148
152
  - Leave clearly Claude-only setup, hook, or personal/meta skills out unless
149
153
  the user explicitly wants them ported.
150
154
  - Translate Claude-specific delegation rather than copying it literally.
151
- Apply the Model routing section above only when an explicit custom-agent
152
- override is justified; otherwise preserve inherited parent configuration.
155
+ Apply the Routing intent section above only when an explicit user-local
156
+ route is justified; otherwise preserve explicit inheritance.
153
157
  - Keep dual-surface generic/vendored skill bodies content-synced. When a
154
158
  Codex mirror must intentionally differ from the Claude source, bracket the
155
159
  source region and the Codex replacement with a matching transform marker
@@ -18,6 +18,12 @@ Show this to the user, then immediately proceed to Step 2. The user reads and th
18
18
 
19
19
  ### 2. Spawn sub-agents
20
20
 
21
+ Before dispatch, resolve a provider-neutral Routing intent through
22
+ `src/lib/routeDispatcher.mjs` and require a Dispatch receipt from the shared
23
+ spawn guard. A detected transport is not authorization; AFK dispatch stops
24
+ unless requested/applied route, model/effort enforcement, environment
25
+ precedence, and catalog/access/policy revisions are proved.
26
+
21
27
  <!-- mirror-xform:start codex-parallel-subagent-dispatch -->
22
28
  When the user has authorized subagent delegation, spawn 3+ sub-agents in parallel with `spawn_agent`. Each must produce a **radically different** interface for the deepened module.
23
29
  <!-- mirror-xform:end -->
@@ -35,8 +35,17 @@ This skill is _informed_ by the project's domain model. The domain language give
35
35
 
36
36
  Read the project's domain glossary and any ADRs in the area you're touching first.
37
37
 
38
+ Before dispatch, resolve a provider-neutral Routing intent through
39
+ `src/lib/routeDispatcher.mjs` and require a Dispatch receipt from the shared
40
+ spawn guard. A detected transport is not authorization; AFK dispatch stops
41
+ unless requested/applied route, model/effort enforcement, environment
42
+ precedence, and catalog/access/policy revisions are proved.
43
+
38
44
  <!-- mirror-xform:start codex-explorer-dispatch -->
39
- When the user has authorized subagent delegation, use `spawn_agent` with `agent_type: explorer` to walk the codebase; otherwise explore locally. Don't follow rigid heuristics — explore organically and note where you experience friction:
45
+ When the user has authorized subagent delegation, use `spawn_agent` with only
46
+ `task_name`, `message`, and `fork_turns` to walk the codebase; otherwise explore
47
+ locally. Don't follow rigid heuristics — explore organically and note where you
48
+ experience friction:
40
49
  <!-- mirror-xform:end -->
41
50
 
42
51
  - Where does understanding one concept require bouncing between many small modules?
@@ -57,6 +57,19 @@ release contain the same artifact.
57
57
  (`missing-file`, `missing-section`, `empty-section`, or
58
58
  `divergent-section`); it never echoes consumer content.
59
59
 
60
+ Independently, run the routing-profile read-only preflight before applying
61
+ the package candidate. A valid unchanged user-local profile reports
62
+ `still valid` and causes zero prompts. Ask after successful Kit activation
63
+ only when the profile is missing, invalid, materially stale, references a
64
+ removed route, or a newly detected surface creates a meaningful choice.
65
+ Re-inspect after package activation, present a typed delta containing only
66
+ that changed choice, and preserve unaffected personal fields. Fingerprint
67
+ and exclusively lock the destination before writing; a concurrent personal
68
+ edit blocks reconciliation and remains untouched. Unattended update records
69
+ `needs-reconcile`; it never invents a personal answer. Declining the
70
+ routing reconcile leaves the successful Kit update applied because package
71
+ installation and personal policy are separate transactions.
72
+
60
73
  3. Read the terminal report. `aktuell` proves a second run found no upstream
61
74
  delta or pending readiness migration. A conflict report names and counts
62
75
  every category and leaves every consumer file untouched. Follow its
@@ -73,10 +73,10 @@ node scripts/readiness.mjs check --skill orchestrate-wave --json
73
73
  - **Plan-level error** (integration/verify reveals a wrong LOCKED decision, not a
74
74
  slice bug): STOP the wave. No improvised redesign AFK — keep worktrees intact,
75
75
  report findings + options.
76
- - **On ANY wave STOP/abort:** if this run planted the active-wave claim, remove
77
- exactly that claim as part of shutdown. Never delete a claim marker observed
78
- during a preflight collision, nor any sibling/foreign wave marker those are
79
- owned by another run. A stale marker owned by this run would block a safe retry.
76
+ - **On ANY wave STOP/abort:** if this run planted the active-wave claim, release
77
+ it via `releaseWaveClaim` with this run's owner as part of shutdown it
78
+ refuses a foreign payload. Never delete a claim marker observed during a
79
+ preflight collision. A stale own marker would block a safe retry.
80
80
  - **Routing = one axis: how expensive is a wrong result to catch?** Mechanically
81
81
  caught (test/screenshot/lint) → default tier at medium/low effort; plausible-but-
82
82
  wrong / subtle logic / architecture → top tier at high effort + main-thread
@@ -87,6 +87,24 @@ node scripts/readiness.mjs check --skill orchestrate-wave --json
87
87
  first red test). The same axis sets how hard you re-verify. Borderline → default
88
88
  tier + re-verify beats blanket top tier.
89
89
 
90
+ ## Orchestration mechanics
91
+
92
+ Pass only host-supplied inventory through `capabilityAdapter.claude` or `.codex`,
93
+ then call the selector. It returns exactly one target; missing or `unknown` evidence
94
+ degrades A → B → C. A model claim is not evidence; do not emulate a missing primitive.
95
+ Before any spawn, resolve the provider-neutral Routing intent through the shared resolver and spawn guard, then use the active Claude or Codex adapter. Codex contributes only its dated host attestation through `routingAdapters/codex.mjs`; it does not create a second catalog, Access graph, or Routing policy. A detected transport is not authorization. The Dispatch receipt must show requested and applied route, model/effort enforcement, environment precedence on mismatch, and catalog/access/policy revisions. AFK blocks unverified, unauthorized, overridden, unenforced, or silently degraded routes; a Codex host without model and effort selectors blocks differentiated AFK before spawn, and unreachable routes follow policy handoff/inherit/block exactly.
96
+ - **Path A:** requires the literal `Workflow` tool, callable and permitted, plus
97
+ individually proven named phases, run identity, runtime output validation,
98
+ journal, and resume. Then read [its recipe](references/dispatch-workflow.md).
99
+ - **Path B:** requires proven native spawn, wait, and aggregate plus effective
100
+ concurrency and thread capacity ≥2. Then read [its recipe](references/dispatch-subagents.md).
101
+ - **Path C:** keep recon and building direct and serial in the main thread. Produce
102
+ the same FILE → SLICES evidence, create each worktree from the integrated base,
103
+ apply the builder contract, validate the result, then continue. Load no reference.
104
+
105
+ Phases 0 and 3–6 always remain in the main thread. Visible fan-out progress may
106
+ replace the ~30-second heartbeat; otherwise the standing heartbeat remains required.
107
+
90
108
  ## Phase 0 — Setup
91
109
 
92
110
  1. **Read everything**: the anchor body, every sub-issue body (each has a Handoff
@@ -98,15 +116,15 @@ node scripts/readiness.mjs check --skill orchestrate-wave --json
98
116
  preflight's single degraded summary is the only warning. Never guess a project
99
117
  command, tunnel, login, or verify recipe.
100
118
  3. **Preflight — refuse a wave already in flight, otherwise claim it.** Before
101
- dispatch, inspect all three same-machine collision signals: **(a)** an existing
102
- `wave-active/<anchor>` tag; **(b)** any slice branch ahead of the wave's current
103
- base (`git rev-list --count <base>..<slice-branch>` > 0); **(c)** uncommitted
104
- changes in any slice worktree (`git -C <worktree> status --porcelain` non-empty).
105
- A hit not created by this run means another session may be building the wave:
106
- **STOP**, report the exact tag/branch/worktree, and do not touch it. If clean,
107
- record that this run owns the claim and plant a LOCAL annotated tag:
108
- `git tag -a wave-active/<anchor> -m "orchestrating since <UTC timestamp>;
109
- slices: <slice-branches>"`. It is local coordination state — never push it.
119
+ dispatch, inspect the two same-machine work signals: **(a)** any slice branch
120
+ ahead of the wave's current base (`git rev-list --count <base>..<slice-branch>`
121
+ > 0); **(b)** uncommitted changes in any slice worktree (`git -C <worktree>
122
+ status --porcelain` non-empty). Acquire the claim itself through `claimWave`
123
+ from `src/lib/waveClaim.mjs`: a compare-and-set on the `wave-active/<anchor>`
124
+ LOCAL annotated tag, so two sessions racing one wave cannot both win. Either
125
+ `acquired: false` or a work signal you did not create means another session
126
+ owns the wave **STOP**, report the returned `claim.owner` plus the exact
127
+ branch/worktree, touch nothing. Local coordination state — never push the tag.
110
128
  4. **Wave worktree**: reuse the planning worktree (never re-create; the handoff
111
129
  points there). Bring its branch to current `main`:
112
130
  `git -C <wave> merge --ff-only origin/main` (if your repo guards destructive
@@ -124,17 +142,10 @@ preflight clean + this run's local claim planted · wave branch ff'd to
124
142
 
125
143
  ## Phase 1 — Disjointness recon (the load-bearing step)
126
144
 
127
- Zero merge conflicts later depends entirely on getting this right.
128
-
129
- - Delegate to a read-only investigator agent: for EACH slice the exact file path of
130
- every named component + resolve ambiguous targets, then a **FILE → SLICES** table
131
- listing every file that appears in ≥2 slices.
132
- - Build the **overlap graph**. Identify the **conflict hub** (the slice whose new
133
- artifacts other slices reuse). **Build the hub first**, merge it, THEN the
134
- dependents stop conflicting.
135
- - Cut into **waves of fully file-disjoint slices**. Edited-by-≥2 = serialize across
136
- waves; only-shared-via-import = safe. A new primitive edited by one slice but
137
- *consumed* by others is NOT a conflict.
145
+ Phase 1 uses the selected orchestration mechanics. Resolve every named component,
146
+ produce the **FILE → SLICES** table and overlap graph, then build the conflict hub
147
+ before its dependents. Cut fully file-disjoint waves; shared imports are safe, but
148
+ files edited by multiple slices serialize across waves.
138
149
  - **Native blocking edges are the frontier authority.** Read the anchor's
139
150
  buildable frontier from the tracker's native issue dependencies:
140
151
  `python3 scripts/board-sync.py frontier <anchor#>` → `FREI` / `BLOCKED by #…` /
@@ -143,15 +154,11 @@ Zero merge conflicts later depends entirely on getting this right.
143
154
  body text or table order alone. The frontier must AGREE with your Phase-1
144
155
  dependency order; a contradiction is a plan finding to reconcile before dispatch,
145
156
  not a detail.
146
- - **Reconcile contradictory sub-issue ACs against the plan BEFORE dispatch — the
147
- plan is authority.** `to-issues` cuts slices independently, so a shared
148
- append-only file (a query-key registry, a barrel, a shared types module) is often
149
- claimed by *every* slice, with duplicate/clashing adds. **The hub slice OWNS the
150
- shared-mutable file: it pre-adds ALL the wave's keys/types/helpers; dependents
151
- CONSUME only and never touch it.** Embed verbatim in each dependent's contract:
152
- "X already exists in `<file>` — do NOT add it, consume only." (Real case: all 14
153
- sub-issues claimed the same registry adds + 4 contradictions — hub expanded to
154
- own all 20 keys, batch merged conflict-free.)
157
+ - **Reconcile contradictory sub-issue ACs against the plan BEFORE dispatch.** Safe
158
+ declaration-only registries may be predeclared by one hub; eager/validated
159
+ registries that read targets must serialize helper-owning slices through
160
+ dependency edges, each appending only its own existing artifact after creation.
161
+ Both preserve one owner per shared edit and the no-conflict invariant.
155
162
  - **Retirement slices require a valid topological deletion order.** Before
156
163
  dispatching slices that delete a legacy cluster, map every to-delete module's
157
164
  production importers and build the cluster's internal import graph. Order the
@@ -160,25 +167,19 @@ Zero merge conflicts later depends entirely on getting this right.
160
167
  deletions form a cycle, separate each-slice-green steps are impossible: combine
161
168
  the whole cycle into ONE atomic slice instead of landing dangling imports.
162
169
 
163
- **Done when:** FILE→SLICES table exists · every ≥2-slice file has exactly ONE
164
- owning slice · disjoint waves cut in dependency order · every dependent contract
165
- carries its verbatim consume-only lines.
170
+ **Done when:** FILE→SLICES table exists · each shared file has either one
171
+ declaration-only owner with verbatim consume-only dependents, or an explicit serialized
172
+ owner sequence for eager/validated additions where each owner appends only its own existing artifact · disjoint waves cut in dependency order.
166
173
 
167
174
  ## Phase 2 — Dispatch one wave in parallel (isolated worktree per implementer)
168
175
 
169
- Phase 2+3 repeat **per disjoint wave** from Phase 1 the conflict-hub wave first.
170
- Within ONE wave, all slices dispatch at once. **Dispatch only `FREI` slices**
171
- re-read the native frontier (`frontier <anchor#>`) before each wave; a
172
- gate-before-build edge clears only when its blocker actually lands (never
173
- "unblock" by editing body text remove the edge via `dep-remove` if the plan
174
- genuinely changed). Two per-slice calls first: **(a)
175
- inline vs delegate** a tiny mechanical bit (a rename, a 1-2-line tweak) you do
176
- yourself — and **(b) tier + effort** (Standing rules → Routing). For each
177
- delegated slice:
178
-
179
- - **One worktree per agent** off the wave-branch HEAD, own index so parallel agents
180
- never share a git index. Use your project's worktree-setup command (`§Setup`),
181
- else plain `git worktree add <path> -b feat/<anchor>-<slug>`.
176
+ Phase 2 uses the selected orchestration mechanics, repeating with Phase 3 per
177
+ disjoint wave, conflict hub first. Dispatch only `FREI` slices: re-read
178
+ `frontier <anchor#>` before each wave and clear changed edges only via `dep-remove`.
179
+ Before each slice, bind **(a) inline vs delegate** and **(b) tier + effort** under
180
+ Standing rules. Tiny mechanical work may stay inline.
181
+ For Path A/B, create one worktree per agent from wave HEAD, using `§Setup` or
182
+ `git worktree add <path> -b feat/<anchor>-<slug>`.
182
183
  - **Build the prompt from [`references/builder-contract.md`](references/builder-contract.md)**
183
184
  — fill the slots with the slice's VERBATIM What+AC, plan decision, recon
184
185
  file:line map and consume-only lines; never paraphrase (paraphrase drift has
@@ -193,8 +194,7 @@ package tests + green fast gate (`§Builder Commands`) — or a STOP item you re
193
194
 
194
195
  ## Phase 3 — Serial integration
195
196
 
196
- In the wave worktree: `git merge --no-ff <slice-branch>` per slice (disjoint
197
- conflict-free). After EACH wave, on the integrated branch:
197
+ In the wave worktree, `git merge --no-ff <slice-branch>` per slice. After EACH wave:
198
198
 
199
199
  - Typecheck both packages + the **FULL suite** — catches sibling/consumer test
200
200
  breaks the agent ownership didn't cover (hardcoded count/tab asserts). Exact
@@ -299,9 +299,9 @@ written · merge order documented.
299
299
  your own processes, targeted by the worktree's assigned ports, never blind).
300
300
  Remove temp verify scripts (a login helper, DB-check scripts).
301
301
  - **Remove only this run's claim marker.** If this run planted
302
- `wave-active/<anchor>`, delete that exact local tag after success or abort. Never
303
- delete a claim marker observed during a preflight collision or any other
304
- `wave-active/*` marker; ownership, not a broad pattern, authorizes cleanup.
302
+ `wave-active/<anchor>`, call `releaseWaveClaim` with this run's owner after
303
+ success or abort; its owner check, not a broad `wave-active/*` pattern,
304
+ authorizes cleanup, and a foreign marker is left untouched.
305
305
  - **Before removing any slice worktree, read its `ANNAHMEN.md`** (an assumptions
306
306
  log, gitignored at worktree-root) and propagate each build-time assumption marker
307
307
  to the sibling issue it carries. A hand-driven multi-PR / migration landing does
@@ -56,13 +56,26 @@ invocation for each in this prompt so the builder cannot guess a wrong one.
56
56
  completed command result. Never end your turn while a command is still running.
57
57
 
58
58
  ## Report back (concise)
59
- Files touched · decisions taken · test results (exact completed command results
60
- and exit status) · commit SHA · STOP items · what the orchestrator should visually
61
- verify.
59
+ Return exactly ONE JSON object against the builder report contract no prose
60
+ around it, no second object. Cover: files touched · decisions taken · test
61
+ results (exact completed command results and exit status) · commit SHA · STOP
62
+ items · what the orchestrator should visually verify.
62
63
  ```
63
64
 
64
65
  Orchestrator notes:
65
66
 
67
+ - **The report contract is identical on every orchestration path.** Whether the
68
+ builder was dispatched by a scripted workflow, by native subagents, or run
69
+ directly and serially, it reports the same shape. `src/lib/reportValidator.mjs`
70
+ is the source of truth; [`references/report-contracts.md`](report-contracts.md)
71
+ is its machine-checked mirror for hosts that must inline a schema. Fill the
72
+ report section above with the builder schema from whichever of the two the
73
+ host can reach — never a hand-written variant.
74
+ - **Validation is always the main thread's.** Schema-validate the returned
75
+ object, then call `semanticVerify` with independently collected Git facts. A
76
+ builder's own claim of success is a hypothesis; a payload that does not parse
77
+ or fails either check is a missing report, not a PASS.
78
+
66
79
  - `{{CONSUME_ONLY_LINES}}` come from the Phase-1 reconciliation, e.g.
67
80
  "X already exists in `<file>` — do NOT add it, consume only."
68
81
  - For dependent slices, fill hub artifact paths from the hub agent's report
@@ -0,0 +1,91 @@
1
+ # Path B — Native subagent dispatch
2
+
3
+ Load this recipe only when the capability selector returns Path B. That result
4
+ requires proven native spawn, wait, and aggregate primitives plus effective
5
+ concurrency and thread capacity ≥2. Route from proven capabilities only, never
6
+ from a surface name, and do not emulate a missing primitive.
7
+
8
+ This recipe is **dormant unless the current host's complete orchestration
9
+ inventory proves Path B.** The dated Codex routing attestation is a separate
10
+ gate: the observed explicit-spawn schema exposes only `task_name`, `message`,
11
+ and `fork_turns`, with no model or effort selector. Therefore
12
+ `routingAdapters/codex.mjs` blocks differentiated AFK before spawn even when
13
+ native start/wait/aggregate evidence is otherwise sufficient for Path B. A
14
+ future host may enable the route only by attesting both orchestration primitives
15
+ and applied model/effort controls; neither is inferred from the surface name.
16
+
17
+ ## Main-thread preparation
18
+
19
+ 1. Read the canonical `RECON_REPORT_SCHEMA` and `BUILDER_REPORT_SCHEMA` values
20
+ from `src/lib/reportValidator.mjs`. They are the same contract every
21
+ orchestration path reports against.
22
+ 2. Embed the relevant schema verbatim in each subagent prompt, together with the
23
+ instruction to return **exactly ONE JSON object** and nothing else — no
24
+ prose, no fences, no second object. The host does not enforce output shape,
25
+ so the contract lives in the prompt and the check lives in the main thread.
26
+ 3. Acquire the wave claim and create every worktree from the integrated base
27
+ through `claimWave` in `src/lib/waveClaim.mjs` before any spawn. Claim and
28
+ worktree creation stay serial in the main thread; only the agents fan out.
29
+
30
+ ## Round 1 — Recon
31
+
32
+ Spawn **one read-only explorer per slice**, all in one batch so they run
33
+ concurrently, then join them with an **explicit wait** on the spawned set —
34
+ never a sleep, a poll loop, or an implicit continue. Aggregate only after the
35
+ wait returns.
36
+
37
+ Each explorer returns one recon report. Validate every returned payload against
38
+ the recon schema in the main thread: a payload that does not parse, carries
39
+ extra top-level keys, or fails the schema **is not a PASS** — it is a missing
40
+ report. Re-spawn that single explorer with the failure quoted back to it; never
41
+ accept a prose summary in place of the object.
42
+
43
+ ## Main-thread reconcile boundary
44
+
45
+ Pass the complete, validated recon set to `reconcileReconReports`. A
46
+ reconciliation failure stops the wave. A successful result is the only boundary
47
+ that permits builders to start; use its overlap graph and dependency edges to
48
+ cut safe dispatch batches. Multiple editors are safe only when dependency
49
+ reachability totally orders them; shared-mutable files still require exactly one
50
+ edit owner.
51
+
52
+ Every orchestration path crosses this same main-thread reconciliation boundary.
53
+ Reconciliation is never delegated to a subagent.
54
+
55
+ ## Round 2 — Build
56
+
57
+ For the current reconciled batch, spawn **one builder per slice**, again as one
58
+ concurrent batch joined by an explicit wait. Give each builder the verbatim
59
+ builder contract, its reconciled allowlist, and its required commands. Resolve
60
+ the provider-neutral Routing intent immediately before each spawn. Pass the
61
+ decision through `routeDispatcher.mjs` and the active surface adapter. Claude
62
+ uses its native or explicitly policy-approved transport attestation; Codex uses
63
+ only its dated `routingAdapters/codex.mjs` host attestation. Both must prove
64
+ their requested and applied model and effort controls before invocation.
65
+ Detection alone never authorizes a transport.
66
+
67
+ The spawn guard compares the requested route with the adapter's applied route
68
+ and environment precedence. It emits the shared Dispatch receipt with
69
+ catalog/access/policy revisions. An unverified control, unauthorized transport,
70
+ override mismatch, or unenforced effort blocks AFK before spawn. A genuinely
71
+ unreachable route follows the policy's handoff, inherit, or block result; never
72
+ silently inherit. A host without a proved per-agent selector remains on its
73
+ existing parent-session fallback only when explicit non-AFK policy permits it.
74
+
75
+ Each builder returns exactly one builder report. Validate it against the builder
76
+ schema and then run `semanticVerify` on it in the main thread. A subagent's own
77
+ claim of success is a hypothesis, never the gate.
78
+
79
+ ## B1 fan-out is out of scope
80
+
81
+ The **B1** shape — a single fan-out over a work list (`spawn_agents_on_csv`)
82
+ plus a host-enforced per-agent `output_schema` — is explicitly excluded. The
83
+ same spike found the callable spawn schema exposes only `task_name`, `message`,
84
+ and `fork_turns`: no work-list fan-out and no output-schema parameter. This
85
+ recipe therefore documents the **B2** shape only: explicit per-slice spawns
86
+ joined by an explicit wait, with validation owned by the main thread.
87
+
88
+ Re-opening B1 requires its own version-pinned verify spike — tracked as an open
89
+ spike issue on the kit's own tracker — before any recipe or adapter change.
90
+ Never infer the capability from a release note; prove it against the pinned
91
+ runtime first.
@@ -0,0 +1,66 @@
1
+ # Path A — Scripted Workflow dispatch
2
+
3
+ Load this recipe only when the capability selector returns Path A. That result
4
+ requires the literal `Workflow` tool and every required primitive. Route from
5
+ proven capabilities only, never from a surface name, and do not emulate
6
+ Workflow. The current Codex host lacks complete capability evidence and selects
7
+ Path C; a future host selects whichever path its evidence proves.
8
+
9
+ ## Main-thread preparation
10
+
11
+ 1. Read the canonical `RECON_REPORT_SCHEMA` and `BUILDER_REPORT_SCHEMA` values
12
+ from `src/lib/reportValidator.mjs`.
13
+ 2. Serialize each value as an inline schema literal in its generated Workflow
14
+ script. Workflow scripts cannot import modules, so never put an `import()`,
15
+ `require`, `process`, or `fetch` workaround in them.
16
+ 3. Build deterministic run arguments. Pass run identity, slice IDs, prompts,
17
+ models, effort levels, and timestamps through `args`; never call
18
+ `Date.now()` or `Math.random()` in a script.
19
+
20
+ ## Run 1 — Recon
21
+
22
+ Declare the named recon phase in `meta.phases`. Within it, make one `agent()`
23
+ call per slice, with explicit `model`, `effort`, and `phase` options. Give every
24
+ call the inline recon schema so the Workflow runtime rejects prose or malformed
25
+ output before aggregation.
26
+
27
+ Use the run identity supplied in `args` and retain the Workflow-managed
28
+ `journal.jsonl`. The main thread waits for the Recon run to finish and collects
29
+ its schema-valid reports. It must not dispatch a builder yet.
30
+
31
+ ## Main-thread reconcile boundary
32
+
33
+ Pass the complete Recon-run result to `reconcileReconReports`. A reconciliation
34
+ failure stops the wave. A successful result is the only boundary that permits
35
+ the Build run to start; use its overlap graph and dependency edges to cut safe
36
+ dispatch batches. Multiple editors are safe only when dependency reachability
37
+ totally orders them; shared-mutable files still require exactly one edit owner.
38
+
39
+ Every orchestration path, including Paths B and C, must cross this same
40
+ main-thread reconciliation boundary. Reconciliation is not Workflow-script
41
+ logic.
42
+
43
+ ## Run 2 — Build
44
+
45
+ Generate a separate Build run with its own named entry in `meta.phases`. For the
46
+ current reconciled batch, make one `agent()` call per slice with explicit
47
+ `model`, `effort`, and `phase` options and the inline builder schema. Preserve
48
+ the reconciled allowlist and required commands in each verbatim builder prompt;
49
+ the main thread still performs `semanticVerify` on every returned report.
50
+
51
+ Before each `agent()` call, resolve its provider-neutral Routing intent and pass
52
+ the decision through the shared spawn guard and active surface adapter. The
53
+ Claude adapter must attest Workflow model/effort precedence in the current
54
+ environment; a future Codex host may use this path only when its dated
55
+ `routingAdapters/codex.mjs` attestation proves the same controls. Create the
56
+ Dispatch receipt before invocation; any requested/applied mismatch, unverified
57
+ control, or unauthorized transport blocks AFK rather than silently degrading.
58
+
59
+ ## Resume exactly once
60
+
61
+ Resume an interrupted Recon or Build run with its recorded `resumeFromRunId`
62
+ and the same deterministic `args`. Workflow returns cached results for completed
63
+ agents: accept those results and dispatch only unfinished calls. Never create a
64
+ replacement run for completed work, and never replay a completed builder. This
65
+ makes each builder phase execute exactly once while the retained
66
+ `journal.jsonl` remains the recovery and progress record.