Space Architect π
Task-scoped workspaces that double as Architect Loop missions β for humans and their agents! β¨π°οΈ
space-architect is a Ruby toolkit for spaces β task-scoped project
workspaces that hold repos, notes, and artifacts under one obvious filesystem
root β fused with the Architect Loop: a structured judgment-and-build cycle
for you and a fleet of headless AI builders. π
The gem ships three composable binaries over clean library seams:
| Binary | What it does | Library |
|---|---|---|
space πͺ |
Create and manage task-scoped workspaces | Space::Core |
architect ποΈ |
Run the Architect Loop β judgment + headless builders | Space::Architect |
src π² |
Tend evergreen repo checkouts for copy-on-write provisioning | Space::Src |
Each is a first-class executable. architect also forwards architect space β¦
and architect src β¦ to the other two, so a mission can drive everything from
one command when that's handier. π
What's a space? πͺ
A space is just a regular directory with a tiny YAML identity file and room for everything a task needs:
~/architect/spaces/20260531-name-of-space/
space.yaml # identity: id, title, status, repos, notes, tags
README.md
repos/ # cloned (or copy-on-write'd) repositories
notes/ # scratch, prompts, logs
architecture/ # iteration files: I<NN>-<name>.md + ARCHITECT.md index + BRIEF.md
build/ # lane worktrees + scratch (build/<id>-<lane>/)
tmp/ # workspace-local temp β use this instead of /tmp
Run a command from anywhere inside a space and it just works β space and
architect walk up from $PWD until they find the nearest space.yaml. No
"current space" state to get out of sync; where you are is the space you
mean. π§
Installation π¦
Add it to your Gemfile:
gem "space-architect"
bundle install
Or grab it yourself:
gem install space-architect
The gem is space-architect; it installs three executables β space,
architect, and src. π
Quick start π
# Spaces
space init # create XDG config + state files
space new "Name of Space" # blast off a new space π
space new "Name of Space" -r org/repo -r org/lib # β¦with repos cloned in (repeat -r)
space list # see all your spaces
space show # show the space you're standing in
# Evergreen checkouts (copy-on-write sources for fast provisioning)
src repo add github.com/example-org/example-app # tend it π²
src sync # one sync pass
src status # per-repo evergreen status
# Architect Loop (run from inside a space)
architect install-skills # install agent skills (once per machine)
architect init # scaffold ARCHITECT.md + architecture/
architect new my-feature # scaffold the next iteration file
architect freeze my-feature # lock the Acceptance Criteria βοΈ
architect dispatch my-feature lane-a # send a headless builder to work
space β task-scoped workspaces π
space init
space new "Name of Space"
space new "Name of Space" -r org/repo -r example-tools/alpha -r example-tools/beta
space list # alias: space ls
space show 20260531-name-of-space
space path 20260531-name-of-space
space current # based on $PWD
space show # based on $PWD
space status done # based on $PWD
space status 20260531-name-of-space done
space config set default_provider github.com
space config set default_organization example-org
space repo add example-app # github.com/example-org/example-app
space repo add example-tools/alpha example-tools/beta
space repo add gitlab.com/example-org/api
space repo resolve example-app example-tools/async
space repo ls # alias: space repos ls
space use 20260531-name-of-space # records recent state, prints the path
space ls --color=always # auto | always | never (--colors also accepted)
Repos are passed with a repeatable -r flag (-r org/repo -r org/lib); the
comma form (-r a,b) works too. Space ids are date-prefixed
(20260531-name-of-space) so they sort naturally, and duplicate names on the
same day get a counter (β¦-name-of-space-2). π
Everything space does is also reachable as architect space β¦ from within a
mission.
src β the evergreen engine π²
src keeps local clones under <src_dir>/<host>/<owner>/<repo> (default
~/architect/src/β¦) clean, on their default branch, and freshly fetched β so
spaces can provision repos by copy-on-write instead of cloning over the
network.
src repo add github.com/example-org/example-app # track + tend a repo
src org add github.com/example-org # track a whole org
src sync # run one sync pass (--repo to scope)
src status # per-repo evergreen status table
src clone example-app # APFS copy-on-write into $PWD
src daemon install # per-user launchd agent for background sync
When space repo add finds a matching evergreen checkout, it copy-on-writes
from it instead of hitting the network β instant provisioning. β‘ The two
surfaces share one layout by design, so they line up with zero configuration:
src repo add github.com/example-org/example-app # tend it: keep it evergreen π²
space repo add example-app # copies it instantly β‘
src has its own --plain / --json output modes for scripting, and its own
fish integration (src shell fish install).
architect β the Architect Loop ποΈ
The Architect Loop is a structured build cycle for you and headless AI builders. Each loop lives inside a space as a mission.
Roles:
- Architect β you (or Claude Opus 4.8 in judgment mode): arbitrates disagreements, writes and freezes iteration files, calls kill/continue, merges builder output. Never writes implementation code.
- Builder β Claude Sonnet 4.6 run headless via
architect dispatch, one per lane in its own git worktree: reads the iteration's Builder Prompt, does the work, writes raw evidence tobuild/<id>-<lane>/report.md. Never grades its own work; never editsarchitecture/.
Filesystem layout:
architecture/
ARCHITECT.md # cross-iteration index; mission-wide state
BRIEF.md # durable Β§-numbered mission contract (optional)
I01-<iteration>.md # one self-contained file per iteration
build/
I01-<iteration>-<lane>/ # lane worktree + scratch per dispatch
run.jsonl # streamed builder output
report.md # builder report (transcribed into the iteration file verbatim)
Iteration file anatomy β one file, grown section by section. You author the content; the CLI owns the persistence (each command writes the section, commits it with the canonical message, and prints back what changed):
| Section | Holds | How you persist it |
|---|---|---|
## Grounds |
why β research / brief distilled (optional) | architect section <it> grounds --from <f> |
## Specification |
what/how β the full delegation contract | architect section <it> specification --from <f> |
## Acceptance Criteria |
proof β exact gate commands + thresholds | architect freeze <it> βοΈ |
## Builder Prompt |
the exact lane-prompt(s) dispatched | architect section <it> prompt --append --lane <l> --from <f> |
## Builder Report |
raw evidence, transcribed verbatim | architect evidence <it> --lane <l> |
## Verdict |
rulings + per-AC PASS/FAIL + KILL/CONTINUE | architect section <it> verdict --from <f> |
The freeze βοΈ β architect freeze <iteration> commits the frozen region
(Grounds / Specification / Acceptance Criteria), records the freeze_sha, and
prints the frozen Acceptance Criteria back. Any change to those sections
afterward is an automatic iteration FAIL. The builder never edits the iteration
file.
Command surface:
architect init # scaffold ARCHITECT.md + the space.yaml architect: block
architect brief new # scaffold the durable mission BRIEF.md
architect new <iteration> # scaffold architecture/I<NN>-<iteration>.md
architect section <it> <section> --from <f> # write + commit a section
architect freeze <iteration> # freeze the Acceptance Criteria βοΈ
architect worktree add <repo> <it> <lane> # isolated worktree per lane (2β4 lanes)
architect dispatch <it> <lane> # dispatch a builder (add --detach to survive long runs)
architect verify <iteration> # post-flight mechanical checks (reports only)
architect evidence <it> --lane <lane> # transcribe the builder's report verbatim
architect gate <iteration> # run the frozen gate commands, stream raw output
architect merge <it> <lane> # integrate ONE judged-passing lane (--no-ff)
architect integrate <it> --lanes a,b # integrate a set of passing lanes, in order
architect status # mission state (read-only)
architect variant add|compare|promote β¦ # competing (harness, model) lanes over one frozen spec
architect research dispatch|status|wait β¦ # parallel read-only research lanes (see below)
A typical session:
architect init # first time
architect new my-feature # scaffold I01-my-feature.md
architect section my-feature specification --from spec.md
architect freeze my-feature # lock it βοΈ
architect dispatch my-feature lane-a --detach # send a builder; poll the report
architect verify my-feature # mechanical post-flight checks
architect evidence my-feature --lane lane-a # transcribe raw evidence
architect gate my-feature # run the frozen gates yourself
# β¦ read the diff against the spec, then write the Verdict β¦
Streaming builder output π‘
architect dispatch can push the builder's stream-json to an ingest server for
live viewing:
# Push to an already-created run (you supply the full ingest URL):
architect dispatch my-feature lane-a \
--push-url $HOST/runs/<id>/ingest \
--push-token $INGEST_TOKEN
# Create a run and push in one step (requires --push-token = server's INGEST_TOKEN):
architect dispatch my-feature lane-a \
--push-host $HOST \
--push-token $INGEST_TOKEN
--push-host POSTs to <HOST>/runs, parses the new run id from the 201
response, derives <HOST>/runs/<id>/ingest, and streams there; the created run
id and ingest URL are printed after dispatch starts. --push-url and
--push-host are mutually exclusive, both require --push-token, and neither
can be combined with --detach (the push tees the live pipe in-process).
Research lanes π
When an iteration needs facts the repo doesn't already have, fan out parallel
read-only research lanes β detached claude -p researchers (no
Edit/Write/Bash) that you supervise:
architect research dispatch 01-official-api.prompt.md 02-changelog.prompt.md
architect research wait # tails each lane's run.jsonl; --level 1-4, --quiet, --thinking
architect research status # status of dispatched runs
Researchers gather; the architect verifies the load-bearing claims against sources and writes the iteration's Grounds section.
Skills π§
architect install-skills installs the bundled architect,
architect-research, and architect-vocabulary skills for your harness:
architect install-skills # default: claude (~/.claude/skills/)
architect install-skills --provider opencode # or codex | pi
architect install-skills --project # into ./β¦ instead of globally
architect install-skills --dry-run # show what would change
architect-vocabulary loads the system's terms and a short orientation when
you're in a space but don't want to run the loop.
Fish shell integration π
Shells can't let a child process change their working directory, so space
and src each ship a small fish wrapper function plus completions (commands,
subcommands, spaces, statuses, config keys, repo refs). Install into fish's
autoloaded directories:
space shell fish install
src shell fish install
exec fish
After restarting fish (or exec fish), space new "β¦" and
space use <id> will cd into the selected space once the command succeeds;
every other command keeps normal CLI behavior. πͺ The functions and completions
are written under ~/.config/fish/, so there's no need to edit config.fish.
For one-off testing without installing:
space shell init fish | source
Configuration βοΈ
Config lives at ~/.config/space-architect/config.yml (XDG-aware) and defaults to:
version: 1
base_dir: ~/architect # spaces_dir + src_dir hang off this by default
default_provider: github.com
default_organization:
git_clone_protocol: ssh # ssh | https
Derived defaults: spaces_dir β <base_dir>/spaces, src_dir (evergreen
checkout root) β <base_dir>/src. Override either explicitly. View values with
space config show; set one with space config set KEY VALUE. Editable keys:
base_dir, spaces_dir, src_dir, default_provider, default_organization,
git_clone_protocol.
Repos: evergreen, copy-on-write, concurrent β‘
Repos are added to the current space under repos/ and tracked in space.yaml.
When an up-to-date evergreen checkout exists at
<src_dir>/<host>/<owner>/<name> (e.g.
~/architect/src/github.com/example-org/example-app), space copies it into the
space instead of cloning over the network β a copy-on-write clone on APFS. β‘
Set src_dir empty to always clone:
space config set src_dir ""
Clone URLs default to SSH (git@github.com:example-org/example-app.git); switch
with space config set git_clone_protocol https. Multiple repos passed to
space repo add are fetched concurrently, up to five at a time, on fibers β
no threads, all cooperative. π§΅ After each repo lands, space runs mise trust
in it. Each space also gets a workspace-local tmp/ β use it instead of /tmp.
Embedding π
The library is split into three namespaces you can require independently:
Space::Coreβ the foundation: config, state, XDG, terminal, git/mise clients, the space store. ThespaceCLI runs on this alone.Space::Architectβ mission state, the builder harness, dispatch, and the research supervisor.Space::Srcβ the evergreen engine (tracking, sync, copy-on-write clone).
require "space_core" # just spaces
require "space_architect" # the full loop (pulls in core + src)
require "space_src" # just the evergreen engine
Documentation π
- Command Reference β every command, flag, and behavior
- Design β why spaces and the Architect Loop exist, and how they're shaped
- Changelog β release history
Development π οΈ
bundle install
bundle exec rake test # the full minitest suite
bundle exec rake build # build the gem into pkg/
bundle exec rake install # build + install into your user gem home
Contributing π
Bug reports and pull requests are welcome on GitHub at https://github.com/jetpks/space-architect!
License π
Available as open source under the terms of the MIT License.
Made with π and fibers π§΅ by Eric