Space Architect πŸš€

Gem Version

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 to build/<id>-<lane>/report.md. Never grades its own work; never edits architecture/.

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. The space CLI 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