0.0
The project is in a healthy, maintained state
A dry-cli CLI for spaces: date-prefixed directories with a YAML identity file, $PWD-based current-space resolution, and XDG config/state. Provisions repos at copy-on-write speed from evergreen checkouts (pairs with repo-tender), concurrently on fibers. Ships fish shell integration and completions.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 6.0
~> 13.0

Runtime

~> 2.39
~> 1.4
~> 1.10
~> 1.16
~> 1.9
~> 0.8
~> 10.2
 Project Readme

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