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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +54 -0
- data/README.md +53 -243
- data/lib/space_architect/bug_report.rb +2 -1
- data/lib/space_architect/cli/architect.rb +20 -7
- data/lib/space_architect/cli.rb +9 -14
- data/lib/space_architect/session_sync/bin_path.rb +1 -1
- data/lib/space_architect/session_sync/cursor.rb +1 -1
- data/lib/space_architect/session_sync/plist.rb +1 -1
- data/lib/{space_core → space_architect}/version.rb +2 -2
- data/lib/space_architect.rb +1 -1
- data/skill/architect/SKILL.md +3 -2
- data/skill/architect-vocabulary/SKILL.md +2 -2
- metadata +18 -177
- data/exe/space +0 -13
- data/exe/src +0 -13
- data/lib/space_architect/cli/space.rb +0 -29
- data/lib/space_architect/cli/src.rb +0 -38
- data/lib/space_core/atomic_write.rb +0 -21
- data/lib/space_core/cli/base_command.rb +0 -19
- data/lib/space_core/cli/build.rb +0 -27
- data/lib/space_core/cli/config.rb +0 -49
- data/lib/space_core/cli/current.rb +0 -16
- data/lib/space_core/cli/help.rb +0 -195
- data/lib/space_core/cli/helpers.rb +0 -115
- data/lib/space_core/cli/init.rb +0 -29
- data/lib/space_core/cli/list.rb +0 -24
- data/lib/space_core/cli/loop_status.rb +0 -47
- data/lib/space_core/cli/new.rb +0 -38
- data/lib/space_core/cli/pack.rb +0 -29
- data/lib/space_core/cli/path.rb +0 -16
- data/lib/space_core/cli/repeatable_options.rb +0 -84
- data/lib/space_core/cli/repo.rb +0 -76
- data/lib/space_core/cli/run.rb +0 -44
- data/lib/space_core/cli/shell.rb +0 -125
- data/lib/space_core/cli/show.rb +0 -21
- data/lib/space_core/cli/status.rb +0 -74
- data/lib/space_core/cli/use.rb +0 -17
- data/lib/space_core/cli.rb +0 -177
- data/lib/space_core/commands.rb +0 -51
- data/lib/space_core/config.rb +0 -152
- data/lib/space_core/errors.rb +0 -14
- data/lib/space_core/git_client.rb +0 -49
- data/lib/space_core/mise_client.rb +0 -37
- data/lib/space_core/oci_builder.rb +0 -56
- data/lib/space_core/oci_packer.rb +0 -103
- data/lib/space_core/oci_runner.rb +0 -89
- data/lib/space_core/paths.rb +0 -58
- data/lib/space_core/repo_reference.rb +0 -19
- data/lib/space_core/repo_resolver.rb +0 -167
- data/lib/space_core/shell_integration.rb +0 -438
- data/lib/space_core/slugger.rb +0 -16
- data/lib/space_core/space.rb +0 -174
- data/lib/space_core/space_store.rb +0 -319
- data/lib/space_core/state.rb +0 -86
- data/lib/space_core/templates/oci/dockerfile.erb +0 -73
- data/lib/space_core/templates/oci/dockerignore.erb +0 -17
- data/lib/space_core/templates/oci/entrypoint.sh.erb +0 -16
- data/lib/space_core/terminal.rb +0 -161
- data/lib/space_core/warnings.rb +0 -13
- data/lib/space_core/xdg.rb +0 -33
- data/lib/space_core.rb +0 -26
- data/lib/space_src/cli/clone.rb +0 -54
- data/lib/space_src/cli/config.rb +0 -65
- data/lib/space_src/cli/daemon.rb +0 -362
- data/lib/space_src/cli/options.rb +0 -21
- data/lib/space_src/cli/org.rb +0 -199
- data/lib/space_src/cli/repo.rb +0 -169
- data/lib/space_src/cli/shell.rb +0 -121
- data/lib/space_src/cli/status.rb +0 -75
- data/lib/space_src/cli/sync.rb +0 -161
- data/lib/space_src/cli.rb +0 -159
- data/lib/space_src/cloner.rb +0 -77
- data/lib/space_src/config/contract.rb +0 -54
- data/lib/space_src/config/duration.rb +0 -79
- data/lib/space_src/config/model.rb +0 -49
- data/lib/space_src/config/store.rb +0 -156
- data/lib/space_src/forge/client.rb +0 -31
- data/lib/space_src/forge/github.rb +0 -98
- data/lib/space_src/launchd/agent.rb +0 -195
- data/lib/space_src/launchd/plist.rb +0 -129
- data/lib/space_src/log_rotator.rb +0 -46
- data/lib/space_src/migration.rb +0 -43
- data/lib/space_src/nav.rb +0 -99
- data/lib/space_src/paths.rb +0 -72
- data/lib/space_src/scm/client.rb +0 -87
- data/lib/space_src/scm/git.rb +0 -232
- data/lib/space_src/scm/status.rb +0 -24
- data/lib/space_src/shell.rb +0 -90
- data/lib/space_src/shell_integration.rb +0 -321
- data/lib/space_src/state/lock.rb +0 -59
- data/lib/space_src/state/store.rb +0 -140
- data/lib/space_src/sync/engine.rb +0 -503
- data/lib/space_src/sync/repo_plan.rb +0 -215
- data/lib/space_src/sync/report.rb +0 -18
- data/lib/space_src/ui/interactive_reporter.rb +0 -280
- data/lib/space_src/ui/json_reporter.rb +0 -39
- data/lib/space_src/ui/mode.rb +0 -68
- data/lib/space_src/ui/plain_reporter.rb +0 -53
- data/lib/space_src/ui/reporter.rb +0 -48
- data/lib/space_src/version.rb +0 -7
- data/lib/space_src.rb +0 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 02caeb5cc690ab3d847e54fed5eb88c1493fa2402ace662ef7f25d2aeb4d055b
|
|
4
|
+
data.tar.gz: 5fa1fc73aaf8e912a74b1daf36e392c4d8afdc19cf1e6af22cc94702ef4146fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
[](https://badge.fury.io/rb/space-architect)
|
|
4
4
|
|
|
5
|
-
> **
|
|
5
|
+
> **The Architect Loop — structured judgment-and-build cycles for humans and their agents!** ✨🛰️
|
|
6
6
|
|
|
7
|
-
`space-architect` is
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
12
|
+
It installs **one executable**, `architect`. The spaces substrate and the
|
|
13
|
+
evergreen-checkout engine live in two sibling gems:
|
|
13
14
|
|
|
14
|
-
|
|
|
15
|
-
|
|
16
|
-
|
|
|
17
|
-
|
|
|
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
|
-
|
|
21
|
-
and `architect
|
|
22
|
-
|
|
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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
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"
|
|
72
|
-
space
|
|
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
|
-
|
|
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
|
-
|
|
407
|
-
space
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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
|
-
|
|
273
|
+
Two namespaces, published as two gems:
|
|
462
274
|
|
|
463
|
-
- **`Space::Core`** — the
|
|
464
|
-
clients, the space store. The `space` CLI runs on this
|
|
465
|
-
- **`Space::Architect`** — project state, the builder harness,
|
|
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
|
|
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 📖
|
|
@@ -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 —
|
|
16
|
-
#
|
|
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::
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
data/lib/space_architect/cli.rb
CHANGED
|
@@ -33,21 +33,11 @@ module Space::Architect
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
if VERSION_REQUEST.include?(argv)
|
|
36
|
-
out.puts Space::
|
|
36
|
+
out.puts Space::Architect::VERSION
|
|
37
37
|
return 0
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
|
|
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
|
|
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
|
|
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
|
-
#
|
|
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
|
data/lib/space_architect.rb
CHANGED
data/skill/architect/SKILL.md
CHANGED
|
@@ -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):** `
|
|
155
|
-
(each repo is a repeatable `-r` flag after the title),
|
|
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
|
-
|
|
135
|
-
|
|
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
|