Workspaces¶
Every run of zordon happens in a workspace. The project root is the
implicit workspace main; you can spin up more, each a fully isolated
copy of the whole stack over the same Alphasfile — its own state
dir, its own pickport() draws, its own per-service git worktree
checkouts, its own alpha.
zordon workspace create feature # checks out every workspace-able
# service into workspaces/feature
zordon workspace create feature api # only `api` (others run from upstream)
zordon workspace create feature api@v2 # …pin `api` to revision v2
cd workspaces/feature
zordon start # walks up, adopts ../../../Alphasfile
# as the leaf — but as workspace "feature"
zordon workspace list
zordon workspace service add --workspace=feature --services=api # add a checkout
zordon workspace service rm --workspace=feature --services=api # drop one
zordon workspace rm feature
create vs start. zordon workspace create <name> [svc[@rev] …]
materializes the editable source: it git worktree adds each picked
service (or all workspace-able services with no args) into
workspaces/<name>/src/<svc> on a branch zordon/<name>. For a
git primary this bare-clones first; for a src primary it adds a
workspace from your local repo (registered in your repo's .git, so
your IDE / git worktree list sees it). zordon start then runs the
whole stack, reusing those checkouts (and lazily creating any missing
ones).
Per-service add/rm. To adjust an existing workspace without recreating it, zordon workspace service add --workspace=<name> --services=<svc[@rev],…> materializes more service checkouts (on the same branch and path start expects), and zordon workspace service rm --workspace=<name> --services=<svc,…> detaches them (the git worktree is removed and its tree deleted).
Both reject --workspace=main, which has no per-service checkout.
zordon start from workspaces/<name>/ walks up, finds the
project's Alphasfile, and adopts it as the leaf — same file on disk,
different invocation. Every level carries two short hashes:
fs::hash()—sha(invocation_dir). Identifies which alpha instance this is; names the socket / tmp dir.mainandfeatureget distinctfs::hash()⇒ distinct sockets, state dirs, and freshpickport()values — they run side by side without colliding.cfg::hash()—sha(alphasfile_bytes + parent_context). Identifies the manifest content. Changes when you edit the Alphasfile (or a parent's resolved services change). Drives federation drift detection.
zordon status shows each level's fs::hash().
Each workspace-able service is materialized via git worktree add from
its primary and built there, so editing code in one workspace's checkout
doesn't touch another's. If the branch zordon/<name> is already
checked out at a different path, you get a clear error (remove that
workspace or point this one elsewhere) instead of a raw git failure.
Federation parents (below) are reused across workspaces — only the
leaf forks.
Partial checkout (sparse)¶
For a big monorepo you rarely want the whole tree. A workspace { sparse
= [...] } block makes the checkout a git sparse cone, materializing
only the listed directories (paths relative to the primary repo root):
service "go" "example" {
src {
path = "../.." # primary = the repo this file is in
exe = "./examples/workspace/src/example" # build target, repo-root-relative
}
vars = { port = net::pickport() }
workspace {
sparse = ["examples/workspace/src/example"]
}
runtime {
cmd = ["${fs::bin()}/example", "-addr", "127.0.0.1:${self.vars.port}"]
}
}
The checkout then holds only that subtree — plus the repo's top-level
files (go.mod, go.sum, …). That's inherent to git cone mode and
desirable: go.mod at the module root is needed to build anyway. See
examples/workspace.
Main use case: an AI agent gets a sandbox next to the developer's stack; derivatives: parallel experiments, A/B-testing two revisions. For async isolation, keep the broker (NATS/Kafka/…) in the project Alphasfile, not the global parent — then each workspace gets its own bus.