space-architect 8.0.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -0
  3. data/README.md +53 -243
  4. data/lib/space_architect/bug_report.rb +2 -1
  5. data/lib/space_architect/cli/architect.rb +20 -7
  6. data/lib/space_architect/cli.rb +9 -14
  7. data/lib/space_architect/session_sync/bin_path.rb +1 -1
  8. data/lib/space_architect/session_sync/cursor.rb +1 -1
  9. data/lib/space_architect/session_sync/plist.rb +1 -1
  10. data/lib/{space_core → space_architect}/version.rb +2 -2
  11. data/lib/space_architect.rb +1 -1
  12. data/skill/architect/SKILL.md +3 -2
  13. data/skill/architect-vocabulary/SKILL.md +2 -2
  14. metadata +18 -177
  15. data/exe/space +0 -13
  16. data/exe/src +0 -13
  17. data/lib/space_architect/cli/space.rb +0 -29
  18. data/lib/space_architect/cli/src.rb +0 -38
  19. data/lib/space_core/atomic_write.rb +0 -21
  20. data/lib/space_core/cli/base_command.rb +0 -19
  21. data/lib/space_core/cli/build.rb +0 -27
  22. data/lib/space_core/cli/config.rb +0 -49
  23. data/lib/space_core/cli/current.rb +0 -16
  24. data/lib/space_core/cli/help.rb +0 -195
  25. data/lib/space_core/cli/helpers.rb +0 -115
  26. data/lib/space_core/cli/init.rb +0 -29
  27. data/lib/space_core/cli/list.rb +0 -24
  28. data/lib/space_core/cli/loop_status.rb +0 -47
  29. data/lib/space_core/cli/new.rb +0 -38
  30. data/lib/space_core/cli/pack.rb +0 -29
  31. data/lib/space_core/cli/path.rb +0 -16
  32. data/lib/space_core/cli/repeatable_options.rb +0 -84
  33. data/lib/space_core/cli/repo.rb +0 -76
  34. data/lib/space_core/cli/run.rb +0 -44
  35. data/lib/space_core/cli/shell.rb +0 -125
  36. data/lib/space_core/cli/show.rb +0 -21
  37. data/lib/space_core/cli/status.rb +0 -74
  38. data/lib/space_core/cli/use.rb +0 -17
  39. data/lib/space_core/cli.rb +0 -177
  40. data/lib/space_core/commands.rb +0 -51
  41. data/lib/space_core/config.rb +0 -152
  42. data/lib/space_core/errors.rb +0 -14
  43. data/lib/space_core/git_client.rb +0 -49
  44. data/lib/space_core/mise_client.rb +0 -37
  45. data/lib/space_core/oci_builder.rb +0 -56
  46. data/lib/space_core/oci_packer.rb +0 -103
  47. data/lib/space_core/oci_runner.rb +0 -89
  48. data/lib/space_core/paths.rb +0 -58
  49. data/lib/space_core/repo_reference.rb +0 -19
  50. data/lib/space_core/repo_resolver.rb +0 -167
  51. data/lib/space_core/shell_integration.rb +0 -438
  52. data/lib/space_core/slugger.rb +0 -16
  53. data/lib/space_core/space.rb +0 -174
  54. data/lib/space_core/space_store.rb +0 -319
  55. data/lib/space_core/state.rb +0 -86
  56. data/lib/space_core/templates/oci/dockerfile.erb +0 -73
  57. data/lib/space_core/templates/oci/dockerignore.erb +0 -17
  58. data/lib/space_core/templates/oci/entrypoint.sh.erb +0 -16
  59. data/lib/space_core/terminal.rb +0 -161
  60. data/lib/space_core/warnings.rb +0 -13
  61. data/lib/space_core/xdg.rb +0 -33
  62. data/lib/space_core.rb +0 -26
  63. data/lib/space_src/cli/clone.rb +0 -54
  64. data/lib/space_src/cli/config.rb +0 -65
  65. data/lib/space_src/cli/daemon.rb +0 -362
  66. data/lib/space_src/cli/options.rb +0 -21
  67. data/lib/space_src/cli/org.rb +0 -199
  68. data/lib/space_src/cli/repo.rb +0 -169
  69. data/lib/space_src/cli/shell.rb +0 -121
  70. data/lib/space_src/cli/status.rb +0 -75
  71. data/lib/space_src/cli/sync.rb +0 -161
  72. data/lib/space_src/cli.rb +0 -159
  73. data/lib/space_src/cloner.rb +0 -77
  74. data/lib/space_src/config/contract.rb +0 -54
  75. data/lib/space_src/config/duration.rb +0 -79
  76. data/lib/space_src/config/model.rb +0 -49
  77. data/lib/space_src/config/store.rb +0 -156
  78. data/lib/space_src/forge/client.rb +0 -31
  79. data/lib/space_src/forge/github.rb +0 -98
  80. data/lib/space_src/launchd/agent.rb +0 -195
  81. data/lib/space_src/launchd/plist.rb +0 -129
  82. data/lib/space_src/log_rotator.rb +0 -46
  83. data/lib/space_src/migration.rb +0 -43
  84. data/lib/space_src/nav.rb +0 -99
  85. data/lib/space_src/paths.rb +0 -72
  86. data/lib/space_src/scm/client.rb +0 -87
  87. data/lib/space_src/scm/git.rb +0 -232
  88. data/lib/space_src/scm/status.rb +0 -24
  89. data/lib/space_src/shell.rb +0 -90
  90. data/lib/space_src/shell_integration.rb +0 -321
  91. data/lib/space_src/state/lock.rb +0 -59
  92. data/lib/space_src/state/store.rb +0 -140
  93. data/lib/space_src/sync/engine.rb +0 -503
  94. data/lib/space_src/sync/repo_plan.rb +0 -215
  95. data/lib/space_src/sync/report.rb +0 -18
  96. data/lib/space_src/ui/interactive_reporter.rb +0 -280
  97. data/lib/space_src/ui/json_reporter.rb +0 -39
  98. data/lib/space_src/ui/mode.rb +0 -68
  99. data/lib/space_src/ui/plain_reporter.rb +0 -53
  100. data/lib/space_src/ui/reporter.rb +0 -48
  101. data/lib/space_src/version.rb +0 -7
  102. data/lib/space_src.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b63abfece4c105ef5b2befd0d8c4e4301d8d5cade10570cd2f41bd0641b8c4be
4
- data.tar.gz: 6b932ae13952dad48f81a2ee68ed52b7cee28ef8edc4a99e7a06f23952c4f107
3
+ metadata.gz: 02caeb5cc690ab3d847e54fed5eb88c1493fa2402ace662ef7f25d2aeb4d055b
4
+ data.tar.gz: 5fa1fc73aaf8e912a74b1daf36e392c4d8afdc19cf1e6af22cc94702ef4146fd
5
5
  SHA512:
6
- metadata.gz: 3cbb55f4fab850bc9fb7b4cf55bb318bf846d54c3f78a399c50b76d325ddbcd12ad52072d224d75a25b6e5830c8fffa6d7e6f51ad522aae231bb2b374ac3980e
7
- data.tar.gz: 4adfa615512c8f6652b85d5948c0a58c9851d30711fc2a1a7f870060601bb6fe0fab9af4ade0c8eebfb5e93a67bf60d1d6516e12fcd0ba96595d530049e0d0da
6
+ metadata.gz: b0f3278ba088effaba68eb1942872bb38dc7b73301bc7f0c5229ab773a69174da531d76009a2725912ab2615c67f1b6321ac3e20648e919adfd471e8a41eb309
7
+ data.tar.gz: 550862ccc0030a536896d219c2645c7194ec56357eebe9ae3eb08024811b60aca7fd857fd2e86daa80a406fa54e0050b922f80926ea66a14fcbb6fa71bcfda5b
data/CHANGELOG.md CHANGED
@@ -5,6 +5,60 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [9.0.0] - 2026-10-09
9
+
10
+ ### Changed
11
+
12
+ - **The split: space-architect is now the Architect Loop only.** The monolith
13
+ carved the space tool and the evergreen engine into their own gems —
14
+ **space-cadet** 9.0.0 (`Space::Core`, the `space` binary) and **repo-tender**
15
+ 1.0.0 (`RepoTender`, the `repo-tender` binary with the deprecated `src`
16
+ shim) — and this gem consumes them as libraries instead of vendoring them.
17
+ Dropped: the vendored `lib/space_core` / `lib/space_src` subtrees, the
18
+ `exe/space` and `exe/src` binaries, and the `architect space …` / `architect
19
+ src …` forwarder intercepts. `architect space …` / `architect src …` are now
20
+ ordinary unknown commands (dry-cli usage + non-zero exit) — the `space`
21
+ binary comes from space-cadet and the `src` binary from repo-tender; re-point
22
+ 8.x scripts and aliases accordingly.
23
+ - **Upgrading from 8.x:** `gem uninstall space-architect` first — the 8.x gem's
24
+ `space` and `src` executables collide with the ones the new gems ship — then
25
+ `gem install space-architect` (pulls space-cadet) and, for the session-sync
26
+ rail, `gem install repo-tender`. Config/state: space-cadet ≥ 9.1 migrates the
27
+ substrate's `config.yml`/`state.yml` from the old
28
+ `~/.config|state/space-architect/` dirs automatically on first run of either
29
+ `space` or `architect` (on 9.0.0, move them across by hand); the loop's own
30
+ session-sync cursor stays where it is.
31
+ - **Host-branded help header.** `architect --help`'s root header now brands
32
+ the loop (`architect 9.0.0 — …`) via space-cadet's product-name/version seam
33
+ instead of the substrate's identity — hence the `space-cadet ~> 9.1`
34
+ dependency floor.
35
+ - **Own version line.** The loop's version is now
36
+ `Space::Architect::VERSION = "9.0.0"` (`lib/space_architect/version.rb`) —
37
+ its first, decoupled from `Space::Core::VERSION`. The gemspec version,
38
+ `architect --version`, the bug-report diagnostics, and the bug-report command
39
+ footer all derive from the loop's own constant; the bug report additionally
40
+ lists `space-cadet: <version>` as a dependency diagnostic.
41
+ - **Dependency posture.** Hard dependency: `space-cadet ~> 9.0`. The declared
42
+ set shrank to what the loop itself requires (`async-http`, `async-process`,
43
+ `protocol-http`, `pastel`, `dry-cli`, `dry-monads`, `dry-validation` — `xdg`,
44
+ `tty-cursor`, `dry-struct`/`dry-types`, and bare `async` were the vendored
45
+ trees' deps, not the loop's). repo-tender is deliberately **not** a gemspec
46
+ runtime dependency: the `sessions agent` launchd seam requires it lazily and,
47
+ when the gem is absent, fails with a short actionable error naming the fix
48
+ (`gem install repo-tender`) instead of a LoadError backtrace. The dev
49
+ Gemfile includes repo-tender so the suite exercises the real integration.
50
+ - **Tests and mutation subjects classified, not carried.** Tests whose subject
51
+ was the vendored tools' functionality (everything under `test/space_core/`
52
+ and `test/space_src/`, the forwarder tests, the space-tool surface,
53
+ shell-integration, slugger, repo-resolver, warnings) dropped with the code —
54
+ their coverage lives in the two gems. Loop tests keep running against the
55
+ gem-served `Space::Core`; fixture setup routes through the gem's own CLI.
56
+ The `:mutant` task now subjects `Space::Architect::GateEvaluator` and
57
+ `Space::Architect::GateLint` only.
58
+ - **Docs and skills updated to the split reality** (README, command reference,
59
+ releasing guide, design doc, skills): one binary, two gem dependencies, no
60
+ forwarders or vendored subtrees.
61
+
8
62
  ## [8.0.0] - 2026-10-09
9
63
 
10
64
  ### Changed
data/README.md CHANGED
@@ -2,24 +2,28 @@
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 projects — for humans and their agents!** ✨🛰️
5
+ > **The Architect Loop — structured judgment-and-build cycles for humans and their agents!** ✨🛰️
6
6
 
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. 🌌
7
+ `space-architect` is the gem behind the **Architect Loop**: a structured
8
+ judgment-and-build cycle for you and a fleet of headless AI builders, run
9
+ inside task-scoped **spaces** — directories that hold repos, notes, and
10
+ artifacts under one obvious filesystem root. 🌌
11
11
 
12
- The gem ships **three composable binaries** over clean library seams:
12
+ It installs **one executable**, `architect`. The spaces substrate and the
13
+ evergreen-checkout engine live in two sibling gems:
13
14
 
14
- | Binary | What it does | Library |
15
- |--------|--------------|---------|
16
- | **`space`** 🪐 | Create, manage & containerize 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` |
15
+ | Gem | Dependency | What it provides |
16
+ |-----|------------|------------------|
17
+ | **space-cadet** | hard | The spaces substrate (`Space::Core`): create, manage & containerize task-scoped workspaces — the `space` binary — plus the copy-on-write evergreen-checkout substrate (`Cloner`, `SCM`) repos provision from |
18
+ | **repo-tender** | soft | Evergreen clone tending — the `repo-tender` binary (with the deprecated `src` shim) — and the launchd agent the `architect sessions agent` commands drive. Install with `gem install repo-tender` when you want the session-sync rail — everything else works without it |
19
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. 🎀
20
+ Until 8.x this gem was the monolith: it shipped `space`, `architect`, and `src`
21
+ binaries (and `architect space …` / `architect src …` forwarders) plus the
22
+ vendored `Space::Core` / `Space::Src` subtrees. The 9.0.0 split carved the
23
+ tools into their own gems; this gem is the loop only. If you're on 8.x, get
24
+ `space` from the **space-cadet** gem and `src` from **repo-tender** now — and
25
+ `gem uninstall space-architect` first: the 8.x gem's `space`/`src` executables
26
+ collide with the ones the new gems ship.
23
27
 
24
28
  ## What's a space? 🪐
25
29
 
@@ -37,10 +41,17 @@ everything a task needs:
37
41
  tmp/ # workspace-local temp — use this instead of /tmp
38
42
  ```
39
43
 
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. 🧭
44
+ Run an `architect` command from inside a space and it just works — the loop
45
+ walks up from `$PWD` until it finds the nearest `space.yaml`. No "current
46
+ space" state to get out of sync; where you *are* is the space you mean. 🧭
47
+
48
+ Create and manage spaces with the **space-cadet** gem:
49
+
50
+ ```sh
51
+ space init # create XDG config + state files
52
+ space new "Name of Space" -r org/repo -r org/lib # blast off a new space 🚀
53
+ space list # see all your spaces
54
+ ```
44
55
 
45
56
  ## Installation 📦
46
57
 
@@ -58,25 +69,18 @@ Or grab it yourself:
58
69
 
59
70
  ```bash
60
71
  gem install space-architect
72
+ gem install repo-tender # optional: enables the sessions launchd agent
61
73
  ```
62
74
 
63
- The gem is `space-architect`; it installs three executables — `space`,
64
- `architect`, and `src`. 🎀
75
+ The gem installs one executable: `architect`. 🎀
65
76
 
66
77
  ## Quick start 🎀
67
78
 
68
79
  ```sh
69
- # Spaces
80
+ # Spaces (space-cadet gem)
70
81
  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
82
+ space new "Name of Space" -r org/repo -r org/lib # blast off a new space 🚀
83
+ space use 20260531-name-of-space # cd into a space by id
80
84
 
81
85
  # Architect Loop (run from inside a space)
82
86
  architect install-skills # install agent skills (once per machine)
@@ -84,157 +88,8 @@ architect init # scaffold ARCHITECT.md + arch
84
88
  architect new my-feature # scaffold the next iteration file
85
89
  architect freeze my-feature # lock the Acceptance Criteria ❄️
86
90
  architect dispatch my-feature lane-a # send a headless builder to work
87
-
88
- # Containers (run from inside a space) — a portable, reproducible-by-SHA image of the space
89
- space pack # render build/oci/ (Dockerfile + entrypoint)
90
- space build # pack + build & tag <space-id>:<git-sha>
91
- space run # run it — login shell, auth from your env
92
91
  ```
93
92
 
94
- ## `space` — task-scoped workspaces 🌌
95
-
96
- ```sh
97
- space init
98
- space new "Name of Space"
99
- space new "Name of Space" -r org/repo -r example-tools/alpha -r example-tools/beta
100
- space list # alias: space ls
101
- space show 20260531-name-of-space
102
- space path 20260531-name-of-space
103
- space current # based on $PWD
104
- space show # based on $PWD
105
- space status # report: metadata + loop status (based on $PWD)
106
- space status 20260531-name-of-space # report another space
107
- space status done # set: active | paused | done | archived
108
- space status 20260531-name-of-space done
109
- space config set default_provider github.com
110
- space config set default_organization example-org
111
- space repo add example-app # github.com/example-org/example-app
112
- space repo add example-tools/alpha example-tools/beta
113
- space repo add gitlab.com/example-org/api
114
- space repo resolve example-app example-tools/async
115
- space repo ls # alias: space repos ls
116
- space use 20260531-name-of-space # records recent state, prints the path
117
- space ls --color=always # auto | always | never (--colors also accepted)
118
- ```
119
-
120
- `space status` is **report-or-set**: with no status keyword (bare, or with just
121
- a space id) it *reports* the space — its metadata plus a compact loop-status
122
- block (project status, current iteration, derived state) when the space runs an
123
- Architect project, quietly omitted otherwise; pass a status keyword (`active`,
124
- `paused`, `done`, `archived`) to *set* it instead. 🔁
125
-
126
- Repos are passed with a repeatable `-r` flag (`-r org/repo -r org/lib`); the
127
- comma form (`-r a,b`) works too. Space ids are date-prefixed
128
- (`20260531-name-of-space`) so they sort naturally, and duplicate names on the
129
- same day get a counter (`…-name-of-space-2`). 📅
130
-
131
- Everything `space` does is also reachable as `architect space …` from within a
132
- project.
133
-
134
- ## Containerize a space: `pack` · `build` · `run` 📦
135
-
136
- A space is self-describing enough to become a container. `space pack` renders a
137
- portable OCI build context from the space; `space build` packs and builds it into
138
- a **reproducible-by-SHA** image; `space run` runs that image with your auth
139
- injected at runtime and stateful paths bind-mounted back to the host. 🐳
140
-
141
- ```sh
142
- space pack # render build/oci/ (Dockerfile + entrypoint + ignore file)
143
- space pack -o /tmp/ctx # …to a different output directory
144
- space build # pack, then build & tag <space-id>:<git-sha> and :latest
145
- space run # run <space-id>:latest — login shell, auth from your env
146
- space run architect status # …or run a one-off command instead of the login shell
147
- space run --tty # force an interactive TTY (default: auto-detect)
148
- ```
149
-
150
- **What lands in the image.** The context copies the whole space tree (filtered by
151
- a generated `Dockerfile.dockerignore`) onto a `ruby:4.0.5` base with `git`, the
152
- Claude Code CLI, and the `space-architect` gem — installed from the in-space
153
- `repos/space-architect` checkout when present (a pinned build), else from
154
- RubyGems. Secrets never enter the layers: `.env`, `*.key`, `*.pem`, ssh keys,
155
- `build/`, and `tmp/` are all excluded by the generated ignore file. 🔒
156
-
157
- **Reproducible by SHA.** `space build` tags the image `<space-id>:<sha>`, where
158
- `<sha>` is the space repo's 12-char `HEAD` (suffixed `-dirty` when the tree has
159
- uncommitted changes), plus a moving `:latest`. Same commit → same tag → same
160
- image. It drives the `container` CLI, but the output is an ordinary OCI/Docker
161
- build context, so `docker build -f build/oci/Dockerfile .` (from the space root)
162
- works just as well.
163
-
164
- **Auth stays out of the layers.** `space run` injects only the auth environment
165
- variables that are actually set — `ANTHROPIC_API_KEY`, `CLAUDE_CODE_OAUTH_TOKEN`,
166
- `ANTHROPIC_BASE_URL` — with `-e` at run time, so credentials live in your shell,
167
- never in the image. 🗝️
168
-
169
- **Forwarding payload credentials.** Beyond the always-on auth trio, a space can declare
170
- `run.env:` in `space.yaml` — a list of host env var names forwarded into the container at
171
- run time. You can also pass `space run --env VAR` (repeatable) for ad hoc additions. All
172
- forwarding is bare `-e VAR` passthrough: values never appear in argv, `ps`, or the image.
173
- A requested-but-unset var warns on stderr instead of silently failing inside the guest.
174
-
175
- ```yaml
176
- run:
177
- env: # run-time: host var names, forwarded as bare -e VAR
178
- - FIREWORKS_API_KEY
179
- - OPENAI_API_KEY
180
- ```
181
-
182
- **Declaring provisioning & persistence** — two optional keys in `space.yaml`:
183
-
184
- ```yaml
185
- pack:
186
- provision: # build-time: relative scripts, baked in by `space build`
187
- - scripts/setup-toolchain.sh
188
- persist: # run-time: absolute guest paths, bind-mounted per run
189
- - /root/.claude
190
- - /root/.local/state
191
- ```
192
-
193
- `provision` scripts must live under the space root and be executable. Each script is
194
- copied into the image individually (`COPY <script> /space/<script>`) and then invoked
195
- (`RUN /space/<script>`) **before** the full space tree lands and **before** the gem is
196
- installed. This ordering is the cache-hygiene guarantee: editing any other space file
197
- leaves the provision and gem-install layers cached, so a rebuild completes in seconds
198
- instead of minutes. Scripts must therefore be self-contained — they run with only the
199
- base system layers and any earlier provision scripts' outputs; they cannot read other
200
- space files or call `architect`/`space`. Scripts must have the executable bit set; COPY
201
- preserves the mode from the build context.
202
-
203
- `persist` paths must be absolute; `space run` bind-mounts each one from
204
- `<space>/.state<path>` on the host (created on first run) so a container's mutable state
205
- survives across runs. Both are validated at pack time.
206
-
207
- Like everything else, these are reachable as `architect space pack|build|run`
208
- from inside a project.
209
-
210
- ## `src` — the evergreen engine 🌲
211
-
212
- `src` keeps local clones under `<src_dir>/<host>/<owner>/<repo>` (default
213
- `~/architect/src/…`) clean, on their default branch, and freshly fetched — so
214
- spaces can provision repos by **copy-on-write** instead of cloning over the
215
- network.
216
-
217
- ```sh
218
- src repo add github.com/example-org/example-app # track + tend a repo
219
- src org add github.com/example-org # track a whole org
220
- src sync # run one sync pass (--repo to scope)
221
- src status # per-repo evergreen status table
222
- src clone example-app # APFS copy-on-write into $PWD
223
- src daemon install # per-user launchd agent for background sync
224
- ```
225
-
226
- When `space repo add` finds a matching evergreen checkout, it copy-on-writes
227
- from it instead of hitting the network — instant provisioning. ⚡ The two
228
- surfaces share one layout by design, so they line up with zero configuration:
229
-
230
- ```sh
231
- src repo add github.com/example-org/example-app # tend it: keep it evergreen 🌲
232
- space repo add example-app # copies it instantly ⚡
233
- ```
234
-
235
- `src` has its own `--plain` / `--json` output modes for scripting, and its own
236
- fish integration (`src shell fish install`).
237
-
238
93
  ## `architect` — the Architect Loop 🏗️
239
94
 
240
95
  The **Architect Loop** is a structured build cycle for you and headless AI
@@ -396,80 +251,35 @@ architect install-skills --dry-run # show what would change
396
251
  `architect-vocabulary` loads the system's terms and a short orientation when
397
252
  you're in a space but don't want to run the loop.
398
253
 
399
- ## Fish shell integration 🐟
400
-
401
- Shells can't let a child process change *their* working directory, so `space`
402
- and `src` each ship a small fish wrapper function plus completions (commands,
403
- subcommands, spaces, statuses, config keys, repo refs). Install into fish's
404
- autoloaded directories:
254
+ ### Sessions: the launchd rail 🛰️ (requires repo-tender)
405
255
 
406
- ```fish
407
- space shell fish install
408
- src shell fish install
409
- exec fish
410
- ```
411
-
412
- After restarting fish (or `exec fish`), `space new "…"` and
413
- `space use <id>` will `cd` into the selected space once the command succeeds;
414
- every other command keeps normal CLI behavior. 🚪 The functions and completions
415
- are written under `~/.config/fish/`, so there's no need to edit `config.fish`.
416
- For one-off testing without installing:
417
-
418
- ```fish
419
- space shell init fish | source
420
- ```
256
+ `architect sessions sync` uploads new conversation transcripts (`~/.pi/agent/sessions`
257
+ and `~/.claude/projects`) to a space-server; `architect sessions agent
258
+ install|uninstall|status` manages the per-user launchd agent that runs the sync
259
+ on an interval. These commands drive **repo-tender**'s launchd agent — a *soft*
260
+ dependency, deliberately absent from the gemspec: without the gem, the sessions
261
+ agent commands print a short error naming the fix (`gem install repo-tender`)
262
+ and the rest of `architect` is unaffected.
421
263
 
422
264
  ## Configuration ⚙️
423
265
 
424
- Config lives at `~/.config/space-architect/config.yml` (XDG-aware) and defaults to:
425
-
426
- ```yaml
427
- version: 1
428
- base_dir: ~/architect # spaces_dir + src_dir hang off this by default
429
- default_provider: github.com
430
- default_organization:
431
- git_clone_protocol: ssh # ssh | https
432
- ```
433
-
434
- Derived defaults: `spaces_dir` → `<base_dir>/spaces`, `src_dir` (evergreen
435
- checkout root) → `<base_dir>/src`. Override either explicitly. View values with
436
- `space config show`; set one with `space config set KEY VALUE`. Editable keys:
437
- `base_dir`, `spaces_dir`, `src_dir`, `default_provider`, `default_organization`,
438
- `git_clone_protocol`.
439
-
440
- ## Repos: evergreen, copy-on-write, concurrent ⚡
441
-
442
- Repos are added to the current space under `repos/` and tracked in `space.yaml`.
443
- When an up-to-date evergreen checkout exists at
444
- `<src_dir>/<host>/<owner>/<name>` (e.g.
445
- `~/architect/src/github.com/example-org/example-app`), `space` copies it into the
446
- space instead of cloning over the network — a copy-on-write clone on APFS. ⚡
447
- Set `src_dir` empty to always clone:
448
-
449
- ```sh
450
- space config set src_dir ""
451
- ```
452
-
453
- Clone URLs default to SSH (`git@github.com:example-org/example-app.git`); switch
454
- with `space config set git_clone_protocol https`. Multiple repos passed to
455
- `space repo add` are fetched **concurrently**, up to five at a time, on fibers —
456
- no threads, all cooperative. 🧵 After each repo lands, `space` runs `mise trust`
457
- in it. Each space also gets a workspace-local `tmp/` — use it instead of `/tmp`.
266
+ The spaces config the loop reads lives at `~/.config/space-cadet/config.yml`
267
+ (XDG-aware, owned by the space-cadet gem) — see `space config show`. The loop
268
+ itself has no config of its own: a space's `space.yaml` `project:` block *is*
269
+ the loop's state.
458
270
 
459
271
  ## Embedding 📚
460
272
 
461
- The library is split into three namespaces you can require independently:
273
+ Two namespaces, published as two gems:
462
274
 
463
- - **`Space::Core`** — the foundation: config, state, XDG, terminal, git/mise
464
- clients, the space store. The `space` CLI runs on this alone.
465
- - **`Space::Architect`** — project state, the builder harness, dispatch, and the
466
- research supervisor.
467
- - **`Space::Src`** — the evergreen engine (tracking, sync, copy-on-write clone).
275
+ - **`Space::Core`** (the space-cadet gem) — the substrate: config, state, XDG,
276
+ terminal, git/mise clients, the space store. The `space` CLI runs on this.
277
+ - **`Space::Architect`** (this gem) — project state, the builder harness,
278
+ dispatch, and the research supervisor, over the `Space::Core` substrate.
468
279
 
469
280
  ```ruby
470
- require "space_core" # just spaces
471
- require "space_architect" # the full loop (pulls in core + src)
472
- require "space_src" # just the evergreen engine
281
+ require "space_core" # just spaces (space-cadet gem)
282
+ require "space_architect" # the loop (pulls in the space-cadet gem)
473
283
  ```
474
284
 
475
285
  ## Documentation 📖
@@ -79,7 +79,8 @@ module Space
79
79
  <<~MD
80
80
  ## Diagnostics
81
81
 
82
- - space-architect: #{Space::Core::VERSION}
82
+ - space-architect: #{Space::Architect::VERSION}
83
+ - space-cadet: #{Space::Core::VERSION}
83
84
  - ruby: #{RUBY_VERSION} (#{RUBY_PLATFORM})
84
85
  MD
85
86
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "json"
4
4
  require "fileutils"
5
- require "space_src/launchd/agent"
6
5
  require_relative "../jobs_client"
7
6
  require_relative "../conversations_client"
8
7
  require_relative "../session_sync"
@@ -12,8 +11,8 @@ module Space::Architect
12
11
  # Optional loop-phase DSL on the shared command base, read by
13
12
  # Space::Core::CLI::Help to group the help listing. A command may declare
14
13
  # `phase <order>, "<Label>"`; groups, and members within a group, sort by
15
- # <order>. Only architect commands declare one — space commands leave it nil
16
- # and render as the single ungrouped default listing (unchanged).
14
+ # <order>. Only architect commands declare one — commands without a phase
15
+ # render as the single ungrouped default listing (unchanged).
17
16
  class BaseCommand
18
17
  def self.phase(order = nil, label = nil)
19
18
  return @phase if order.nil?
@@ -800,7 +799,8 @@ module Space::Architect
800
799
  terminal.say result[:command]
801
800
  terminal.say ""
802
801
  terminal.say "Diagnostics:"
803
- terminal.say " space-architect #{Space::Core::VERSION}"
802
+ terminal.say " space-architect #{Space::Architect::VERSION}"
803
+ terminal.say " space-cadet #{Space::Core::VERSION}"
804
804
  terminal.say " ruby #{RUBY_VERSION} (#{RUBY_PLATFORM})"
805
805
  terminal.say " space: #{space.id} — #{space.title}" if space
806
806
  CLI.record_outcome(Outcome.new(exit_code: 0))
@@ -1168,6 +1168,17 @@ module Space::Architect
1168
1168
  end
1169
1169
 
1170
1170
  def format_failure(f) = f.is_a?(Hash) ? f.inspect : f.to_s
1171
+
1172
+ # The launchd-agent seam is repo-tender's — a soft dependency, never a
1173
+ # gemspec runtime dep. Required lazily so `sessions agent …` degrades
1174
+ # with an actionable hint instead of failing at boot when the gem is
1175
+ # absent; handle_errors turns the raise into a red message + exit 1.
1176
+ def agent
1177
+ require "repo_tender"
1178
+ RepoTender::Launchd::Agent
1179
+ rescue LoadError
1180
+ raise Space::Core::Error, "sessions agent needs the repo-tender gem — install it with: gem install repo-tender"
1181
+ end
1171
1182
  end
1172
1183
 
1173
1184
  class Install < BaseCommand
@@ -1196,7 +1207,7 @@ module Space::Architect
1196
1207
  File.write(pp, xml)
1197
1208
  File.chmod(0o600, pp)
1198
1209
 
1199
- result = Space::Src::Launchd::Agent.new(label: SessionSync::LABEL).install(pp)
1210
+ result = agent.new(label: SessionSync::LABEL).install(pp)
1200
1211
  raise Space::Core::Error, "bootstrap failed: #{format_failure(result.failure)}" if result.failure?
1201
1212
 
1202
1213
  terminal.say "Installed: #{terminal.path(pp)}"
@@ -1213,7 +1224,7 @@ module Space::Architect
1213
1224
  setup_terminal(**opts.slice(:color, :colors))
1214
1225
  handle_errors do
1215
1226
  pp = plist_path
1216
- result = Space::Src::Launchd::Agent.new(label: SessionSync::LABEL).uninstall
1227
+ result = agent.new(label: SessionSync::LABEL).uninstall
1217
1228
  terminal.say "bootout reported: #{format_failure(result.failure)}" if result.failure?
1218
1229
 
1219
1230
  if File.exist?(pp)
@@ -1234,7 +1245,7 @@ module Space::Architect
1234
1245
  def call(**opts)
1235
1246
  setup_terminal(**opts.slice(:color, :colors))
1236
1247
  handle_errors do
1237
- result = Space::Src::Launchd::Agent.new(label: SessionSync::LABEL).status
1248
+ result = agent.new(label: SessionSync::LABEL).status
1238
1249
  raise Space::Core::Error, "status failed: #{format_failure(result.failure)}" if result.failure?
1239
1250
 
1240
1251
  s = result.success
@@ -1256,6 +1267,8 @@ end
1256
1267
  # Loop-phase declarations above sort the architect help listing; its namespaces
1257
1268
  # (brief/worktree/variant/research) declare no phase and list under this header.
1258
1269
  Space::Core::CLI::Help.trailing_group_label = "Groups"
1270
+ Space::Core::CLI::Help.product_name = "architect"
1271
+ Space::Core::CLI::Help.product_version = Space::Architect::VERSION
1259
1272
 
1260
1273
  Space::Architect::CLI::Registry.register "init", Space::Architect::CLI::Architect::Init
1261
1274
  Space::Architect::CLI::Registry.register "ground", Space::Architect::CLI::Architect::Ground
@@ -33,21 +33,11 @@ module Space::Architect
33
33
  end
34
34
 
35
35
  if VERSION_REQUEST.include?(argv)
36
- out.puts Space::Core::VERSION
36
+ out.puts Space::Architect::VERSION
37
37
  return 0
38
38
  end
39
39
 
40
- if argv.first == "src"
41
- return dispatch_src(argv[1..], out, err)
42
- end
43
-
44
- normalized = normalize_args(argv)
45
-
46
- if normalized.first == "space"
47
- return dispatch_space(normalized[1..], out, err)
48
- end
49
-
50
- Dry::CLI.new(Registry).call(arguments: normalized, out: out, err: err)
40
+ Dry::CLI.new(Registry).call(arguments: normalize_args(argv), out: out, err: err)
51
41
  last_outcome&.exit_code || 0
52
42
  end
53
43
 
@@ -88,6 +78,13 @@ module Space::Architect
88
78
  end
89
79
 
90
80
  def self.run(argv, out = $stdout, err = $stderr)
81
+ # One-shot 8.x app-dir migration (the substrate's config/state, owned by
82
+ # Space::Core::Migration in space-cadet) before dispatch — skipped for
83
+ # the pure help/version queries so they stay side-effect-free. Running it
84
+ # here too means `architect` picks up an 8.x user's config even if they
85
+ # never ran `space` first.
86
+ Space::Core::Migration.run(err: err) unless TOP_LEVEL_HELP.include?(argv) || VERSION_REQUEST.include?(argv)
87
+
91
88
  Kernel.exit(call(argv, out, err))
92
89
  rescue Interrupt
93
90
  err.puts "interrupted"
@@ -97,6 +94,4 @@ module Space::Architect
97
94
  end
98
95
 
99
96
  require_relative "cli/architect"
100
- require_relative "cli/space"
101
- require_relative "cli/src"
102
97
  require_relative "cli/research"
@@ -5,7 +5,7 @@ require "open3"
5
5
  module Space::Architect
6
6
  module SessionSync
7
7
  # Resolves the absolute path to the `architect` executable the plist
8
- # should invoke, imitating Space::Src::CLI::Daemon::Helpers::Resolve's
8
+ # should invoke, imitating RepoTender::CLI::Daemon::Helpers::Resolve's
9
9
  # detect_bin_path precedence: an env override (tests), the dev checkout's
10
10
  # exe/architect, `which architect`, then the installed gem's bin.
11
11
  module BinPath
@@ -6,7 +6,7 @@ require "fileutils"
6
6
  module Space::Architect
7
7
  module SessionSync
8
8
  # Machine-managed cursor at $XDG_STATE_HOME/space-architect/session-sync.yaml
9
- # (imitates Space::Src::State::Store's load/write/emit shape). Keyed by
9
+ # (imitates RepoTender::State::Store's load/write/emit shape). Keyed by
10
10
  # absolute source path; each entry records the size + mtime observed the
11
11
  # last time that file was uploaded.
12
12
  class Cursor
@@ -3,7 +3,7 @@
3
3
  module Space::Architect
4
4
  module SessionSync
5
5
  # Hand-rolled launchd plist emitter for the session-sync agent, imitating
6
- # Space::Src::Launchd::Plist's shape. Under launchd's bare PATH, a bare
6
+ # RepoTender::Launchd::Plist's shape. Under launchd's bare PATH, a bare
7
7
  # env-relative ruby binstub shebang resolves to macOS system Ruby instead
8
8
  # of the caller's toolchain, so ProgramArguments names the interpreter
9
9
  # explicitly (ruby_bin) rather than relying on shebang resolution — no
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Space
4
- module Core
5
- VERSION = "8.0.0"
4
+ module Architect
5
+ VERSION = "9.0.0"
6
6
  end
7
7
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "space_core"
4
- require "space_src"
4
+ require_relative "space_architect/version"
5
5
 
6
6
  require_relative "space_architect/harness"
7
7
  require_relative "space_architect/run_creator"
@@ -151,8 +151,9 @@ loop.
151
151
  an iteration index pointing at each iteration file; per-iteration detail lives
152
152
  in the iteration file, never duplicated into the handoff. `architect status`
153
153
  prints project state (iterations, freeze_shas, lanes, verdicts) at any point.
154
- - **Space setup (first time):** `architect space new "Project Name" -r org/repo -r …`
155
- (each repo is a repeatable `-r` flag after the title), then `architect init` inside
154
+ - **Space setup (first time):** `space new "Project Name" -r org/repo -r …`
155
+ (the space-cadet binary; each repo is a repeatable `-r` flag after the title),
156
+ then `architect init` inside
156
157
  the space to scaffold `architecture/ARCHITECT.md`.
157
158
  - Scale to the task: trivial fixes don't need the loop — say so and let the
158
159
  human do it inline or in a normal session. The loop is for iteration-sized
@@ -131,8 +131,8 @@ Safe **read-only** commands to orient yourself (these don't run the loop):
131
131
 
132
132
  ```sh
133
133
  architect status # project state: iterations, freeze shas, lanes, verdicts
134
- architect space show # the space you're standing in
135
- architect space list # all your spaces
134
+ space show # the space you're standing in (space-cadet binary)
135
+ space list # all your spaces
136
136
  ```
137
137
 
138
138
  ## Maintenance