space-architect 1.2.0 β†’ 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62235ba54045a8883eaaaced2fef7c231d45ad6cb363dda9256ec65692b6023b
4
- data.tar.gz: 7d90b91f3a247c20cc273c332807c65c8e500dc62bffaec1a35076263eb969a2
3
+ metadata.gz: db24aa20a68fdf981176f7e51a46794a4fc2ec5cef9765c33de5832f0a314a9e
4
+ data.tar.gz: 8912085239c76c1228e01d8986d789ba0fde42b4517459830c1f08cdb6e0fcfc
5
5
  SHA512:
6
- metadata.gz: 042c966a4dbf2075abaeaffb23ad9e426a4421ffcd9621ff238d2f074771e5d65bc7030775fe1733dde40030dc0aff37b84c35e13a035ac29705e3e42667c96e
7
- data.tar.gz: f633823970cefde990131c1cce4a415bd8f767030120438ae7bd76220653ab0c42580352de48ab2c34b82f5fd4cc597c6ba14410603e66de6a3dd86f89e197ee
6
+ metadata.gz: 06a4e3382403542421679272136d6c1f6a99ac5dece354b5175f5d895b1afb9cce902f9e11ea2cf64c940dd4a00f11d3dfa7390a0941f387ae4a28f47cdbc3fb
7
+ data.tar.gz: 73c71c080f640540c4cfb57f347f12eae5a2486c45a373a525c44dc35ea54edf7b43ee415d979352f6569406f0f261e8d4a601af869eae5bd9f9055df02d9807
data/README.md CHANGED
@@ -69,6 +69,7 @@ architect space status done # mark the current mission comp
69
69
  **Architect Loop (run from inside a space):**
70
70
 
71
71
  ```sh
72
+ architect install-skills # install skills for your harness (once per machine)
72
73
  architect init # scaffold ARCHITECT.md + architecture/
73
74
  architect new <iteration> # scaffold next iteration file
74
75
  architect dispatch <iteration> <lane> # dispatch a builder for a lane
@@ -77,6 +78,14 @@ architect freeze <iteration> # freeze Acceptance Criteria
77
78
  architect verify <iteration> # post-flight mechanical checks
78
79
  ```
79
80
 
81
+ `architect install-skills` installs the bundled `architect`, `architect-research`,
82
+ and `architect-vocabulary` skills for a harness. (`architect-vocabulary` loads the
83
+ system's terms and a short orientation when you're in a space but don't want to run
84
+ the loop β€” see [The Architect Loop](#the-architect-loop-).) Default is `claude`
85
+ (`~/.claude/skills/`); use `--provider
86
+ opencode|codex|pi` for other harnesses, and `--project` to install into the current
87
+ directory instead of globally. See the [command reference](docs/reference.md) for details.
88
+
80
89
  ## Usage πŸ›°οΈ
81
90
 
82
91
  ```sh
@@ -348,6 +348,31 @@ module SpaceArchitect
348
348
  end
349
349
  end
350
350
 
351
+ class InstallSkills < Dry::CLI::Command
352
+ include GlobalOptions
353
+ include Helpers
354
+
355
+ desc "Install bundled skills (architect, architect-research, architect-vocabulary) for a harness"
356
+ option :provider, default: "claude", desc: "Harness: claude, codex, opencode, pi"
357
+ option :project, type: :boolean, default: false, desc: "Install to CWD instead of global"
358
+ option :force, type: :boolean, default: false, desc: "Overwrite existing skills that differ"
359
+ option :dry_run, type: :boolean, default: false, desc: "Print what would happen without writing files"
360
+
361
+ def call(provider: "claude", project: false, force: false, dry_run: false, **opts)
362
+ setup_terminal(**opts.slice(:color, :colors))
363
+ handle_errors do
364
+ result = SkillInstaller.install(provider, project: project, force: force,
365
+ env: project_config.env, dry_run: dry_run)
366
+ verb = dry_run ? "Would install" : "Installed"
367
+ terminal.say "#{verb} skills for #{provider} β†’ #{terminal.path(result[:dest_root])}"
368
+ result[:skills].each do |s|
369
+ terminal.say " #{s[:name]}: #{terminal.style_skill_action(s[:action])} (#{terminal.path(s[:path])})"
370
+ end
371
+ CLI.record_outcome(Outcome.new(exit_code: 0))
372
+ end
373
+ end
374
+ end
375
+
351
376
  module Brief
352
377
  class New < Dry::CLI::Command
353
378
  include GlobalOptions
@@ -559,6 +584,7 @@ SpaceArchitect::CLI::Registry.register "evidence", SpaceArchitect::CLI::Archite
559
584
  SpaceArchitect::CLI::Registry.register "merge", SpaceArchitect::CLI::Architect::Merge
560
585
  SpaceArchitect::CLI::Registry.register "integrate", SpaceArchitect::CLI::Architect::Integrate
561
586
  SpaceArchitect::CLI::Registry.register "gate", SpaceArchitect::CLI::Architect::Gate
587
+ SpaceArchitect::CLI::Registry.register "install-skills", SpaceArchitect::CLI::Architect::InstallSkills
562
588
  SpaceArchitect::CLI::Registry.register "brief" do |b|
563
589
  b.register "new", SpaceArchitect::CLI::Architect::Brief::New
564
590
  end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "pathname"
5
+
6
+ module SpaceArchitect
7
+ module SkillInstaller
8
+ PROVIDERS = %w[claude codex opencode pi].freeze
9
+
10
+ class << self
11
+ def source_root
12
+ Pathname.new(__dir__).parent.parent.join("skill")
13
+ end
14
+
15
+ def dest_root(provider, project:, env:, cwd: Dir.pwd)
16
+ case provider.to_s
17
+ when "claude"
18
+ base = project ? Pathname.new(cwd) : Pathname.new(XDG.home(env: env))
19
+ base.join(".claude", "skills")
20
+ when "codex"
21
+ base = project ? Pathname.new(cwd) : Pathname.new(XDG.home(env: env))
22
+ base.join(".agents", "skills")
23
+ when "opencode"
24
+ project ? Pathname.new(cwd).join(".opencode", "skills") : XDG.config_home(env: env).join("skills")
25
+ when "pi"
26
+ base = project ? Pathname.new(cwd) : Pathname.new(pi_agent_dir(env: env))
27
+ base.join("skills")
28
+ else
29
+ raise Error, "Unknown provider '#{provider}'. Expected one of: #{PROVIDERS.join(', ')}"
30
+ end
31
+ end
32
+
33
+ def install(provider, project:, force:, env:, cwd: Dir.pwd, dry_run: false)
34
+ validate_provider!(provider)
35
+ dest = dest_root(provider, project: project, env: env, cwd: cwd)
36
+ results = []
37
+
38
+ source_skills.each do |skill_dir|
39
+ name = skill_dir.basename.to_s
40
+ skill_dest = dest.join(name)
41
+ results << install_skill(skill_dir, skill_dest, force: force, dry_run: dry_run)
42
+ end
43
+
44
+ { dest_root: dest, skills: results, dry_run: dry_run }
45
+ end
46
+
47
+ def source_skills
48
+ source_root.children.select(&:directory?)
49
+ end
50
+
51
+ private
52
+
53
+ def validate_provider!(provider)
54
+ return if PROVIDERS.include?(provider.to_s)
55
+
56
+ raise Error, "Unknown provider '#{provider}'. Expected one of: #{PROVIDERS.join(', ')}"
57
+ end
58
+
59
+ def pi_agent_dir(env:)
60
+ Pathname.new(env.fetch("PI_CODING_AGENT_DIR", File.join(XDG.home(env: env), ".pi", "agent")))
61
+ end
62
+
63
+ def install_skill(source, dest, force:, dry_run:)
64
+ name = source.basename.to_s
65
+
66
+ if dest.exist?
67
+ if same_content?(source, dest)
68
+ return { name: name, action: :unchanged, path: dest }
69
+ end
70
+
71
+ unless force
72
+ return { name: name, action: :conflict, path: dest } if dry_run
73
+
74
+ raise Error,
75
+ "Refusing to overwrite existing skill at #{dest}. Re-run with --force."
76
+ end
77
+
78
+ unless dry_run
79
+ FileUtils.rm_rf(dest)
80
+ FileUtils.cp_r(source, dest)
81
+ end
82
+ { name: name, action: dry_run ? :would_update : :updated, path: dest }
83
+ else
84
+ unless dry_run
85
+ FileUtils.mkdir_p(dest.parent)
86
+ FileUtils.cp_r(source, dest)
87
+ end
88
+ { name: name, action: dry_run ? :would_install : :installed, path: dest }
89
+ end
90
+ end
91
+
92
+ def same_content?(source, dest)
93
+ return false unless dest.directory?
94
+
95
+ source_files = Dir.glob("#{source}/**/*").reject { |f| File.directory?(f) }
96
+ dest_files = Dir.glob("#{dest}/**/*").reject { |f| File.directory?(f) }
97
+
98
+ return false if source_files.length != dest_files.length
99
+
100
+ source_files.sort.zip(dest_files.sort).all? do |sf, df|
101
+ rel = sf.sub("#{source}/", "")
102
+ df.end_with?(rel) && File.read(sf) == File.read(df)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -74,6 +74,21 @@ module SpaceArchitect
74
74
  end.wait
75
75
  end
76
76
 
77
+ def style_skill_action(action)
78
+ case action.to_s
79
+ when "installed", "updated"
80
+ pastel.green(action)
81
+ when "would_install", "would_update"
82
+ pastel.cyan(action)
83
+ when "unchanged"
84
+ pastel.bright_black(action)
85
+ when "conflict"
86
+ pastel.yellow(action)
87
+ else
88
+ action.to_s
89
+ end
90
+ end
91
+
77
92
  private
78
93
 
79
94
  def color_mode
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SpaceArchitect
4
- VERSION = "1.2.0"
4
+ VERSION = "1.3.0"
5
5
  end
@@ -19,6 +19,7 @@ require_relative "space_architect/git_client"
19
19
  require_relative "space_architect/mise_client"
20
20
  require_relative "space_architect/space_store"
21
21
  require_relative "space_architect/shell_integration"
22
+ require_relative "space_architect/skill_installer"
22
23
  require_relative "space_architect/terminal"
23
24
  require_relative "space_architect/harness"
24
25
  require_relative "space_architect/dispatcher"
@@ -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" org/repo …`
130
+ (repos are variadic positionals 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.