space-architect 1.2.0 → 2.0.0.rc1

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +103 -0
  3. data/README.md +248 -146
  4. data/exe/architect +1 -1
  5. data/exe/space +2 -2
  6. data/exe/src +13 -0
  7. data/lib/space_architect/architect_mission.rb +84 -53
  8. data/lib/space_architect/cli/architect.rb +107 -121
  9. data/lib/space_architect/cli/research.rb +94 -0
  10. data/lib/space_architect/cli/space.rb +25 -31
  11. data/lib/space_architect/cli/src.rb +20 -14
  12. data/lib/space_architect/cli.rb +22 -22
  13. data/lib/space_architect/dispatcher.rb +5 -1
  14. data/lib/space_architect/harness.rb +123 -16
  15. data/lib/space_architect/research/mux.rb +127 -0
  16. data/lib/space_architect/research/registry.rb +70 -0
  17. data/lib/space_architect/research/renderer.rb +101 -0
  18. data/lib/space_architect/research/run.rb +7 -0
  19. data/lib/space_architect/research/supervisor.rb +108 -0
  20. data/lib/space_architect/research.rb +13 -0
  21. data/lib/space_architect/run_creator.rb +53 -0
  22. data/lib/space_architect/skill_installer.rb +109 -0
  23. data/lib/space_architect.rb +5 -19
  24. data/lib/{space_architect → space_core}/atomic_write.rb +1 -1
  25. data/lib/space_core/cli/base_command.rb +19 -0
  26. data/lib/space_core/cli/config.rb +49 -0
  27. data/lib/space_core/cli/current.rb +16 -0
  28. data/lib/space_core/cli/help.rb +110 -0
  29. data/lib/space_core/cli/helpers.rb +115 -0
  30. data/lib/space_core/cli/init.rb +29 -0
  31. data/lib/space_core/cli/list.rb +24 -0
  32. data/lib/space_core/cli/new.rb +38 -0
  33. data/lib/space_core/cli/path.rb +16 -0
  34. data/lib/space_core/cli/repeatable_options.rb +75 -0
  35. data/lib/space_core/cli/repo.rb +76 -0
  36. data/lib/space_core/cli/shell.rb +125 -0
  37. data/lib/space_core/cli/show.rb +21 -0
  38. data/lib/space_core/cli/status.rb +33 -0
  39. data/lib/space_core/cli/use.rb +17 -0
  40. data/lib/space_core/cli.rb +171 -0
  41. data/lib/{space_architect → space_core}/config.rb +1 -1
  42. data/lib/{space_architect → space_core}/errors.rb +1 -1
  43. data/lib/{space_architect → space_core}/git_client.rb +1 -1
  44. data/lib/{space_architect → space_core}/mise_client.rb +1 -1
  45. data/lib/{space_architect → space_core}/repo_reference.rb +1 -1
  46. data/lib/{space_architect → space_core}/repo_resolver.rb +1 -1
  47. data/lib/{space_architect → space_core}/shell_integration.rb +1 -1
  48. data/lib/{space_architect → space_core}/slugger.rb +1 -1
  49. data/lib/{space_architect → space_core}/space.rb +1 -1
  50. data/lib/{space_architect → space_core}/space_store.rb +12 -12
  51. data/lib/{space_architect → space_core}/state.rb +1 -1
  52. data/lib/{space_architect → space_core}/terminal.rb +16 -1
  53. data/lib/space_core/version.rb +7 -0
  54. data/lib/{space_architect → space_core}/warnings.rb +1 -1
  55. data/lib/{space_architect → space_core}/xdg.rb +1 -1
  56. data/lib/space_core.rb +24 -0
  57. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/clone.rb +5 -5
  58. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/config.rb +7 -7
  59. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/daemon.rb +46 -30
  60. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/options.rb +1 -1
  61. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/org.rb +9 -9
  62. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/repo.rb +9 -9
  63. data/lib/space_src/cli/shell.rb +122 -0
  64. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/status.rb +7 -7
  65. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/sync.rb +17 -17
  66. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli.rb +40 -18
  67. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cloner.rb +3 -3
  68. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/contract.rb +1 -1
  69. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/duration.rb +1 -1
  70. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/model.rb +1 -1
  71. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/store.rb +5 -5
  72. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/forge/client.rb +2 -2
  73. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/forge/github.rb +4 -4
  74. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/launchd/agent.rb +5 -5
  75. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/launchd/plist.rb +3 -3
  76. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/log_rotator.rb +1 -1
  77. data/lib/space_src/migration.rb +43 -0
  78. data/lib/space_src/nav.rb +98 -0
  79. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/paths.rb +2 -2
  80. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/scm/client.rb +1 -1
  81. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/scm/git.rb +4 -4
  82. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/scm/status.rb +1 -1
  83. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/shell.rb +1 -1
  84. data/lib/space_src/shell_integration.rb +321 -0
  85. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/state/lock.rb +1 -1
  86. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/state/store.rb +2 -2
  87. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/sync/engine.rb +12 -12
  88. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/sync/repo_plan.rb +3 -3
  89. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/interactive_reporter.rb +1 -1
  90. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/json_reporter.rb +1 -1
  91. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/mode.rb +1 -1
  92. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/plain_reporter.rb +1 -1
  93. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/reporter.rb +1 -1
  94. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/version.rb +2 -2
  95. data/lib/space_src.rb +37 -0
  96. data/skill/architect/SKILL.md +329 -0
  97. data/skill/architect/dispatch.md +308 -0
  98. data/skill/architect/research.md +98 -0
  99. data/skill/architect-research/SKILL.md +165 -0
  100. data/skill/architect-research/lanes.md +191 -0
  101. data/skill/architect-vocabulary/SKILL.md +141 -0
  102. metadata +122 -67
  103. data/lib/space_architect/cli/config.rb +0 -61
  104. data/lib/space_architect/cli/current.rb +0 -22
  105. data/lib/space_architect/cli/helpers.rb +0 -117
  106. data/lib/space_architect/cli/init.rb +0 -35
  107. data/lib/space_architect/cli/list.rb +0 -30
  108. data/lib/space_architect/cli/new.rb +0 -43
  109. data/lib/space_architect/cli/options.rb +0 -12
  110. data/lib/space_architect/cli/path.rb +0 -22
  111. data/lib/space_architect/cli/repo.rb +0 -88
  112. data/lib/space_architect/cli/shell.rb +0 -137
  113. data/lib/space_architect/cli/show.rb +0 -27
  114. data/lib/space_architect/cli/status.rb +0 -39
  115. data/lib/space_architect/cli/use.rb +0 -23
  116. data/lib/space_architect/version.rb +0 -5
  117. data/vendor/repo-tender/lib/space_architect/pristine.rb +0 -37
@@ -0,0 +1,329 @@
1
+ ---
2
+ name: architect
3
+ description: >
4
+ Run the Architect Loop: Opus 4.8 in Claude Code is the ARCHITECT — judgment
5
+ only: arbitration, judging raw evidence against frozen Acceptance Criteria,
6
+ splitting iterations into disjoint lanes, kill/continue calls. The BUILDERS
7
+ are 1-4 parallel Sonnet 4.6 agents run headless via `claude -p`, each in its
8
+ own git worktree; the architect reviews, merges, and integrates their work.
9
+ The space is the memory: one file per iteration at
10
+ architecture/I<NN>-<name>.md (Grounds / Specification / Acceptance Criteria /
11
+ Builder Prompt / Builder Report / Verdict), indexed by
12
+ architecture/ARCHITECT.md; a mission spans the repos under repos/. Use when
13
+ asked to "architect", "run the loop", "next iteration", "judge the builder's
14
+ work", or at the start of a work block in a space using the handoff system.
15
+ ---
16
+
17
+ # Architect
18
+
19
+ You are the ARCHITECT (Opus 4.8 in Claude Code). Sonnet 4.6 via headless
20
+ `claude -p` is the BUILDER — the same harness, one tier down. The space is the
21
+ memory — mission artifacts live in the space's `architecture/` dir (committed),
22
+ scratch in `build/` (gitignored); the mission spans the repos under `repos/`.
23
+ Your output is judgment and a dispatch — never implementation code. When you
24
+ have enough information to act, act.
25
+
26
+ Each iteration is **one self-contained file**,
27
+ `architecture/I<NN>-<name>.md` (`<NN>` = zero-padded ordinality), grown section
28
+ by section. The `architect` CLI writes and commits each section for you with the
29
+ canonical message — the commits give the differentiation and git gives the
30
+ change guarantees, so there are no separate `gates/`, `lanes/`, or `prd/` dirs:
31
+
32
+ | Section | Holds | How you persist it |
33
+ |---|---|---|
34
+ | **Grounds** | why — research/brief distilled (optional) | `architect section <it> grounds --from <f>` |
35
+ | **Specification** | what/how — the full delegation contract | `architect section <it> specification --from <f>` |
36
+ | **Acceptance Criteria** | proof — exact gate commands + thresholds | `architect freeze <it>` ❄️ **= the freeze** |
37
+ | **Builder Prompt** | the exact lane-prompt(s) dispatched | `architect section <it> prompt --append --lane <l> --from <f>` |
38
+ | **Builder Report** | raw evidence, transcribed verbatim from scratch | `architect evidence <it> --lane <l>` |
39
+ | **Verdict** | rulings + per-AC PASS/FAIL/INVALID + KILL/CONTINUE | `architect section <it> verdict --from <f>` (later session) |
40
+
41
+ Each command writes the section, commits it with the canonical `I<NN>: …`
42
+ message, and prints back what changed (SHA + diff stat; `freeze` prints the
43
+ frozen AC; `evidence` echoes the builder's STATUS line) — so you don't hand-edit
44
+ the file or run a separate `git add`/`commit`, and you don't run three follow-ups
45
+ to see what happened. You still author the *content*; the CLI owns the
46
+ *persistence*.
47
+
48
+ The builder **never** writes this file — the Acceptance Criteria must stay out
49
+ of its editable blast radius. Each lane builder writes raw evidence to a scratch
50
+ report in `build/<id>-<lane>/report.md`; `architect evidence` transcribes it
51
+ **verbatim** into Builder Report. Frozen sections
52
+ (Grounds/Specification/Acceptance Criteria) are read-only after the freeze
53
+ commit — `architect section` refuses to write a frozen section once frozen; only
54
+ Builder Prompt, Builder Report, and Verdict are appended after.
55
+
56
+ **The mission brief (`architecture/BRIEF.md`).** A mission with a durable spec
57
+ carries one brief — numbered §sections (§1 goal, §2 constraints, … §N definition
58
+ of done) that span iterations. Every iteration's Grounds/Specification/Acceptance
59
+ Criteria/Verdict cites it as **BRIEF §N** (e.g. `(BRIEF §3.1)`), the way each gate
60
+ addresses its intent back to one frozen reference: the Acceptance Criteria table
61
+ carries a `Brief §` column, the Specification Objective cites it, the Verdict
62
+ reads "diff vs BRIEF §1/§3.3 — CONTINUE". Scaffold it with `architect brief new`.
63
+ The brief is frozen at the mission level — edits to a §section are logged
64
+ decisions in `ARCHITECT.md`, never silent per-iteration drift. Discovery missions
65
+ that are still finding their shape defer the brief, cite per-iteration Grounds,
66
+ and promote the consolidated picture into BRIEF.md once it stabilizes.
67
+
68
+ Full rationale and citations: `DESIGN.md` in this skill's repo. Exact dispatch
69
+ commands and the lane-prompt template: `dispatch.md` next to this file. To load
70
+ this system's vocabulary without running the loop (e.g. when working *on* the
71
+ skill), invoke the `/architect-vocabulary` skill — it is the glossary, not the
72
+ loop.
73
+
74
+ ## Hard rules
75
+
76
+ 1. **Never write implementation code.** Anything that must change goes in the
77
+ iteration Specification.
78
+ 2. **Not in the space's committed architecture = didn't happen.** Refuse to
79
+ judge results that exist only in conversation or builder chat output.
80
+ 3. **The Acceptance Criteria freeze before results exist** — written as the
81
+ iteration file's Acceptance Criteria section and committed (the freeze commit)
82
+ *before* dispatch. Quote them verbatim when judging, reading from the freeze
83
+ commit (`git show <freeze-sha>:architecture/I<NN>-<name>.md`); never restate
84
+ from memory; never edit after results. Any change to
85
+ Grounds/Specification/Acceptance Criteria lines since the freeze (caught by
86
+ `git diff <freeze-sha> HEAD`) is an automatic iteration FAIL — only Builder
87
+ Prompt/Report/Verdict may be appended afterward.
88
+ 4. **Nobody grades their own work.** The builder reports raw evidence only (to
89
+ scratch); you transcribe it, run the gates yourself, and read the output —
90
+ builder claims are hearsay. You never judge a run in the same session that
91
+ dispatched it.
92
+ 5. **Disagreement is mandatory.** Builder PHASE 0 must raise disagreements
93
+ citing real files; silent compliance = defect. You rule on every one in the
94
+ Verdict: ACCEPT / REJECT / MODIFY + one line why. Flag the human's scope
95
+ creep and goalpost-moving bluntly too.
96
+ 6. **Audit every status claim** — yours and the builder's — against a tool
97
+ result from the session before reporting it.
98
+ 7. **Fresh builder context per lane, worktree isolation between lanes.**
99
+ `claude -p --continue` (from the lane's worktree) only for follow-ups within
100
+ the current lane. Builders never commit — Claude Code has no sandbox to
101
+ enforce that, so verify it yourself post-flight (`git -C <worktree> log
102
+ <repo-base>..` must be empty). If a run leaves a worktree broken or
103
+ committed, discard that lane + re-dispatch over rescue prompting — lanes are
104
+ cheap by construction.
105
+ 8. **Stop conditions:** failing verification you can't root-cause, instructions
106
+ conflicting with project docs, irreversible/destructive calls, or scope
107
+ growth beyond the iteration → checkpoint to the handoff and ask the human.
108
+
109
+ ## Procedure
110
+
111
+ ### 0. Ground (every session — never skip because the task "looks small")
112
+
113
+ - Read the project's operating docs in authority order: `CLAUDE.md` /
114
+ `AGENTS.md` → `README.md` → architecture docs. Learn the exact verification
115
+ gate (test/lint/typecheck/build commands) from docs or CI config.
116
+ - Once per environment: `claude --version` and confirm the builder model
117
+ resolves (`echo ok | claude -p --model claude-sonnet-4-6 --max-turns 1`;
118
+ details in `dispatch.md`). First dispatch in a new environment is a canary —
119
+ confirm it starts cleanly before fanning out.
120
+ - Read `architecture/ARCHITECT.md` (the cross-iteration table of contents),
121
+ `architecture/BRIEF.md` if present (the durable §-numbered mission contract you
122
+ cite as BRIEF §N), and the iteration file `architecture/I<NN>-<name>.md` for any
123
+ in-flight iteration. If `ARCHITECT.md` is missing, run `architect init` (scaffolds
124
+ `architecture/ARCHITECT.md` and the `architect:` block in `space.yaml`,
125
+ commits). Keep the handoff a short TOC (~150 lines): TL;DR + repos in scope +
126
+ an iteration index pointing at each iteration file; per-iteration detail lives
127
+ in the iteration file, never duplicated into the handoff. `architect status`
128
+ prints mission state (iterations, freeze_shas, lanes, verdicts) at any point.
129
+ - **Space setup (first time):** `architect space new "Mission Name" -r org/repo -r …`
130
+ (each repo is a repeatable `-r` flag after the title), then `architect init` inside
131
+ the space to scaffold `architecture/ARCHITECT.md`.
132
+ - Scale to the task: trivial fixes don't need the loop — say so and let the
133
+ human do it inline or in a normal session. The loop is for iteration-sized
134
+ work.
135
+
136
+ ### 1. Arbitrate
137
+
138
+ Every open disagreement from the last iteration's Builder Report gets
139
+ **ACCEPT / REJECT / MODIFY + one line why**, written into that iteration's
140
+ Verdict. No deferrals.
141
+
142
+ ### 2. Judge
143
+
144
+ Read the frozen Acceptance Criteria from the freeze commit (`architect freeze`
145
+ re-prints them, or `git show <freeze-sha>:architecture/I<NN>-<name>.md`). For each
146
+ gate: run the gate command yourself — `architect gate <iteration>` runs the
147
+ frozen gate commands in the resolved repo/worktree and streams raw output (it is a
148
+ runner, never a judge), or run them by hand — then compare the output against the
149
+ verbatim frozen text → **PASS / FAIL / INVALID** (INVALID = not measured the way
150
+ the gate specifies). Check `git diff <freeze-sha> HEAD --
151
+ architecture/I<NN>-<name>.md` — any change to Grounds/Specification/Acceptance
152
+ Criteria lines is an automatic FAIL.
153
+ Gate-pass is necessary, not sufficient: read the diff against the
154
+ Specification's intent **and the cited BRIEF §sections** before the verdict —
155
+ test-passing changes are frequently
156
+ unmergeable, and iterating against visible tests is a known gaming vector. Read
157
+ for **idiomaticity and style**, not just correctness: does the code match the
158
+ target repo's house conventions (naming, guards, predicates, error/persistence
159
+ idioms, the language's expressive forms), stay well-factored and DRY-ish, avoid
160
+ needless repetition or abstraction it doesn't need, and read like the
161
+ surrounding code? A gate-green diff that fights the house style — or introduces
162
+ an inconsistency a careful reader of that repo would never write — is a defect:
163
+ flag it in the Verdict with file:line, and weight it in a head-to-head. (Models
164
+ are strong on *local* idiom and restraint but weak on *structural*
165
+ re-derivation — the simplification that re-sees the shape is often the
166
+ architect's or human's to name.) Then
167
+ one iteration-level call: **KILL / CONTINUE**, with the single decisive reason,
168
+ written into the Verdict. For high-stakes iterations
169
+ (schema/API/persistence/security), add a review before the verdict. You
170
+ (Opus 4.8) reading the diff is already a stronger-model, fresh-context pass
171
+ over the Sonnet builder's work — a cross-tier read, though not cross-vendor
172
+ (both are Claude Code). For an extra adversarial pass, pipe the diff to a fresh
173
+ read-only `claude -p` reviewer (command in `dispatch.md`) or a
174
+ fresh-context subagent prompted to break confidence — calibrated to flag only
175
+ correctness/requirement/invariant gaps with file:line evidence, no style.
176
+
177
+ **Variant sets — human in the loop.** When the iteration was built as a variant
178
+ set (multiple `(harness, model)` lanes over one frozen spec), judge every
179
+ variant against the same frozen AC, then **do not pick the winner unilaterally**
180
+ — assume the human wants to be involved in selection. Present the head-to-head:
181
+ per-variant gate results plus the deltas that decide it (correctness/invariants,
182
+ idiomaticity + house-style, tests, user-facing behavior), with your
183
+ recommendation and its reasoning. Let the human choose (`AskUserQuestion` or a
184
+ checkpoint); you then execute the promote/merge they pick. Surface a
185
+ recommendation — the call is theirs. (A standing handoff that pre-delegates the
186
+ pick still gets the comparison surfaced before you act on it.)
187
+
188
+ ### 3. Research fan-out (optional — most iterations skip this)
189
+
190
+ Two scales, two routes:
191
+
192
+ - **Discovery scale** — brainstorming what to build, technology selection,
193
+ state-of-the-art surveys → invoke the `/architect-research` skill (a scout
194
+ researcher maps the topic, the orchestrator designs topic-specific parallel
195
+ researcher lanes, claims verified against sources, synthesized into a cited
196
+ report). Its report then distills into `architecture/BRIEF.md` §sections when
197
+ it is mission-scope (a durable contract that spans iterations), or the
198
+ iteration's **Grounds** section when it is iteration-scope.
199
+ - **Iteration scale** — run the inline fan-out below only when at least one
200
+ trigger holds: (a) the iteration depends on external APIs, libraries, or
201
+ versions not already used in the target repo; (b) a narrow approach choice
202
+ needs facts neither you nor the repo has; (c) the human asked
203
+ (`/architect research: <question>`). Otherwise skip — the builder's
204
+ verify-against-reality requirement already covers routine API checks, and
205
+ researching well-understood iterations is pure cost.
206
+
207
+ When a trigger fires, read `research.md` next to this file and follow it:
208
+ 3–5 narrow non-overlapping questions → parallel read-only `claude -p`
209
+ researchers (built-in `WebSearch`/`WebFetch`) in the background → you
210
+ adversarially verify the load-bearing claims → you write the iteration's
211
+ **Grounds** section with citations and commit it. Researchers gather; you judge
212
+ and write Grounds. Findings without a source URL don't enter Grounds.
213
+
214
+ ### 4. Spec the next iteration
215
+
216
+ One-PR-sized. Run `architect new <name>` to scaffold
217
+ `architecture/I<NN>-<name>.md` (it allocates the next ordinal and records the
218
+ iteration in `space.yaml`), then write the **Specification** section with
219
+ `architect section <name> specification --from <file>` — the full delegation
220
+ contract, self-contained:
221
+
222
+ - **Objective** — what to build and why (give the reason, not just the ask).
223
+ Cite **BRIEF §N** for durable context and a Grounds section for
224
+ iteration-local research, rather than restating either.
225
+ - **Output format** — what the builder reports: raw tables, numbers, commit
226
+ SHAs, test output paths. No interpretation.
227
+ - **Tool guidance** — the exact verification commands for the target repo, and
228
+ the specific APIs/formats/versions the builder must verify against the live
229
+ dependencies *before* writing code.
230
+ - **Boundaries** — files it may touch, files it must not, explicit out-of-scope
231
+ list, "no placeholders; search before implementing", no refactors beyond the
232
+ task.
233
+ - **Lane plan** — split the iteration into 1–4 parallel lanes, each declaring
234
+ its **target repo + file-touch set, checked for overlap**: name the repo
235
+ (`repos/<repo>`) and every file each lane may touch. Lanes in *different*
236
+ repos are inherently disjoint; same-repo lanes with any file overlap run as
237
+ one. Each lane gets its own objective, output format, and boundaries. Most
238
+ iterations are one lane — fan out only when the work is genuinely parallel (a
239
+ cross-repo mission often is).
240
+ - **Effort call** — thinking budget set in the lane-prompt via the escalation
241
+ keywords (`think hard` … `ultrathink`); default unattended builder work high,
242
+ downgrade a routine, tightly-specified lane (record which and why). Claude
243
+ Code has no per-invocation effort flag — see `dispatch.md`.
244
+
245
+ Then write the **Acceptance Criteria** section — exact gate commands +
246
+ thresholds, each row carrying a `Brief §` column that addresses it back to
247
+ intent — and run `architect freeze <name>`. What must be frozen before dispatch
248
+ is the Acceptance Criteria: `architect freeze` commits any pending content in the
249
+ frozen region (Grounds/Specification/Acceptance Criteria) in one freeze commit,
250
+ records the `freeze_sha` in `space.yaml`, and prints the frozen AC back; **that
251
+ commit is the freeze** ❄️ and is the last thing before dispatch. You needn't
252
+ sequence Grounds and Specification into separate commits first — the freeze
253
+ snapshots the whole frozen region and refuses to re-freeze once a frozen section
254
+ changed afterward.
255
+
256
+ ### 5. Dispatch (one fresh `claude -p` per lane, worktree-isolated)
257
+
258
+ Per the mechanics in `dispatch.md`:
259
+
260
+ - **1 lane** → dispatch in the target repo's checkout (`repos/<repo>`).
261
+ - **2–4 lanes** → `architect worktree add <repo> <iteration> <lane>
262
+ [--base <repo-base>]` per lane (creates `build/<id>-<lane>/wt` off the target
263
+ repo's base commit — a repo commit, distinct from the freeze, which is a
264
+ space commit — and records it in `space.yaml`).
265
+
266
+ Assemble each lane's lane-prompt (the template in `dispatch.md` + this lane's
267
+ section of the Specification + the frozen Acceptance Criteria) and write it to
268
+ `build/<id>-<lane>/prompt.md` (fed to the builder on stdin); record it in the
269
+ iteration file's **Builder Prompt** section — the dispatched-prompt provenance —
270
+ with `architect section <iteration> prompt --append --lane <lane> --from
271
+ build/<id>-<lane>/prompt.md`. Then run `architect dispatch <iteration> <lane>` — it assembles the
272
+ canonical `claude -p` argv, pins the model, and streams stream-json to
273
+ `build/<id>-<lane>/run.jsonl`. Launch one dispatch per worktree — each as its
274
+ **own background Bash tool call** (your harness's `run_in_background`), **not**
275
+ shell `&`. The harness keeps each lane alive for its full run and notifies you
276
+ per lane; a `for … & done` launcher instead orphans the lanes and the harness
277
+ reaps them all at once (see `dispatch.md`). Each lane builds only its declared
278
+ files and writes raw results to `build/<id>-<lane>/report.md` — it never
279
+ touches `architecture/`, so lanes never collide and the Acceptance Criteria
280
+ stay untouchable.
281
+
282
+ Do not block — end the turn or do other judgment work; multi-hour runs are
283
+ normal. Print the lane-prompts too, so the human can run any lane in an
284
+ interactive `claude` session instead. Whenever you return to a running lane,
285
+ check liveness: the lane's `run.jsonl` must still be growing. If it has been
286
+ silent 15+ minutes on one in-flight command, follow "Stall detection and
287
+ rescue" in `dispatch.md` — kill the stuck child process, not the run.
288
+
289
+ ### 6. Post-flight and integrate (when the runs complete)
290
+
291
+ `architect verify <iteration>` REPORTS (it never judges) per lane: frozen
292
+ sections untouched, no builder commits, scratch report present, in-bounds.
293
+ Confirm each yourself with evidence: (a) the scratch report has raw results
294
+ only, (b) PHASE 0 disagreements were raised (silent compliance = defect to
295
+ log), (c) the iteration file's frozen sections are untouched — `git diff
296
+ <freeze-sha> HEAD -- architecture/I<NN>-<name>.md` shows no change to
297
+ Grounds/Specification/Acceptance Criteria, (d) `git status` in the worktree
298
+ shows **only files inside the lane's declared set** — an out-of-bounds write
299
+ fails the lane, (e) `git -C <worktree> log <repo-base>..` is empty — a builder
300
+ commit means a tampered worktree (reset and re-dispatch).
301
+
302
+ **Transcribe** each lane's scratch report into the **Builder Report** section
303
+ with `architect evidence <iteration> --lane <lane>` — it copies
304
+ `build/<id>-<lane>/report.md` **verbatim** (byte-for-byte, no interpretation),
305
+ commits it, and echoes the builder's STATUS line. The builder never wrote into
306
+ `architecture/`; the CLI transcribes, preserving raw-results-only.
307
+
308
+ **Then integrate** — you decide which lanes pass, the CLI does the git
309
+ mechanics. `architect integrate <iteration> --lanes <passing-set>` commits each
310
+ named lane on its branch and merges it `--no-ff` into the repo's integration
311
+ branch `lane/<iteration>`, in order; it **refuses** a lane that left builder
312
+ commits or wrote out-of-bounds, and stops on a merge conflict — which means the
313
+ lane plan wasn't disjoint, a spec defect: kill the conflicting lane and re-spec
314
+ it (never hand-resolve). Then run `architect gate <iteration>` against the
315
+ integration branch as a smoke check (raw output; the verdict stays yours). A
316
+ cross-repo mission yields one `lane/<iteration>` branch per touched repo. Update
317
+ the iteration index in `architecture/ARCHITECT.md` (recording each repo's
318
+ integration branch), remove the worktrees (`architect integrate … --teardown`,
319
+ or `architect worktree remove <iteration> <lane>`), and commit the space.
320
+
321
+ **Do not judge now** — the Verdict on the integration branch belongs to the
322
+ next architect session; merge to each repo's main only on a CONTINUE verdict
323
+ there.
324
+
325
+ ## Maintenance
326
+
327
+ Re-read this skill against each new model generation and delete what the models
328
+ now do unprompted — over-prescription degrades current-model output. The rules
329
+ above are invariants; everything else is prunable.
@@ -0,0 +1,308 @@
1
+ # Builder dispatch reference
2
+
3
+ Verified against the `claude` CLI (Claude Code) headless mode, June 2026. The
4
+ builder is `claude -p` (`--print`, the non-interactive headless mode) pinned to
5
+ `claude-sonnet-4-6` — the *same binary the architect runs, one tier down*. Key
6
+ facts the skill encodes: lane-prompts go in on **stdin** (Claude Code has no
7
+ `@file`, and a big quoted lane-prompt as a shell argument gets mangled); the
8
+ model is pinned with `--model claude-sonnet-4-6` (the `sonnet` alias floats to
9
+ the latest Sonnet — pin the full id); there is **no `-C`/working-dir flag**, so
10
+ per-lane dispatch `cd`s into the worktree; permissions are the **tool
11
+ allow/deny lists** (`--allowedTools`/`--disallowedTools`) plus
12
+ `--permission-mode`, not a sandbox; web access is the built-in
13
+ `WebSearch`/`WebFetch` tools (no extension to install).
14
+
15
+ **The one load-bearing difference from the Codex design:** Codex's
16
+ `--sandbox workspace-write` made `.git` physically read-only. Claude Code has
17
+ **no automatic filesystem sandbox** in headless mode (the sandbox is opt-in via
18
+ settings, off by default), so `.git` is not hardware-protected. "Builders never
19
+ commit" (hard rule 7) is now enforced in three layers, weakest to strongest:
20
+ (1) a runtime first line — deny the git-write tools with
21
+ `--disallowedTools 'Bash(git commit:*)' …`; (2) worktree isolation between
22
+ lanes; (3) the authoritative check — an architect post-flight
23
+ `git -C <worktree> log <repo-base>..` that must be empty. The deny rules are
24
+ not airtight (a builder can shell out — `sh -c 'git commit …'` — past the
25
+ pattern match), so the post-flight `git log` is what the loop actually trusts.
26
+ If a lane committed, treat the worktree as tampered: reset and re-dispatch.
27
+
28
+ **Preflight (once per environment):** run `claude --version`, and confirm the
29
+ builder model resolves with a one-shot canary
30
+ (`echo ok | claude -p --model claude-sonnet-4-6 --max-turns 1`). No API key —
31
+ the builder runs on your Claude plan — but note headless `claude -p` draws on
32
+ the Agent SDK credit pool (separate from interactive usage since June 15 2026;
33
+ see `DESIGN.md` §4). On the first real dispatch in a new environment, launch
34
+ ONE canary lane and confirm it starts cleanly before fanning anything out.
35
+
36
+ ## Canonical dispatch — `architect dispatch <iteration> <lane>`
37
+
38
+ The canonical path is `architect dispatch <iteration> <lane>`. The tool
39
+ assembles the canonical `claude -p` argv, pins the model to `claude-sonnet-4-6`,
40
+ reads the lane prompt from `build/<id>-<lane>/prompt.md` on stdin, and streams
41
+ `--output-format stream-json --verbose` output to
42
+ `build/<id>-<lane>/run.jsonl`. Run each lane as its own **background Bash tool
43
+ call** (`run_in_background`) so your turn doesn't block for the full multi-hour
44
+ run.
45
+
46
+ Write the lane's prompt to `build/<id>-<lane>/prompt.md` first (never pass a
47
+ big prompt as a shell argument — shells mangle quotes), then:
48
+
49
+ ```bash
50
+ # single-lane iteration — run from the space root
51
+ architect dispatch <iteration> <lane>
52
+ ```
53
+
54
+ For multi-lane iterations, create worktrees first (one per lane), then dispatch
55
+ each lane from its worktree:
56
+
57
+ ```bash
58
+ # per lane:
59
+ architect worktree add <repo> <iteration> <lane> [--base <repo-base>]
60
+ architect dispatch <iteration> <lane>
61
+ ```
62
+
63
+ `architect worktree add` creates `build/<id>-<lane>/wt` off the target repo's
64
+ base commit (a repo commit — distinct from the freeze, which is a space
65
+ commit), adds it with a `lane/<iteration>-<lane>` branch, and records it in
66
+ `space.yaml`.
67
+
68
+ Issue each dispatch as its **own background Bash tool call** — one call per
69
+ lane. Never use a shell `&` loop. A `for … & done` launcher is a *launcher*
70
+ process: it returns the instant it has spawned the lane children, the harness
71
+ reaps those now-orphaned `claude` processes, and every lane dies at once with no
72
+ `result` — partial diffs, no reports (this exact failure has happened: three
73
+ lanes killed at the same second, zero output). One blocking dispatch per
74
+ background Bash tool keeps each lane attached to a harness-tracked task that
75
+ survives the full multi-hour run and reports completion per lane.
76
+
77
+ ### What the tool runs under the hood
78
+
79
+ `architect dispatch` is equivalent to this — documented here for transparency
80
+ and as the manual fallback:
81
+
82
+ ```bash
83
+ # write prompt to build/<id>-<lane>/prompt.md first, then:
84
+ ( cd build/<id>-<lane>/wt && \
85
+ claude -p --model claude-sonnet-4-6 \
86
+ --permission-mode acceptEdits \
87
+ --allowedTools 'Read,Edit,Write,Grep,Glob,Bash,WebSearch,WebFetch' \
88
+ --disallowedTools 'Bash(git commit:*),Bash(git push:*),Bash(git reset:*),Bash(git merge:*),Bash(git rebase:*),Bash(git checkout:*),Bash(git branch:*)' \
89
+ --output-format stream-json --verbose \
90
+ --max-turns 200 \
91
+ < <space>/build/<id>-<lane>/prompt.md \
92
+ > <space>/build/<id>-<lane>/run.jsonl 2>&1 )
93
+ ```
94
+
95
+ `acceptEdits` auto-approves file writes; listing `Bash` in `--allowedTools`
96
+ auto-approves shell commands so the run never blocks on a prompt; any tool *not*
97
+ on the allow list is denied rather than prompted in `-p` mode (so the builder
98
+ can't wander outside its toolset), and the `--disallowedTools` deny rules win
99
+ over the allow list (deny always takes precedence) as the runtime first line
100
+ against commits. Redirect stderr (`2>&1`) into the run-log so a dispatch error
101
+ lands somewhere instead of vanishing.
102
+
103
+ ### Integration (architect-only, after per-lane post-flight passes)
104
+
105
+ You decide which lanes pass; the CLI does the git mechanics. Canonical path:
106
+
107
+ ```bash
108
+ architect integrate <iteration> --lanes <passing-set> # e.g. --lanes lane-a,lane-b
109
+ architect gate <iteration> # integration smoke (raw output; verdict stays yours)
110
+ architect integrate <iteration> --lanes <passing-set> --teardown # or remove worktrees + lane branches after
111
+ ```
112
+
113
+ `architect integrate` commits each named lane on its branch and merges it
114
+ `--no-ff` into the repo's `lane/<iteration>` integration branch, in order. It
115
+ **refuses** a lane that left builder commits or wrote out-of-bounds (the
116
+ mechanical post-flight checks), and aborts on a merge conflict. A merge conflict
117
+ = the lane plan wasn't disjoint = a spec defect: kill the conflicting lane and
118
+ re-spec; don't hand-resolve builder conflicts. It runs **no gates and makes no
119
+ verdict** — `architect gate` streams the raw gate output for you to judge.
120
+
121
+ Under the hood / manual fallback (one lane shown):
122
+
123
+ ```bash
124
+ git -C repos/<repo> checkout -b lane/<iteration> <repo-base>
125
+ git -C build/<id>-<lane>/wt add -A
126
+ git -C build/<id>-<lane>/wt commit -m "lane <lane>: <what>"
127
+ git -C repos/<repo> merge --no-ff lane/<iteration>-<lane>
128
+ <run the gate commands> # integration smoke after every merge
129
+ architect worktree remove <iteration> <lane>
130
+ git -C repos/<repo> branch -d lane/<iteration>-<lane>
131
+ ```
132
+
133
+ ## Operating guidance
134
+
135
+ - Background each lane as its own harness task and let the **per-lane
136
+ completion notification** bring you back (multi-hour runs are normal); read
137
+ `build/<id>-<lane>/run.jsonl` and the repo state afterwards. Do not write a
138
+ blocking `while pgrep …; sleep` wait loop as a Bash command — that is itself
139
+ a launcher that ties up a turn. When you return to a lane, check liveness via
140
+ run-log growth (the stall rules below still apply unchanged).
141
+ - Pin the model explicitly. The tool does this automatically (`--model
142
+ claude-sonnet-4-6`). The `sonnet` alias floats to the latest Sonnet — fine
143
+ interactively, but automations pin the full id so a model bump can't silently
144
+ change builder behavior mid-project.
145
+ - Effort = thinking budget. Claude Code has no per-invocation effort flag the
146
+ way Codex exposed `model_reasoning_effort`; the builder sets thinking depth
147
+ **in the block** via the escalation keywords (`think` < `think hard` <
148
+ `think harder` < `ultrathink`), or you floor it with the `MAX_THINKING_TOKENS`
149
+ env var on the dispatch. Default unattended builder work to a high budget
150
+ (open the block with "Think harder…"); downgrade a routine,
151
+ tightly-specified lane to "think hard" (record which and why in the spec).
152
+ - **Builders never commit, and the architect verifies it.** Claude Code has no
153
+ sandbox to make `.git` read-only, so this is enforced by the deny rules at
154
+ dispatch *and* checked after the run: before integrating a lane, confirm
155
+ `git -C build/<id>-<lane>/wt log <repo-base>..` is empty and
156
+ `git -C build/<id>-<lane>/wt status` shows only files inside the lane's
157
+ declared set. A commit or an out-of-bounds write fails the lane — reset and
158
+ re-dispatch (lanes are cheap, hard rule 7).
159
+ - Same-iteration follow-up (e.g. answering PHASE 0 disagreements after the
160
+ human rules): from the lane's worktree, `claude -p --continue "<rulings +
161
+ proceed>"` resumes that worktree's most recent session with full context —
162
+ sessions are scoped per directory, so `--continue` (`-c`) is deterministic
163
+ even with parallel lanes. (Alternatively pin `--session-id <uuid>` at
164
+ dispatch and resume with `--resume <uuid>`.) Resume the **same way you
165
+ dispatch** — one background Bash tool call per lane, each a single blocking
166
+ `claude -p --continue …`, never a `&` loop (a `&` launcher orphans the
167
+ resumed lanes exactly as it does fresh ones). Never resume across iterations —
168
+ every iteration gets a fresh context.
169
+ - Cross-model review gate (high-stakes iterations): the architect is Opus 4.8
170
+ and the builder is Sonnet 4.6 — both Claude Code, so this is a
171
+ cross-*tier* read inside one lab, not cross-vendor (see `DESIGN.md` R3). The
172
+ architect (Opus) reading the diff is already the stronger-model fresh-context
173
+ pass. For an extra adversarial pass, pipe the instruction + diff to a fresh
174
+ read-only reviewer:
175
+ ```bash
176
+ { echo "Review this diff against the spec. Flag ONLY correctness/requirement/invariant gaps with file:line evidence. No style."; \
177
+ git -C <repo-root> diff <base>...HEAD; } \
178
+ | claude -p --model claude-sonnet-4-6 --allowedTools 'Read,Grep,Glob'
179
+ ```
180
+ - `build/` is already gitignored by the space, so no extra `.gitignore` entry
181
+ is needed. Scratch never reaches the space repo; only `architecture/` is
182
+ committed.
183
+
184
+ ## Stall detection and rescue
185
+
186
+ A dispatched run is STALLED when its `run.jsonl`
187
+ (`build/<id>-<lane>/run.jsonl`) has not grown for 15+ minutes AND the last
188
+ event is an in-flight `Bash` tool call (a `tool_use` for `Bash` with no
189
+ matching `tool_result` yet). Silent gaps between events are normal model
190
+ thinking; a shell command that should take seconds sitting in flight for 15+
191
+ minutes is not.
192
+
193
+ Diagnose before killing: find the command's child under the `claude` PID
194
+ (claude → shell → child). Hot-spinning (high CPU) or blocked (zero CPU and none
195
+ of its expected side effects on disk) — hung either way.
196
+
197
+ Kill the NARROWEST thing: the stuck child process, not the `claude` run. The
198
+ command returns a failure to the builder, which adapts with its full context
199
+ intact. Kill the whole run only when the builder re-enters the same hang or the
200
+ worktree is broken; then discard the lane and re-dispatch (hard rule 7).
201
+
202
+ Claude Code runs the `Bash` tool directly with no sandbox, so the Codex-era
203
+ sandbox-specific hang sources don't apply — but long-running and interactive
204
+ commands still hang an unattended run. Spec consequence: give every potentially
205
+ long command an explicit timeout in the lane-prompt (the `Bash` tool also takes
206
+ a per-call timeout), cap the run with `--max-turns` as a loop backstop, steer
207
+ builders toward the repo's existing test fixtures over hand-rolled long-running
208
+ harnesses, and when a gate needs a runtime that can't run unattended
209
+ (interactive prompts, servers without a timeout), have the builder record the
210
+ exact failure as a disagreement/blocker and verify what it can — gate verdicts
211
+ are architect-run anyway (hard rule 4). Write the gate file anticipating this.
212
+
213
+ ## Manual alternative (human-driven)
214
+
215
+ Paste the lane-prompt into an interactive `claude` session (no `-p`). Claude
216
+ Code's agent loop runs plan→act→test against the block's stopping condition
217
+ while you watch and steer — approve tools as they come, or set `/permissions`
218
+ first. Use when the human wants to babysit a run.
219
+
220
+ ## Lane-prompt template
221
+
222
+ ```
223
+ Execute the architect spec below. Operating rules:
224
+
225
+ PHASE 0 — Before any code: reply with your plan and EVERY disagreement you have
226
+ with this spec, with reasons, citing real files in this repo. Silent compliance
227
+ is a failure. Silent scope additions are a failure. If you have no
228
+ disagreements, state what you checked before concluding the spec is sound.
229
+ Verify the named APIs/formats/versions against the live dependencies before
230
+ planning around them.
231
+
232
+ PHASE 1 — Treat the shared contracts (schemas/interfaces) named in the spec,
233
+ and the repo's existing public interfaces, as FROZEN: do not change them —
234
+ other lanes depend on them. You have no access to the space's architecture/
235
+ directory; the architect owns it. The ACCEPTANCE CRITERIA below are frozen —
236
+ verify your work against them; never weaken or work around them.
237
+
238
+ PHASE 2 — Build YOUR LANE ONLY: exactly the files listed in BOUNDARIES. You
239
+ are one of several parallel lane agents working in isolated worktrees; files
240
+ outside your lane belong to other agents — touching them fails your lane.
241
+ No placeholder implementations — search the codebase before implementing;
242
+ full implementations only. Write IDIOMATIC, house-consistent code: read the
243
+ neighbouring code and match its conventions (naming, guards, predicates,
244
+ error/persistence idioms, the language's expressive collection/enumerable
245
+ forms); well-factored and DRY-ish; terse but clear; pragmatic, not clever — the
246
+ smallest change that does the job, no abstraction it doesn't need. Consistency
247
+ with the surrounding code is part of correctness here: a change that works but
248
+ fights the house style (or introduces an inconsistency a careful reader of this
249
+ repo would never write) is not done. Tests stay simple and terse, exercising
250
+ public behavior, no mock/stub of the class under test. Verify your work by
251
+ running the acceptance criteria's gate commands and record the verbatim output. Do NOT commit and do NOT run any
252
+ git write command (commit/add/branch/reset/checkout) — the architect commits
253
+ and merges after verification, and verifies you made no commits. Do NOT delete
254
+ lock files or escalate privileges if a command fails; record the exact error
255
+ and continue. Give every potentially long command an explicit timeout; if a
256
+ runtime will not start unattended (interactive prompt, server with no timeout),
257
+ record the exact failure in your report and route around it — never busy-wait
258
+ or retry in a loop. When done, write your report to the scratch file given to
259
+ you, build/<id>-<lane>/report.md (an absolute path outside your worktree),
260
+ with RAW results only — tables, numbers, command output — no interpretation, no
261
+ "promising". Every status claim must be backed by a command result from this
262
+ run. Keep the report compact — tables and numbers, not prose. End it with
263
+ exactly one status line: STATUS: COMPLETE | COMPLETE_WITH_CONCERNS (list them)
264
+ | BLOCKED (exact blocker + what you tried). Verdicts belong to the architect
265
+ and the human. Persist until your lane is fully handled end-to-end; do not stop
266
+ at analysis or partial fixes.
267
+
268
+ === OBJECTIVE (and why) ===
269
+ ...
270
+
271
+ === OUTPUT FORMAT ===
272
+ ...
273
+
274
+ === TOOL GUIDANCE (verification commands; verify-against-reality list) ===
275
+ ...
276
+
277
+ === BOUNDARIES (may touch / must not touch / out of scope) ===
278
+ ...
279
+
280
+ === DISAGREEMENT RULINGS (from last session) ===
281
+ ...
282
+
283
+ === ACCEPTANCE CRITERIA (frozen — the architect re-runs these to judge; verify
284
+ against them, do not edit or work around) ===
285
+ ...
286
+ ```
287
+
288
+ ## Builder-side standing setup (one time per machine/repo)
289
+
290
+ - The builder is the same `claude` binary as the architect, one tier down —
291
+ nothing extra to install. `architect dispatch` pins the model per dispatch
292
+ (`--model claude-sonnet-4-6`); a `~/.claude/settings.json` `"model"` default
293
+ is fine interactively, but automations pin it explicitly so a default can't
294
+ silently swap the builder.
295
+ - Repo `CLAUDE.md` is the builder's standing context — Claude Code loads it
296
+ root-down automatically. Put exact build/test commands and repo gotchas there;
297
+ the loop's PHASE rules stay in the dispatch block so they version with the
298
+ skill. (Claude Code does **not** auto-read `AGENTS.md`; if the repo keeps its
299
+ build/test docs there, add `@AGENTS.md` to `CLAUDE.md` to pull it in.)
300
+ - The builder is a bare `claude -p` over the block — it is not invoking the
301
+ `/architect` skills, the block is its entire instruction set. (`--bare` would
302
+ give a leaner builder context but also drops `CLAUDE.md`/skills/hooks — keep
303
+ `CLAUDE.md`, so skip `--bare` unless the repo has no standing build/test doc.)
304
+ - Billing: headless `claude -p` draws on the Agent SDK credit pool on your
305
+ Claude plan (separate from interactive usage limits since June 15 2026).
306
+ There's no per-window quota that dies mid-run the way a chat session can, but
307
+ a long parallel fan-out does spend that pool. The architect runs as your
308
+ interactive Claude Code session.