space-architect 1.3.0 → 2.0.0.rc2

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +103 -0
  3. data/README.md +267 -158
  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 → architect_project.rb} +475 -125
  8. data/lib/space_architect/cli/architect.rb +248 -178
  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/gate_evaluator.rb +65 -0
  15. data/lib/space_architect/gate_lint.rb +140 -0
  16. data/lib/space_architect/harness.rb +145 -17
  17. data/lib/space_architect/research/mux.rb +127 -0
  18. data/lib/space_architect/research/registry.rb +70 -0
  19. data/lib/space_architect/research/renderer.rb +101 -0
  20. data/lib/space_architect/research/run.rb +7 -0
  21. data/lib/space_architect/research/supervisor.rb +108 -0
  22. data/lib/space_architect/research.rb +13 -0
  23. data/lib/space_architect/run_creator.rb +53 -0
  24. data/lib/space_architect/skill_installer.rb +81 -79
  25. data/lib/space_architect/templates/architect.md.erb +15 -4
  26. data/lib/space_architect/templates/brief.md.erb +5 -5
  27. data/lib/space_architect/templates/iteration.md.erb +17 -6
  28. data/lib/space_architect.rb +8 -21
  29. data/lib/{space_architect → space_core}/atomic_write.rb +1 -1
  30. data/lib/space_core/cli/base_command.rb +19 -0
  31. data/lib/space_core/cli/build.rb +27 -0
  32. data/lib/space_core/cli/config.rb +49 -0
  33. data/lib/space_core/cli/current.rb +16 -0
  34. data/lib/space_core/cli/help.rb +123 -0
  35. data/lib/space_core/cli/helpers.rb +115 -0
  36. data/lib/space_core/cli/init.rb +29 -0
  37. data/lib/space_core/cli/list.rb +24 -0
  38. data/lib/space_core/cli/new.rb +38 -0
  39. data/lib/space_core/cli/pack.rb +29 -0
  40. data/lib/space_core/cli/path.rb +16 -0
  41. data/lib/space_core/cli/repeatable_options.rb +75 -0
  42. data/lib/space_core/cli/repo.rb +76 -0
  43. data/lib/space_core/cli/run.rb +29 -0
  44. data/lib/space_core/cli/shell.rb +125 -0
  45. data/lib/space_core/cli/show.rb +21 -0
  46. data/lib/space_core/cli/status.rb +33 -0
  47. data/lib/space_core/cli/use.rb +17 -0
  48. data/lib/space_core/cli.rb +177 -0
  49. data/lib/{space_architect → space_core}/config.rb +1 -1
  50. data/lib/{space_architect → space_core}/errors.rb +1 -1
  51. data/lib/{space_architect → space_core}/git_client.rb +1 -1
  52. data/lib/{space_architect → space_core}/mise_client.rb +1 -1
  53. data/lib/space_core/oci_builder.rb +56 -0
  54. data/lib/space_core/oci_packer.rb +99 -0
  55. data/lib/space_core/oci_runner.rb +73 -0
  56. data/lib/{space_architect → space_core}/repo_reference.rb +1 -1
  57. data/lib/{space_architect → space_core}/repo_resolver.rb +1 -1
  58. data/lib/{space_architect → space_core}/shell_integration.rb +1 -1
  59. data/lib/{space_architect → space_core}/slugger.rb +1 -1
  60. data/lib/{space_architect → space_core}/space.rb +11 -3
  61. data/lib/{space_architect → space_core}/space_store.rb +13 -13
  62. data/lib/{space_architect → space_core}/state.rb +1 -1
  63. data/lib/space_core/templates/oci/dockerfile.erb +63 -0
  64. data/lib/space_core/templates/oci/dockerignore.erb +17 -0
  65. data/lib/space_core/templates/oci/entrypoint.sh.erb +10 -0
  66. data/lib/{space_architect → space_core}/terminal.rb +1 -1
  67. data/lib/space_core/version.rb +7 -0
  68. data/lib/{space_architect → space_core}/warnings.rb +1 -1
  69. data/lib/{space_architect → space_core}/xdg.rb +1 -1
  70. data/lib/space_core.rb +24 -0
  71. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/clone.rb +5 -5
  72. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/config.rb +7 -7
  73. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/daemon.rb +46 -30
  74. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/options.rb +1 -1
  75. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/org.rb +9 -9
  76. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/repo.rb +9 -9
  77. data/lib/space_src/cli/shell.rb +122 -0
  78. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/status.rb +7 -7
  79. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/sync.rb +17 -17
  80. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli.rb +42 -11
  81. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cloner.rb +3 -3
  82. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/contract.rb +1 -1
  83. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/duration.rb +1 -1
  84. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/model.rb +1 -1
  85. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/store.rb +5 -5
  86. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/forge/client.rb +2 -2
  87. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/forge/github.rb +4 -4
  88. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/launchd/agent.rb +5 -5
  89. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/launchd/plist.rb +3 -3
  90. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/log_rotator.rb +1 -1
  91. data/lib/space_src/migration.rb +43 -0
  92. data/lib/space_src/nav.rb +98 -0
  93. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/paths.rb +2 -2
  94. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/scm/client.rb +1 -1
  95. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/scm/git.rb +4 -4
  96. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/scm/status.rb +1 -1
  97. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/shell.rb +1 -1
  98. data/lib/space_src/shell_integration.rb +321 -0
  99. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/state/lock.rb +1 -1
  100. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/state/store.rb +2 -2
  101. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/sync/engine.rb +12 -12
  102. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/sync/repo_plan.rb +3 -3
  103. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/interactive_reporter.rb +1 -1
  104. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/json_reporter.rb +1 -1
  105. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/mode.rb +1 -1
  106. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/plain_reporter.rb +1 -1
  107. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/reporter.rb +1 -1
  108. data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/version.rb +2 -2
  109. data/lib/space_src.rb +37 -0
  110. data/skill/architect/SKILL.md +110 -54
  111. data/skill/architect/dispatch.md +147 -39
  112. data/skill/architect/research.md +46 -37
  113. data/skill/architect-research/SKILL.md +2 -2
  114. data/skill/architect-vocabulary/SKILL.md +24 -21
  115. metadata +127 -68
  116. data/lib/space_architect/cli/config.rb +0 -61
  117. data/lib/space_architect/cli/current.rb +0 -22
  118. data/lib/space_architect/cli/helpers.rb +0 -117
  119. data/lib/space_architect/cli/init.rb +0 -35
  120. data/lib/space_architect/cli/list.rb +0 -30
  121. data/lib/space_architect/cli/new.rb +0 -43
  122. data/lib/space_architect/cli/options.rb +0 -12
  123. data/lib/space_architect/cli/path.rb +0 -22
  124. data/lib/space_architect/cli/repo.rb +0 -88
  125. data/lib/space_architect/cli/shell.rb +0 -137
  126. data/lib/space_architect/cli/show.rb +0 -27
  127. data/lib/space_architect/cli/status.rb +0 -39
  128. data/lib/space_architect/cli/use.rb +0 -23
  129. data/lib/space_architect/version.rb +0 -5
  130. data/vendor/repo-tender/lib/space_architect/pristine.rb +0 -44
@@ -1,25 +1,28 @@
1
1
  ---
2
2
  name: architect
3
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.
4
+ Run the Architect Loop: a strong reasoning model (or a human) is the ARCHITECT
5
+ — judgment only: arbitration, judging raw evidence against frozen Acceptance
6
+ Criteria, splitting iterations into disjoint lanes, kill/continue calls. The
7
+ BUILDERS are 1-4 parallel cheaper agents run headless (reference harness:
8
+ `claude -p`), each in its own git worktree; the architect reviews, merges, and
9
+ integrates their work.
9
10
  The space is the memory: one file per iteration at
10
11
  architecture/I<NN>-<name>.md (Grounds / Specification / Acceptance Criteria /
11
12
  Builder Prompt / Builder Report / Verdict), indexed by
12
- architecture/ARCHITECT.md; a mission spans the repos under repos/. Use when
13
+ architecture/ARCHITECT.md; a project spans the repos under repos/. Use when
13
14
  asked to "architect", "run the loop", "next iteration", "judge the builder's
14
15
  work", or at the start of a work block in a space using the handoff system.
15
16
  ---
16
17
 
17
18
  # Architect
18
19
 
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/`.
20
+ You are the ARCHITECT the judgment role: a strong reasoning model (or a human),
21
+ run interactively. The BUILDER is a cheaper model run headless (reference
22
+ harness: `claude -p`), one or more per iteration — the models filling both roles
23
+ are an operator choice (see `docs/DESIGN.md` §1–§2), not fixed. The space is the
24
+ memory — project artifacts live in the space's `architecture/` dir (committed),
25
+ scratch in `build/` (gitignored); the project spans the repos under `repos/`.
23
26
  Your output is judgment and a dispatch — never implementation code. When you
24
27
  have enough information to act, act.
25
28
 
@@ -33,7 +36,7 @@ change guarantees, so there are no separate `gates/`, `lanes/`, or `prd/` dirs:
33
36
  |---|---|---|
34
37
  | **Grounds** | why — research/brief distilled (optional) | `architect section <it> grounds --from <f>` |
35
38
  | **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** |
39
+ | **Acceptance Criteria** | proof — prose conditions (AC1, AC2, …) + fenced ` ```gates ` block of runnable checks | `architect freeze <it>` ❄️ **= the freeze** |
37
40
  | **Builder Prompt** | the exact lane-prompt(s) dispatched | `architect section <it> prompt --append --lane <l> --from <f>` |
38
41
  | **Builder Report** | raw evidence, transcribed verbatim from scratch | `architect evidence <it> --lane <l>` |
39
42
  | **Verdict** | rulings + per-AC PASS/FAIL/INVALID + KILL/CONTINUE | `architect section <it> verdict --from <f>` (later session) |
@@ -53,19 +56,21 @@ report in `build/<id>-<lane>/report.md`; `architect evidence` transcribes it
53
56
  commit — `architect section` refuses to write a frozen section once frozen; only
54
57
  Builder Prompt, Builder Report, and Verdict are appended after.
55
58
 
56
- **The mission brief (`architecture/BRIEF.md`).** A mission with a durable spec
59
+ **The project brief (`architecture/BRIEF.md`).** A project with a durable spec
57
60
  carries one brief — numbered §sections (§1 goal, §2 constraints, … §N definition
58
61
  of done) that span iterations. Every iteration's Grounds/Specification/Acceptance
59
62
  Criteria/Verdict cites it as **BRIEF §N** (e.g. `(BRIEF §3.1)`), the way each gate
60
63
  addresses its intent back to one frozen reference: the Acceptance Criteria table
61
64
  carries a `Brief §` column, the Specification Objective cites it, the Verdict
62
65
  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
66
+ The brief is frozen at the project level — edits to a §section are logged
67
+ decisions in `ARCHITECT.md`, never silent per-iteration drift. Discovery projects
65
68
  that are still finding their shape defer the brief, cite per-iteration Grounds,
66
69
  and promote the consolidated picture into BRIEF.md once it stabilizes.
67
70
 
68
- Full rationale and citations: `DESIGN.md` in this skill's repo. Exact dispatch
71
+ Full rationale and citations: `docs/DESIGN.md` in this skill's repo the
72
+ source-backed "why" behind these rules (the **R**-numbers and **§**-numbers cited
73
+ throughout this skill point into it). Exact dispatch
69
74
  commands and the lane-prompt template: `dispatch.md` next to this file. To load
70
75
  this system's vocabulary without running the loop (e.g. when working *on* the
71
76
  skill), invoke the `/architect-vocabulary` skill — it is the glossary, not the
@@ -114,20 +119,20 @@ loop.
114
119
  `AGENTS.md` → `README.md` → architecture docs. Learn the exact verification
115
120
  gate (test/lint/typecheck/build commands) from docs or CI config.
116
121
  - Once per environment: `claude --version` and confirm the builder model
117
- resolves (`echo ok | claude -p --model claude-sonnet-4-6 --max-turns 1`;
122
+ resolves (`echo ok | claude -p --model <builder-model> --max-turns 1`;
118
123
  details in `dispatch.md`). First dispatch in a new environment is a canary —
119
124
  confirm it starts cleanly before fanning out.
120
125
  - Read `architecture/ARCHITECT.md` (the cross-iteration table of contents),
121
- `architecture/BRIEF.md` if present (the durable §-numbered mission contract you
126
+ `architecture/BRIEF.md` if present (the durable §-numbered project contract you
122
127
  cite as BRIEF §N), and the iteration file `architecture/I<NN>-<name>.md` for any
123
128
  in-flight iteration. If `ARCHITECT.md` is missing, run `architect init` (scaffolds
124
- `architecture/ARCHITECT.md` and the `architect:` block in `space.yaml`,
129
+ `architecture/ARCHITECT.md` and the `project:` block in `space.yaml`,
125
130
  commits). Keep the handoff a short TOC (~150 lines): TL;DR + repos in scope +
126
131
  an iteration index pointing at each iteration file; per-iteration detail lives
127
132
  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" org/repo …`
130
- (repos are variadic positionals after the title), then `architect init` inside
133
+ prints project state (iterations, freeze_shas, lanes, verdicts) at any point.
134
+ - **Space setup (first time):** `architect space new "Project Name" -r org/repo -r …`
135
+ (each repo is a repeatable `-r` flag after the title), then `architect init` inside
131
136
  the space to scaffold `architecture/ARCHITECT.md`.
132
137
  - Scale to the task: trivial fixes don't need the loop — say so and let the
133
138
  human do it inline or in a normal session. The loop is for iteration-sized
@@ -166,11 +171,13 @@ re-derivation — the simplification that re-sees the shape is often the
166
171
  architect's or human's to name.) Then
167
172
  one iteration-level call: **KILL / CONTINUE**, with the single decisive reason,
168
173
  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
+ (schema/API/persistence/security), add a review before the verdict. The
175
+ architect reading the diff is already a stronger-model, fresh-context pass over
176
+ the builder's work — a capability-gap read whose independence depends on the
177
+ pairing: a same-lab architect/builder shares the builder's blind spots (so the
178
+ frozen gates stay the independent check), while a cross-vendor pairing is more
179
+ independent (see `docs/DESIGN.md` §1/R3). For an extra adversarial pass, pipe the
180
+ diff to a fresh read-only `claude -p` reviewer (command in `dispatch.md`) or a
174
181
  fresh-context subagent prompted to break confidence — calibrated to flag only
175
182
  correctness/requirement/invariant gaps with file:line evidence, no style.
176
183
 
@@ -194,7 +201,7 @@ Two scales, two routes:
194
201
  researcher maps the topic, the orchestrator designs topic-specific parallel
195
202
  researcher lanes, claims verified against sources, synthesized into a cited
196
203
  report). Its report then distills into `architecture/BRIEF.md` §sections when
197
- it is mission-scope (a durable contract that spans iterations), or the
204
+ it is project-scope (a durable contract that spans iterations), or the
198
205
  iteration's **Grounds** section when it is iteration-scope.
199
206
  - **Iteration scale** — run the inline fan-out below only when at least one
200
207
  trigger holds: (a) the iteration depends on external APIs, libraries, or
@@ -214,8 +221,13 @@ and write Grounds. Findings without a source URL don't enter Grounds.
214
221
  ### 4. Spec the next iteration
215
222
 
216
223
  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
224
+ `architecture/I<NN>-<name>.md` (it allocates the next ordinal **at spec-time** and records the
225
+ iteration in `space.yaml`). The iteration index in `ARCHITECT.md` holds only scaffolded
226
+ iterations — planned/queued work lives un-numbered in the ordered Backlog until it is
227
+ about to be specced. Pre-numbering planned work forces renumber churn every time priorities
228
+ reshuffle; the ordinal belongs to the work only once `architect new` is called.
229
+
230
+ Then write the **Specification** section with
219
231
  `architect section <name> specification --from <file>` — the full delegation
220
232
  contract, self-contained:
221
233
 
@@ -236,22 +248,47 @@ contract, self-contained:
236
248
  repos are inherently disjoint; same-repo lanes with any file overlap run as
237
249
  one. Each lane gets its own objective, output format, and boundaries. Most
238
250
  iterations are one lane — fan out only when the work is genuinely parallel (a
239
- cross-repo mission often is).
251
+ cross-repo project often is). Two first-class patterns — runnable recipes in `dispatch.md`: **parallel +
252
+ fast-follow** (disjoint lanes integrate first; a fast-follow lane off
253
+ `project/<slug>` carries the seam — see `### Parallel + fast-follow`) and
254
+ **serial deferred judgment** (iterations run to gates-green with `architect
255
+ verdict` withheld; one later batch session judges each against its own frozen
256
+ AC — see `### Serial deferred judgment`).
240
257
  - **Effort call** — thinking budget set in the lane-prompt via the escalation
241
258
  keywords (`think hard` … `ultrathink`); default unattended builder work high,
242
259
  downgrade a routine, tightly-specified lane (record which and why). Claude
243
260
  Code has no per-invocation effort flag — see `dispatch.md`.
244
261
 
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.
262
+ **Spike (probe) iterations.** When the open question is too uncertain for a
263
+ build the repo can't answer it and routine API-verification won't resolve it
264
+ spec a *spike* (probe) instead of a build iteration. A spike is
265
+ investigate-only: its deliverable is a **recommendation**, not merged behavior.
266
+ Its lane reads, experiments in throwaway scratch (never the worktree), and
267
+ writes a structured recommendation to its scratch report; there is usually
268
+ nothing to integrate. Acceptance Criteria are **read-bound** gates are
269
+ minimal (at most suite-green confirming the probe broke nothing), because the
270
+ proof is the architect reading the recommendation against the question the spike
271
+ was set, not a runnable check; the AC names that question. The spike verdict
272
+ uses **ADOPT / REVISE / REJECT** (not KILL/CONTINUE): the architect transcribes
273
+ the recommendation into Builder Report, then the Verdict records the
274
+ disposition and, if adopted, names the follow-up build iteration it spawns. A
275
+ spike's CONTINUE means "recommendation accepted + disposition recorded." This
276
+ is distinct from discovery-scale research (`/architect-research`, which surveys
277
+ a whole topic): a spike is one iteration-sized, decision-oriented probe run
278
+ through the normal builder/lane machinery.
279
+
280
+ Then write the **Acceptance Criteria** section — prose conditions (AC1, AC2, …)
281
+ that the architect judges against, followed by a fenced ` ```gates ` block of
282
+ runnable checks (each gate carries `id`, `ac`, `cmd`, and `expect`; `cwd` is
283
+ optional) — and run `architect freeze <name>`. What must be frozen before
284
+ dispatch is the Acceptance Criteria: `architect freeze` lints the gates block
285
+ (absent or empty gates is allowed but warns; malformed fails), commits any
286
+ pending content in the frozen region (Grounds/Specification/Acceptance Criteria)
287
+ in one freeze commit, records the `freeze_sha` in `space.yaml`, and prints the
288
+ frozen AC back; **that commit is the freeze** ❄️ and is the last thing before
289
+ dispatch. You needn't sequence Grounds and Specification into separate commits
290
+ first — the freeze snapshots the whole frozen region and refuses to re-freeze
291
+ once a frozen section changed afterward.
255
292
 
256
293
  ### 5. Dispatch (one fresh `claude -p` per lane, worktree-isolated)
257
294
 
@@ -279,14 +316,23 @@ files and writes raw results to `build/<id>-<lane>/report.md` — it never
279
316
  touches `architecture/`, so lanes never collide and the Acceptance Criteria
280
317
  stay untouchable.
281
318
 
282
- Do not block — end the turn or do other judgment work; multi-hour runs are
319
+ Do not block — end the turn or do other judgment work; long runs (30–60 minutes) are
283
320
  normal. Print the lane-prompts too, so the human can run any lane in an
284
321
  interactive `claude` session instead. Whenever you return to a running lane,
285
322
  check liveness: the lane's `run.jsonl` must still be growing. If it has been
286
323
  silent 15+ minutes on one in-flight command, follow "Stall detection and
287
324
  rescue" in `dispatch.md` — kill the stuck child process, not the run.
288
325
 
289
- ### 6. Post-flight and integrate (when the runs complete)
326
+ When all lanes complete, **the dispatch session's job is done** — babysit
327
+ liveness per `dispatch.md` but do not run gates, transcribe evidence, integrate
328
+ lanes, or write the Verdict. Hand off to a fresh judging session (§6).
329
+
330
+ ### 6. Post-flight, judge, and integrate (judging session)
331
+
332
+ A fresh judging session — not the session that dispatched (see §1 and §5) —
333
+ opens with the **MECHANICAL POST-FLIGHT CHECKS** and owns everything through the
334
+ Verdict and integration. Because this session did not dispatch, §1's
335
+ fresh-session-judgment is intact: it is the correct session to evaluate results.
290
336
 
291
337
  `architect verify <iteration>` REPORTS (it never judges) per lane: frozen
292
338
  sections untouched, no builder commits, scratch report present, in-bounds.
@@ -307,20 +353,30 @@ commits it, and echoes the builder's STATUS line. The builder never wrote into
307
353
 
308
354
  **Then integrate** — you decide which lanes pass, the CLI does the git
309
355
  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
356
+ named lane on its branch and merges it `--no-ff` into the stable
357
+ `project/<slug>` branch (slug derived from `space.title`; persistent and shared
358
+ across all iterations), in order; it **refuses** a lane that left builder
312
359
  commits or wrote out-of-bounds, and stops on a merge conflict — which means the
313
360
  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.
361
+ it (never hand-resolve). A cross-repo project yields one `project/<slug>` branch
362
+ per touched repo. `main` is never touched per-iteration `--teardown` deletes
363
+ only the per-lane `lane/<iteration>-<lane>` branches and worktrees, never the
364
+ project branch. Update the iteration index in `architecture/ARCHITECT.md`
365
+ (recording the `project/<slug>` branch), remove the worktrees (`architect
366
+ integrate … --teardown`, or `architect worktree remove <iteration> <lane>`), and
367
+ commit the space.
368
+
369
+ **Run the frozen gates cold** `architect gate <iteration>` runs the frozen
370
+ gate commands against the integration tree and streams raw output (a runner, not
371
+ a judge). Read the output, check the diff against the Specification and the
372
+ cited BRIEF §sections (per §2), then write the **Verdict** (`architect verdict
373
+ <iteration> continue|kill --from <file>`): disagreement rulings, per-AC
374
+ PASS/FAIL/INVALID, the KILL/CONTINUE call.
375
+
376
+ At project end, `architect land` prints the single `gh pr create --base main
377
+ --head project/<slug>` command per touched repo and writes a PR body to
378
+ `build/land/` — no push, no `gh` call; the human runs it from the repo when
379
+ the project is ready to ship.
324
380
 
325
381
  ## Maintenance
326
382
 
@@ -1,12 +1,13 @@
1
1
  # Builder dispatch reference
2
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
3
+ Verified against the `claude` CLI (Claude Code) headless mode the reference
4
+ harness — June 2026. The builder is `claude -p` (`--print`, the non-interactive
5
+ headless mode) pinned to the configured builder model (`<builder-model>`) a
6
+ cheaper model run headless via the same harness the architect uses. Key facts the
7
+ skill encodes: lane-prompts go in on **stdin** (Claude Code has no `@file`, and a
8
+ big quoted lane-prompt as a shell argument gets mangled); the model is pinned with
9
+ `--model <builder-model>` (a floating alias drifts to whatever ships next pin
10
+ the full id); there is **no `-C`/working-dir flag**, so
10
11
  per-lane dispatch `cd`s into the worktree; permissions are the **tool
11
12
  allow/deny lists** (`--allowedTools`/`--disallowedTools`) plus
12
13
  `--permission-mode`, not a sandbox; web access is the built-in
@@ -27,21 +28,22 @@ If a lane committed, treat the worktree as tampered: reset and re-dispatch.
27
28
 
28
29
  **Preflight (once per environment):** run `claude --version`, and confirm the
29
30
  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
+ (`echo ok | claude -p --model <builder-model> --max-turns 1`). No API key —
31
32
  the builder runs on your Claude plan — but note headless `claude -p` draws on
32
33
  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
+ see `docs/DESIGN.md` §4). On the first real dispatch in a new environment, launch
34
35
  ONE canary lane and confirm it starts cleanly before fanning anything out.
35
36
 
36
37
  ## Canonical dispatch — `architect dispatch <iteration> <lane>`
37
38
 
38
39
  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
+ assembles the canonical `claude -p` argv, pins the builder model (the lane's
41
+ configured model or the CLI's reference default; see `docs/DESIGN.md` §4),
40
42
  reads the lane prompt from `build/<id>-<lane>/prompt.md` on stdin, and streams
41
43
  `--output-format stream-json --verbose` output to
42
44
  `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
+ call** (`run_in_background`) so your turn doesn't block for the full run (30–60
46
+ minutes is typical).
45
47
 
46
48
  Write the lane's prompt to `build/<id>-<lane>/prompt.md` first (never pass a
47
49
  big prompt as a shell argument — shells mangle quotes), then:
@@ -72,7 +74,7 @@ reaps those now-orphaned `claude` processes, and every lane dies at once with no
72
74
  `result` — partial diffs, no reports (this exact failure has happened: three
73
75
  lanes killed at the same second, zero output). One blocking dispatch per
74
76
  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.
77
+ survives the full run and reports completion per lane.
76
78
 
77
79
  ### What the tool runs under the hood
78
80
 
@@ -82,7 +84,7 @@ and as the manual fallback:
82
84
  ```bash
83
85
  # write prompt to build/<id>-<lane>/prompt.md first, then:
84
86
  ( cd build/<id>-<lane>/wt && \
85
- claude -p --model claude-sonnet-4-6 \
87
+ claude -p --model <builder-model> \
86
88
  --permission-mode acceptEdits \
87
89
  --allowedTools 'Read,Edit,Write,Grep,Glob,Bash,WebSearch,WebFetch' \
88
90
  --disallowedTools 'Bash(git commit:*),Bash(git push:*),Bash(git reset:*),Bash(git merge:*),Bash(git rebase:*),Bash(git checkout:*),Bash(git branch:*)' \
@@ -100,48 +102,153 @@ over the allow list (deny always takes precedence) as the runtime first line
100
102
  against commits. Redirect stderr (`2>&1`) into the run-log so a dispatch error
101
103
  lands somewhere instead of vanishing.
102
104
 
103
- ### Integration (architect-only, after per-lane post-flight passes)
105
+ ### Integration (judging session — after per-lane post-flight passes)
104
106
 
105
- You decide which lanes pass; the CLI does the git mechanics. Canonical path:
107
+ This block runs in the judging session, not the dispatch session the dispatch
108
+ session's job ends when builders finish (see SKILL.md §5–6). You decide which
109
+ lanes pass; the CLI does the git mechanics. Canonical path:
106
110
 
107
111
  ```bash
108
112
  architect integrate <iteration> --lanes <passing-set> # e.g. --lanes lane-a,lane-b
109
113
  architect gate <iteration> # integration smoke (raw output; verdict stays yours)
110
114
  architect integrate <iteration> --lanes <passing-set> --teardown # or remove worktrees + lane branches after
115
+ architect land # end of project: prints gh pr create --base main --head project/<slug>
111
116
  ```
112
117
 
113
118
  `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.
119
+ `--no-ff` into the repo's stable `project/<slug>` branch (slug of `space.title`,
120
+ persistent across all iterations), in order. It **refuses** a lane that left
121
+ builder commits or wrote out-of-bounds (the mechanical post-flight checks), and
122
+ aborts on a merge conflict. A merge conflict = the lane plan wasn't disjoint = a
123
+ spec defect: kill the conflicting lane and re-spec; don't hand-resolve builder
124
+ conflicts. It runs **no gates and makes no verdict** — `architect gate` streams
125
+ the raw gate output for you to judge. `--teardown` deletes only the per-lane
126
+ `lane/<iteration>-<lane>` branches and worktrees; it never deletes the
127
+ `project/<slug>` branch.
120
128
 
121
129
  Under the hood / manual fallback (one lane shown):
122
130
 
123
131
  ```bash
124
- git -C repos/<repo> checkout -b lane/<iteration> <repo-base>
132
+ # check out or create the project integration branch:
133
+ git -C repos/<repo> checkout project/<slug> 2>/dev/null || \
134
+ git -C repos/<repo> checkout -b project/<slug> <repo-base>
125
135
  git -C build/<id>-<lane>/wt add -A
126
136
  git -C build/<id>-<lane>/wt commit -m "lane <lane>: <what>"
127
137
  git -C repos/<repo> merge --no-ff lane/<iteration>-<lane>
128
138
  <run the gate commands> # integration smoke after every merge
129
139
  architect worktree remove <iteration> <lane>
130
140
  git -C repos/<repo> branch -d lane/<iteration>-<lane>
141
+ # at project end:
142
+ architect land # prints gh pr create --base main --head project/<slug>
131
143
  ```
132
144
 
145
+ ### Parallel + fast-follow
146
+
147
+ Use when an iteration is near-disjoint — all but a thin shared seam (a
148
+ registration line, an index entry, a shared require). Route the seam into a
149
+ dedicated fast-follow lane; the parallel lanes stay genuinely disjoint and
150
+ integrate without conflict.
151
+
152
+ **Recipe:**
153
+
154
+ 1. **Spec the seam out of the parallel lanes.** Assign the seam file(s) to the
155
+ fast-follow lane's `--touch` set and exclude them from every parallel lane's
156
+ touch-set — so the parallel set is disjoint by construction.
157
+
158
+ 2. **Create worktrees and dispatch the parallel lanes** (off the repo base):
159
+ ```bash
160
+ architect worktree add <repo> <iteration> lane-a
161
+ architect worktree add <repo> <iteration> lane-b
162
+ architect dispatch <iteration> lane-a # own background Bash call each
163
+ architect dispatch <iteration> lane-b
164
+ ```
165
+
166
+ 3. **Judging session — integrate the parallel set.** `project/<slug>` advances
167
+ to their merged tip:
168
+ ```bash
169
+ architect integrate <iteration> --lanes lane-a,lane-b
170
+ architect gate <iteration>
171
+ ```
172
+
173
+ 4. **Create the fast-follow lane off the integrated tip.** `--base` accepts any
174
+ git ref — passing `project/<slug>` roots the new worktree at the merged tip
175
+ (the keystone move):
176
+ ```bash
177
+ architect worktree add <repo> <iteration> ff --base project/<slug>
178
+ architect dispatch <iteration> ff
179
+ ```
180
+
181
+ 5. **Judging session — integrate the fast-follow lane.** Because it descends
182
+ directly from `project/<slug>`, the `--no-ff` merge appends cleanly with no
183
+ conflicts:
184
+ ```bash
185
+ architect integrate <iteration> --lanes ff
186
+ architect gate <iteration>
187
+ ```
188
+
189
+ **Invariant:** the parallel lanes must stay disjoint — a conflict among them is
190
+ still a disjointness defect (kill and re-spec; never hand-resolve). The
191
+ fast-follow lane is the sanctioned home for the seam and never conflicts because
192
+ it is a descendant of the integrated tip.
193
+
194
+ ### Serial deferred judgment
195
+
196
+ Use when several iterations (or serial same-file lanes within one iteration)
197
+ should run to gates-green without a judging session between each — batching cold
198
+ AC judgment into one later session.
199
+
200
+ **Recipe:**
201
+
202
+ Per iteration, freeze and dispatch as normal. In a fresh judging session, run
203
+ post-flight, integrate, and gate — but **withhold `architect verdict`**:
204
+
205
+ ```bash
206
+ # judging session (per iteration) — stop before verdict:
207
+ architect integrate <iteration> --lanes <passing-set>
208
+ architect gate <iteration>
209
+ # do NOT run: architect verdict <iteration> continue|kill
210
+ ```
211
+
212
+ Each integrated-but-unjudged iteration surfaces as `awaiting-verdict` in
213
+ `architect status`:
214
+
215
+ ```bash
216
+ architect status
217
+ # II Iteration … Verdict
218
+ # 03 some-feature … awaiting-verdict
219
+ # 04 another-feature … awaiting-verdict
220
+ ```
221
+
222
+ One later batch judging session evaluates all `awaiting-verdict` iterations,
223
+ oldest-first. For each: read its own frozen AC from its freeze commit, run its
224
+ gates cold, and record the verdict:
225
+
226
+ ```bash
227
+ architect gate <iteration> # run the frozen gates cold
228
+ architect verdict <iteration> continue # or: kill
229
+ ```
230
+
231
+ **§1 preserved:** each verdict is cold and fresh-session — the batch judging
232
+ session did not dispatch any of these iterations, so the §1
233
+ fresh-session-judgment rule holds for every verdict in the batch.
234
+
235
+ **Deliberate risk:** iteration N+1 integrated on top of N's not-yet-judged work
236
+ rests on a foundation that a later KILL at N would revert. Accept this coupling
237
+ only consciously, and always judge oldest-first so a KILL stops you before you
238
+ compound it.
239
+
133
240
  ## Operating guidance
134
241
 
135
242
  - 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
243
+ completion notification** bring you back (long runs — 30–60 minutes — are normal); read
137
244
  `build/<id>-<lane>/run.jsonl` and the repo state afterwards. Do not write a
138
245
  blocking `while pgrep …; sleep` wait loop as a Bash command — that is itself
139
246
  a launcher that ties up a turn. When you return to a lane, check liveness via
140
247
  run-log growth (the stall rules below still apply unchanged).
141
248
  - 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.
249
+ <builder-model>`). A floating alias (a bare "latest"/tier tag) drifts to
250
+ whatever ships next — fine interactively, but automations pin the full id so a
251
+ model bump can't silently change builder behavior mid-project.
145
252
  - Effort = thinking budget. Claude Code has no per-invocation effort flag the
146
253
  way Codex exposed `model_reasoning_effort`; the builder sets thinking depth
147
254
  **in the block** via the escalation keywords (`think` < `think hard` <
@@ -166,16 +273,17 @@ git -C repos/<repo> branch -d lane/<iteration>-<lane>
166
273
  `claude -p --continue …`, never a `&` loop (a `&` launcher orphans the
167
274
  resumed lanes exactly as it does fresh ones). Never resume across iterations —
168
275
  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:
276
+ - Capability-gap review gate (high-stakes iterations): the architect outranks the
277
+ builder, so the architect reading the diff is already a stronger-model,
278
+ fresh-context pass over it. How independent that read is depends on the pairing
279
+ — a same-lab architect/builder shares the builder's blind spots (the frozen
280
+ gates stay the independent check), a cross-vendor pairing is more independent
281
+ (see `docs/DESIGN.md` §1/R3). For an extra adversarial pass, pipe the
282
+ instruction + diff to a fresh read-only reviewer:
175
283
  ```bash
176
284
  { echo "Review this diff against the spec. Flag ONLY correctness/requirement/invariant gaps with file:line evidence. No style."; \
177
285
  git -C <repo-root> diff <base>...HEAD; } \
178
- | claude -p --model claude-sonnet-4-6 --allowedTools 'Read,Grep,Glob'
286
+ | claude -p --model <builder-model> --allowedTools 'Read,Grep,Glob'
179
287
  ```
180
288
  - `build/` is already gitignored by the space, so no extra `.gitignore` entry
181
289
  is needed. Scratch never reaches the space repo; only `architecture/` is
@@ -287,11 +395,11 @@ against them, do not edit or work around) ===
287
395
 
288
396
  ## Builder-side standing setup (one time per machine/repo)
289
397
 
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.
398
+ - The builder is the same `claude` binary as the architect (reference harness),
399
+ running a cheaper model — nothing extra to install. `architect dispatch` pins
400
+ the model per dispatch (`--model <builder-model>`); a `~/.claude/settings.json`
401
+ `"model"` default is fine interactively, but automations pin it explicitly so a
402
+ default can't silently swap the builder.
295
403
  - Repo `CLAUDE.md` is the builder's standing context — Claude Code loads it
296
404
  root-down automatically. Put exact build/test commands and repo gotchas there;
297
405
  the loop's PHASE rules stay in the dispatch block so they version with the