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
data/README.md CHANGED
@@ -2,12 +2,24 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/space-architect.svg)](https://badge.fury.io/rb/space-architect)
4
4
 
5
- > **Task-scoped workspaces that double as Architect Loop missions — for humans and their agents!** ✨🛰️
5
+ > **Task-scoped workspaces that double as Architect Loop projects — for humans and their agents!** ✨🛰️
6
6
 
7
- `space-architect` is a Ruby CLI for creating and managing **spaces** — task-scoped
8
- project workspaces that hold repos, notes, and artifacts under one obvious
9
- filesystem root — fused with the **Architect Loop**: a structured judgment-and-build
10
- cycle for you and a fleet of headless AI builders. 🌌
7
+ `space-architect` is a Ruby toolkit for **spaces** — task-scoped project
8
+ workspaces that hold repos, notes, and artifacts under one obvious filesystem
9
+ root — fused with the **Architect Loop**: a structured judgment-and-build cycle
10
+ for you and a fleet of headless AI builders. 🌌
11
+
12
+ The gem ships **three composable binaries** over clean library seams:
13
+
14
+ | Binary | What it does | Library |
15
+ |--------|--------------|---------|
16
+ | **`space`** 🪐 | Create and manage task-scoped workspaces | `Space::Core` |
17
+ | **`architect`** 🏗️ | Run the Architect Loop — judgment + headless builders | `Space::Architect` |
18
+ | **`src`** 🌲 | Tend evergreen repo checkouts for copy-on-write provisioning | `Space::Src` |
19
+
20
+ Each is a first-class executable. `architect` also forwards `architect space …`
21
+ and `architect src …` to the other two, so a project can drive everything from
22
+ one command when that's handier. 🎀
11
23
 
12
24
  ## What's a space? 🪐
13
25
 
@@ -15,19 +27,20 @@ A space is just a regular directory with a tiny YAML identity file and room for
15
27
  everything a task needs:
16
28
 
17
29
  ```text
18
- ~/src/spaces/20260531-name-of-space/
30
+ ~/architect/spaces/20260531-name-of-space/
19
31
  space.yaml # identity: id, title, status, repos, notes, tags
20
32
  README.md
21
33
  repos/ # cloned (or copy-on-write'd) repositories
22
34
  notes/ # scratch, prompts, logs
23
- architecture/ # iteration files: I<NN>-<name>.md + ARCHITECT.md index
35
+ architecture/ # iteration files: I<NN>-<name>.md + ARCHITECT.md index + BRIEF.md
24
36
  build/ # lane worktrees + scratch (build/<id>-<lane>/)
25
37
  tmp/ # workspace-local temp — use this instead of /tmp
26
38
  ```
27
39
 
28
- Run a command from anywhere inside a space and it just works — `architect` walks
29
- up from `$PWD` until it finds the nearest `space.yaml`. No "current space" state to
30
- get out of sync; where you *are* is the space you mean. 🧭
40
+ Run a command from anywhere inside a space and it just works — `space` and
41
+ `architect` walk up from `$PWD` until they find the nearest `space.yaml`. No
42
+ "current space" state to get out of sync; where you *are* is the space you
43
+ mean. 🧭
31
44
 
32
45
  ## Installation 📦
33
46
 
@@ -37,8 +50,6 @@ Add it to your `Gemfile`:
37
50
  gem "space-architect"
38
51
  ```
39
52
 
40
- Then:
41
-
42
53
  ```bash
43
54
  bundle install
44
55
  ```
@@ -49,225 +60,323 @@ Or grab it yourself:
49
60
  gem install space-architect
50
61
  ```
51
62
 
52
- The primary executable is `architect`. The gem is `space-architect`. 🎀
53
- A `space` shim is also installed and forwards all arguments to `architect space …`
54
- for convenience.
55
-
56
- ## Quick Start 🎀
63
+ The gem is `space-architect`; it installs three executables — `space`,
64
+ `architect`, and `src`. 🎀
57
65
 
58
- **Space management:**
66
+ ## Quick start 🎀
59
67
 
60
68
  ```sh
61
- architect space init # create XDG config + state files
62
- architect space new "Name of Space" # blast off a new space 🚀
63
- architect space new "Name of Space" org/repo … # with repos cloned in (variadic)
64
- architect space list # see all your spaces
65
- architect space show # show the space you're standing in
66
- architect space status done # mark the current mission complete
69
+ # Spaces
70
+ space init # create XDG config + state files
71
+ space new "Name of Space" # blast off a new space 🚀
72
+ space new "Name of Space" -r org/repo -r org/lib # …with repos cloned in (repeat -r)
73
+ space list # see all your spaces
74
+ space show # show the space you're standing in
75
+
76
+ # Evergreen checkouts (copy-on-write sources for fast provisioning)
77
+ src repo add github.com/example-org/example-app # tend it 🌲
78
+ src sync # one sync pass
79
+ src status # per-repo evergreen status
80
+
81
+ # Architect Loop (run from inside a space)
82
+ architect install-skills # install agent skills (once per machine)
83
+ architect init # scaffold ARCHITECT.md + architecture/
84
+ architect new my-feature # scaffold the next iteration file
85
+ architect freeze my-feature # lock the Acceptance Criteria ❄️
86
+ architect dispatch my-feature lane-a # send a headless builder to work
67
87
  ```
68
88
 
69
- **Architect Loop (run from inside a space):**
89
+ ## `space` task-scoped workspaces 🌌
70
90
 
71
91
  ```sh
72
- architect install-skills # install skills for your harness (once per machine)
73
- architect init # scaffold ARCHITECT.md + architecture/
74
- architect new <iteration> # scaffold next iteration file
75
- architect dispatch <iteration> <lane> # dispatch a builder for a lane
76
- architect status # show mission state (read-only)
77
- architect freeze <iteration> # freeze Acceptance Criteria
78
- architect verify <iteration> # post-flight mechanical checks
92
+ space init
93
+ space new "Name of Space"
94
+ space new "Name of Space" -r org/repo -r example-tools/alpha -r example-tools/beta
95
+ space list # alias: space ls
96
+ space show 20260531-name-of-space
97
+ space path 20260531-name-of-space
98
+ space current # based on $PWD
99
+ space show # based on $PWD
100
+ space status done # based on $PWD
101
+ space status 20260531-name-of-space done
102
+ space config set default_provider github.com
103
+ space config set default_organization example-org
104
+ space repo add example-app # github.com/example-org/example-app
105
+ space repo add example-tools/alpha example-tools/beta
106
+ space repo add gitlab.com/example-org/api
107
+ space repo resolve example-app example-tools/async
108
+ space repo ls # alias: space repos ls
109
+ space use 20260531-name-of-space # records recent state, prints the path
110
+ space ls --color=always # auto | always | never (--colors also accepted)
79
111
  ```
80
112
 
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.
113
+ Repos are passed with a repeatable `-r` flag (`-r org/repo -r org/lib`); the
114
+ comma form (`-r a,b`) works too. Space ids are date-prefixed
115
+ (`20260531-name-of-space`) so they sort naturally, and duplicate names on the
116
+ same day get a counter (`…-name-of-space-2`). 📅
117
+
118
+ Everything `space` does is also reachable as `architect space …` from within a
119
+ project.
120
+
121
+ ## `src` — the evergreen engine 🌲
122
+
123
+ `src` keeps local clones under `<src_dir>/<host>/<owner>/<repo>` (default
124
+ `~/architect/src/…`) clean, on their default branch, and freshly fetched — so
125
+ spaces can provision repos by **copy-on-write** instead of cloning over the
126
+ network.
127
+
128
+ ```sh
129
+ src repo add github.com/example-org/example-app # track + tend a repo
130
+ src org add github.com/example-org # track a whole org
131
+ src sync # run one sync pass (--repo to scope)
132
+ src status # per-repo evergreen status table
133
+ src clone example-app # APFS copy-on-write into $PWD
134
+ src daemon install # per-user launchd agent for background sync
135
+ ```
88
136
 
89
- ## Usage 🛰️
137
+ When `space repo add` finds a matching evergreen checkout, it copy-on-writes
138
+ from it instead of hitting the network — instant provisioning. ⚡ The two
139
+ surfaces share one layout by design, so they line up with zero configuration:
90
140
 
91
141
  ```sh
92
- architect space init
93
- architect space new "Name of Space"
94
- architect space new "Name of Space" org/repo example-tools/alpha example-tools/beta
95
- architect space list
96
- architect space show 20260531-name-of-space
97
- architect space path 20260531-name-of-space
98
- architect space current # based on $PWD
99
- architect space show # based on $PWD
100
- architect space status done # based on $PWD
101
- architect space status 20260531-name-of-space done
102
- architect space config set default_provider github.com
103
- architect space config set default_organization example-org
104
- architect space repo add example-app # github.com/example-org/example-app
105
- architect space repo add example-tools/alpha example-tools/beta
106
- architect space repo add gitlab.com/example-org/api
107
- architect space repo resolve example-app example-tools/async
108
- architect space repo ls
109
- architect space use 20260531-name-of-space # records recent state and prints the path
110
- architect space ls --color=always # auto, always, or never; --colors is also accepted
142
+ src repo add github.com/example-org/example-app # tend it: keep it evergreen 🌲
143
+ space repo add example-app # copies it instantly ⚡
111
144
  ```
112
145
 
113
- Space ids are date-prefixed (`20260531-name-of-space`) so they sort naturally,
114
- and duplicate names on the same day get a counter (`...-name-of-space-2`). 📅
146
+ `src` has its own `--plain` / `--json` output modes for scripting, and its own
147
+ fish integration (`src shell fish install`).
115
148
 
116
- ## The Architect Loop 🏗️
149
+ ## `architect` — the Architect Loop 🏗️
117
150
 
118
- Space Architect ships a structured build cycle for you and headless AI builders
119
- called the **Architect Loop**. Each loop lives inside a space as a *mission*.
151
+ The **Architect Loop** is a structured build cycle for you and headless AI
152
+ builders. Each loop lives inside a space as a *project*.
120
153
 
121
154
  **Roles:**
122
155
 
123
- - **Architect** — you (or Claude Opus 4.8 in judgment mode): arbitrates disagreements,
124
- writes and freezes iteration files, calls kill/continue, merges builder output.
125
- - **Builder** Claude Sonnet 4.6 run headless via `architect dispatch`; reads the
126
- iteration's Builder Prompt from `architecture/`, does the work, writes its report
127
- to `build/<id>-<lane>/`.
156
+ - **Architect** — the judgment role: a strong reasoning model (or you), run
157
+ interactively. Arbitrates disagreements, writes and freezes iteration files,
158
+ calls kill/continue, merges builder output. Never writes implementation code.
159
+ - **Builder** the execution role: a cheaper model run headless via `architect
160
+ dispatch`, one per lane in its own git worktree. Reads the iteration's Builder
161
+ Prompt, does the work, writes raw evidence to `build/<id>-<lane>/report.md`.
162
+ Never grades its own work; never edits `architecture/`.
163
+
164
+ The loop is **model-agnostic** — which models fill the two roles is your choice
165
+ (e.g. a strong Claude model judging a cheaper one on the same plan, or a
166
+ cross-vendor pairing for more independent review). Set it per dispatch with
167
+ `architect dispatch --model …`, or run several pairings head-to-head as a
168
+ **variant set** (`architect variant add`). See
169
+ [docs/DESIGN.md](docs/DESIGN.md) §1–§2 for the reasoning.
128
170
 
129
171
  **Filesystem layout:**
130
172
 
131
173
  ```text
132
174
  architecture/
133
- ARCHITECT.md # cross-iteration index; mission-wide state
134
- I01-<iteration>.md # one file per iteration
135
- I02-<iteration>.md
175
+ ARCHITECT.md # cross-iteration index; project-wide state
176
+ BRIEF.md # durable §-numbered project contract (optional)
177
+ I01-<iteration>.md # one self-contained file per iteration
136
178
  build/
137
179
  I01-<iteration>-<lane>/ # lane worktree + scratch per dispatch
138
180
  run.jsonl # streamed builder output
139
- report.md # builder report (transcribed to iteration file verbatim)
181
+ report.md # builder report (transcribed into the iteration file verbatim)
140
182
  ```
141
183
 
142
- **Iteration file anatomy** (in `architecture/I<NN>-<name>.md`):
184
+ **Iteration file anatomy** one file, grown section by section. You author the
185
+ *content*; the CLI owns the *persistence* (each command writes the section,
186
+ commits it with the canonical message, and prints back what changed):
187
+
188
+ | Section | Holds | How you persist it |
189
+ |---------|-------|--------------------|
190
+ | `## Grounds` | why — research / brief distilled (optional) | `architect section <it> grounds --from <f>` |
191
+ | `## Specification` | what/how — the full delegation contract | `architect section <it> specification --from <f>` |
192
+ | `## Acceptance Criteria` | proof — exact gate commands + thresholds | `architect freeze <it>` ❄️ |
193
+ | `## Builder Prompt` | the exact lane-prompt(s) dispatched | `architect section <it> prompt --append --lane <l> --from <f>` |
194
+ | `## Builder Report` | raw evidence, transcribed verbatim | `architect evidence <it> --lane <l>` |
195
+ | `## Verdict` | rulings + per-AC PASS/FAIL + KILL/CONTINUE | `architect section <it> verdict --from <f>` |
196
+
197
+ **The freeze ❄️** — `architect freeze <iteration>` commits the frozen region
198
+ (Grounds / Specification / Acceptance Criteria), records the `freeze_sha`, and
199
+ prints the frozen Acceptance Criteria back. Any change to those sections
200
+ afterward is an automatic iteration FAIL. The builder never edits the iteration
201
+ file.
202
+
203
+ **Re-grounding 🧭** — `architect init` also scaffolds a `SessionStart` hook that
204
+ runs `architect ground` (emitting `ARCHITECT.md`, `BRIEF.md`, and the in-flight
205
+ iteration) so every fresh session starts oriented — the loop leans on
206
+ fresh-session judgment, and this is what makes picking up cold cheap. Builders
207
+ inside a lane worktree are never grounded.
208
+
209
+ **Command surface:**
143
210
 
144
- | Section | Who writes it | When |
145
- |---------|--------------|------|
146
- | `## Grounds` | Architect | Before dispatch — research, PRD, decisions |
147
- | `## Specification` | Architect | Before dispatch — full delegation contract |
148
- | `## Acceptance Criteria` | Architect | Before `architect freeze` frozen, read-only after |
149
- | `## Builder Prompt` | Architect | Records the exact prompt dispatched |
150
- | `## Builder Report` | Architect | Transcribed verbatim from `build/…/report.md` |
151
- | `## Verdict` | Architect | After reviewing evidence KILL / CONTINUE |
152
-
153
- **Acceptance Criteria freeze before results** `architect freeze <iteration>` commits
154
- the frozen sections and records `freeze_sha`; any change to Grounds, Specification,
155
- or Acceptance Criteria after that point is an automatic iteration FAIL. The builder
156
- never edits the iteration file.
211
+ ```sh
212
+ architect init # scaffold ARCHITECT.md + the space.yaml project: block + SessionStart hook
213
+ architect brief new # scaffold the durable project BRIEF.md
214
+ architect new <iteration> # scaffold architecture/I<NN>-<iteration>.md
215
+ architect section <it> <section> --from <f> # write + commit a section
216
+ architect freeze <iteration> # freeze the Acceptance Criteria ❄️
217
+ architect worktree add <repo> <it> <lane> # isolated worktree per lane (2–4 lanes)
218
+ architect dispatch <it> <lane> # dispatch a builder (add --detach to survive long runs)
219
+ architect verify <iteration> # post-flight mechanical checks (reports only)
220
+ architect evidence <it> --lane <lane> # transcribe the builder's report verbatim
221
+ architect gate <iteration> # run the frozen gate commands, stream raw output
222
+ architect merge <it> <lane> # integrate ONE judged-passing lane (--no-ff)
223
+ architect integrate <it> --lanes a,b # integrate a set of passing lanes, in order
224
+ architect land # end-of-project PR command (no push, no gh)
225
+ architect status # project state (read-only)
226
+ architect variant add|compare|promote … # competing (harness, model) lanes over one frozen spec
227
+ architect research dispatch|status|wait … # parallel read-only research lanes (see below)
228
+ ```
157
229
 
158
- **Typical loop session:**
230
+ A typical session:
159
231
 
160
232
  ```sh
161
- # From inside your space:
162
- architect init # first time: scaffold ARCHITECT.md
163
- architect new my-feature # scaffold architecture/I01-my-feature.md
164
- # write Grounds + Specification + Acceptance Criteria …
165
- architect freeze my-feature # lock it
166
- architect dispatch my-feature lane-A # send builder to work
167
- # … builder runs, writes build/I01-my-feature-lane-A/report.md …
233
+ architect init # first time
234
+ architect new my-feature # scaffold I01-my-feature.md
235
+ architect section my-feature specification --from spec.md
236
+ architect freeze my-feature # lock it ❄️
237
+ architect dispatch my-feature lane-a --detach # send a builder; poll the report
168
238
  architect verify my-feature # mechanical post-flight checks
169
- architect status # review mission state
170
- # architect reads evidence and writes Verdict …
239
+ architect evidence my-feature --lane lane-a # transcribe raw evidence
240
+ architect gate my-feature # run the frozen gates yourself
241
+ # … read the diff against the spec, then write the Verdict …
242
+ architect integrate my-feature --lanes lane-a # merge passing lanes → project/<slug>
243
+ architect land # print gh pr create at project end
244
+ ```
245
+
246
+ ### Streaming builder output 📡
247
+
248
+ `architect dispatch` can push the builder's stream-json to an ingest server for
249
+ live viewing:
250
+
251
+ ```sh
252
+ # Push to an already-created run (you supply the full ingest URL):
253
+ architect dispatch my-feature lane-a \
254
+ --push-url $HOST/runs/<id>/ingest \
255
+ --push-token $INGEST_TOKEN
256
+
257
+ # Create a run and push in one step (requires --push-token = server's INGEST_TOKEN):
258
+ architect dispatch my-feature lane-a \
259
+ --push-host $HOST \
260
+ --push-token $INGEST_TOKEN
261
+ ```
262
+
263
+ `--push-host` POSTs to `<HOST>/runs`, parses the new run id from the `201`
264
+ response, derives `<HOST>/runs/<id>/ingest`, and streams there; the created run
265
+ id and ingest URL are printed after dispatch starts. `--push-url` and
266
+ `--push-host` are mutually exclusive, both require `--push-token`, and neither
267
+ can be combined with `--detach` (the push tees the live pipe in-process).
268
+
269
+ ### Research lanes 🔭
270
+
271
+ When an iteration needs facts the repo doesn't already have, fan out parallel
272
+ **read-only** research lanes — detached `claude -p` researchers (no
273
+ Edit/Write/Bash) that you supervise:
274
+
275
+ ```sh
276
+ architect research dispatch 01-official-api.prompt.md 02-changelog.prompt.md
277
+ architect research wait # tails each lane's run.jsonl; --level 1-4, --quiet, --thinking
278
+ architect research status # status of dispatched runs
171
279
  ```
172
280
 
281
+ Researchers gather; the architect verifies the load-bearing claims against
282
+ sources and writes the iteration's **Grounds** section.
283
+
284
+ ### Skills 🧠
285
+
286
+ `architect install-skills` installs the bundled `architect`,
287
+ `architect-research`, and `architect-vocabulary` skills for your harness:
288
+
289
+ ```sh
290
+ architect install-skills # default: claude (~/.claude/skills/)
291
+ architect install-skills --provider opencode # or codex | pi
292
+ architect install-skills --project # into ./… instead of globally
293
+ architect install-skills --dry-run # show what would change
294
+ ```
295
+
296
+ `architect-vocabulary` loads the system's terms and a short orientation when
297
+ you're in a space but don't want to run the loop.
298
+
173
299
  ## Fish shell integration 🐟
174
300
 
175
- Shells can't let a child process change *their* working directory, so `architect`
176
- ships a small fish wrapper function. It also installs fish completions for commands,
177
- subcommands, spaces, statuses, config keys, and common config values. Install both
178
- into fish's autoloaded directories:
301
+ Shells can't let a child process change *their* working directory, so `space`
302
+ and `src` each ship a small fish wrapper function plus completions (commands,
303
+ subcommands, spaces, statuses, config keys, repo refs). Install into fish's
304
+ autoloaded directories:
179
305
 
180
306
  ```fish
181
- architect space shell fish install
307
+ space shell fish install
308
+ src shell fish install
182
309
  exec fish
183
310
  ```
184
311
 
185
- Restarting fish (or `exec fish`) lets the current terminal pick up the new autoloaded
186
- wrapper function. After that, `architect space new "Name of Space"` and
187
- `architect space use 20260531-name-of-space` will `cd` into the selected space once the
188
- CLI command succeeds. Every other command keeps normal CLI behavior. 🚪
189
-
190
- The function is written to `~/.config/fish/functions/space.fish` and completions to
191
- `~/.config/fish/completions/space.fish`, so there's no need to edit `config.fish`.
312
+ After restarting fish (or `exec fish`), `space new "…"` and
313
+ `space use <id>` will `cd` into the selected space once the command succeeds;
314
+ every other command keeps normal CLI behavior. 🚪 The functions and completions
315
+ are written under `~/.config/fish/`, so there's no need to edit `config.fish`.
192
316
  For one-off testing without installing:
193
317
 
194
318
  ```fish
195
- architect space shell init fish | source
319
+ space shell init fish | source
196
320
  ```
197
321
 
198
322
  ## Configuration ⚙️
199
323
 
200
- Configuration follows the XDG base directory spec:
324
+ Config lives at `~/.config/space-architect/config.yml` (XDG-aware) and defaults to:
201
325
 
202
326
  ```yaml
203
327
  version: 1
204
- spaces_dir: ~/src/spaces
205
- evergreen_dir: ~/src/evergreen
328
+ base_dir: ~/architect # spaces_dir + src_dir hang off this by default
206
329
  default_provider: github.com
207
330
  default_organization:
208
- git_clone_protocol: ssh
331
+ git_clone_protocol: ssh # ssh | https
209
332
  ```
210
333
 
211
- View current values: `architect space config show`. Set a value: `architect space config set KEY VALUE`.
334
+ Derived defaults: `spaces_dir` `<base_dir>/spaces`, `src_dir` (evergreen
335
+ checkout root) → `<base_dir>/src`. Override either explicitly. View values with
336
+ `space config show`; set one with `space config set KEY VALUE`. Editable keys:
337
+ `base_dir`, `spaces_dir`, `src_dir`, `default_provider`, `default_organization`,
338
+ `git_clone_protocol`.
212
339
 
213
- ## Repos: evergreen, copy-on-write, concurrent 🌲
340
+ ## Repos: evergreen, copy-on-write, concurrent
214
341
 
215
342
  Repos are added to the current space under `repos/` and tracked in `space.yaml`.
216
- When an up-to-date local copy exists under `evergreen_dir` at
217
- `<evergreen_dir>/<provider>/<owner>/<name>` (e.g.
218
- `~/src/evergreen/github.com/example-org/example-app`), `architect` copies it into the
219
- space instead of cloning over the network — much faster, and a copy-on-write clone
220
- on APFS. ⚡ Set `evergreen_dir` to empty to always clone:
343
+ When an up-to-date evergreen checkout exists at
344
+ `<src_dir>/<host>/<owner>/<name>` (e.g.
345
+ `~/architect/src/github.com/example-org/example-app`), `space` copies it into the
346
+ space instead of cloning over the network — a copy-on-write clone on APFS. ⚡
347
+ Set `src_dir` empty to always clone:
221
348
 
222
349
  ```sh
223
- architect space config set evergreen_dir ""
350
+ space config set src_dir ""
224
351
  ```
225
352
 
226
- When no evergreen copy is found, the repo is cloned over the network. Clone URLs
227
- default to SSH (`git@github.com:example-org/example-app.git`). Prefer HTTPS?
353
+ Clone URLs default to SSH (`git@github.com:example-org/example-app.git`); switch
354
+ with `space config set git_clone_protocol https`. Multiple repos passed to
355
+ `space repo add` are fetched **concurrently**, up to five at a time, on fibers —
356
+ no threads, all cooperative. 🧵 After each repo lands, `space` runs `mise trust`
357
+ in it. Each space also gets a workspace-local `tmp/` — use it instead of `/tmp`.
228
358
 
229
- ```sh
230
- architect space config set git_clone_protocol https
231
- ```
232
-
233
- When stdout/stderr are attached to a TTY, long-running repo operations show an
234
- interactive spinner. Multiple repos passed to `architect space repo add` are fetched
235
- **concurrently**, up to five at a time, on fibers — no threads, all cooperative. 🧵
236
- After each repo is in place, `architect` runs `mise trust` in it so local mise config
237
- is ready to go.
359
+ ## Embedding 📚
238
360
 
239
- Each space also gets a workspace-local `tmp/`. Use it instead of `/tmp` or
240
- `/var/tmp`; when using `mktemp`, point it at `tmp/`. 🗑️
361
+ The library is split into three namespaces you can require independently:
241
362
 
242
- ## The `src` engine: evergreen checkouts 🌿
363
+ - **`Space::Core`** the foundation: config, state, XDG, terminal, git/mise
364
+ clients, the space store. The `space` CLI runs on this alone.
365
+ - **`Space::Architect`** — project state, the builder harness, dispatch, and the
366
+ research supervisor.
367
+ - **`Space::Src`** — the evergreen engine (tracking, sync, copy-on-write clone).
243
368
 
244
- `architect src …` exposes the **vendored** evergreen engine (from
245
- [repo-tender](https://github.com/jetpks/repo-tender)) directly no separate
246
- installation needed. It keeps local clones under
247
- `~/src/evergreen/<host>/<owner>/<repo>` clean, on their default branch, and freshly
248
- fetched.
249
-
250
- ```sh
251
- architect src repo add github.com/example-org/example-app # tend it 🌲
252
- architect src sync # run one sync pass
253
- architect src status # per-repo evergreen status
254
- ```
255
-
256
- When `architect space repo add` sees a matching evergreen copy, it copy-on-writes
257
- from it instead of hitting the network — instant provisioning. ⚡
258
-
259
- The vendored engine and space management share the same layout by design — both use
260
- `<evergreen_dir>/<host>/<owner>/<repo>` — so they line up with zero configuration:
261
-
262
- ```sh
263
- architect src repo add github.com/example-org/example-app # tend it: keep it evergreen 🌲
264
- architect space repo add example-app # copies it instantly ⚡
369
+ ```ruby
370
+ require "space_core" # just spaces
371
+ require "space_architect" # the full loop (pulls in core + src)
372
+ require "space_src" # just the evergreen engine
265
373
  ```
266
374
 
267
375
  ## Documentation 📖
268
376
 
269
377
  - **[Command Reference](docs/reference.md)** — every command, flag, and behavior
270
- - **[Design](docs/design.md)** — why spaces and the Architect Loop exist and how they're shaped
378
+ - **[Design](docs/DESIGN.md)** — the source-backed rationale: the twelve invariant rules (R1–R12), the failure-mode → mitigation table, and why the loop is shaped this way
379
+ - **[Changelog](CHANGELOG.md)** — release history
271
380
 
272
381
  ## Development 🛠️
273
382
 
data/exe/architect CHANGED
@@ -10,4 +10,4 @@ end
10
10
 
11
11
  require "space_architect"
12
12
 
13
- SpaceArchitect::CLI.run(ARGV, $stdout, $stderr)
13
+ Space::Architect::CLI.run(ARGV, $stdout, $stderr)
data/exe/space CHANGED
@@ -8,6 +8,6 @@ if File.exist?(source_gemfile)
8
8
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
9
9
  end
10
10
 
11
- require "space_architect"
11
+ require "space_core"
12
12
 
13
- SpaceArchitect::CLI.run(["space", *ARGV], $stdout, $stderr)
13
+ Space::Core::CLI.run(ARGV, $stdout, $stderr)
data/exe/src ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ source_gemfile = File.expand_path("../Gemfile", __dir__)
5
+ if File.exist?(source_gemfile)
6
+ ENV["BUNDLE_GEMFILE"] ||= source_gemfile
7
+ require "bundler/setup"
8
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
9
+ end
10
+
11
+ require "space_src"
12
+
13
+ Space::Src::CLI.run(ARGV, $stdout, $stderr)