Git-native CLI for the Wazoo multi-repo workspace.
wspace is a small, git-native CLI that manages a multi-repo Wazoo workspace
without Git submodules. It keeps the working rules in one place and makes them
enforceable from the terminal.
Design principles:
- Thin over custom. Prefer plain
gitporcelain/plumbing and well-known directory conventions over bespoke state files. The workspace layout is encoded in a singleworkspace.jsonmanifest. - Conservative mutation. Commands that write or move state (update, update
refuses to touch dirty repositories, feature branches, missing repos, or
unmanaged checkouts.
updateonly fetches and fast-forwards clean default branches; it never resets, rebases, stashes, or rewrites history. When the workspace root is itself a git checkout,updatetreats it like any other clean default branch andcheckreports it as(workspace root). The root's dirty probe ignores untracked files, so its ownrepos/andworktrees/contents never mark it dirty. Scoped runs (--workspace <name>) leave the root out entirely. - Machine-readable output.
check --jsonemits structured results for tools; plain output is for humans. - Exit code contract.
wspace checkexits0when the workspace is clean and1when any repository is dirty, diverged, missing, or otherwise not in sync.
wspace check— read-only baseline check. ReportsCLEAN,DIRTY,FEATURE_CLEAN,DIVERGED,UNKNOWN,MISSING, andUNMANAGEDstates. When the workspace root directory is itself a git checkout, it is reported first as(workspace root)and non-clean states fail the check. Untracked files at the root never count as dirty, and--workspace <name>checks only the named sub-workspace.wspace init [--host <host>] [--owner <owner>] [<repo...>]— one-time scaffold for an empty directory: writes a freshworkspace.json(schema v4) with optional host/owner and seeded shorthand entries, and creates the standardrepos/directory. Fails closed if any manifest already exists.wspace install [<repo...>]— clone missing repositories from the manifest (or only a specified subset of repos). Prints a warning that fresh clones lack gitignored files and repo-specific setup.wspace add [<name>] [--url <url>] [--name <n>] [--as-workspace] [--create] [--visibility <public|private>]— append an entry to the manifest: a bare orowner/nameshorthand string, or an object entry via--url(name defaults to the URL basename, overridable with--nameor a positional name). Edits are surgical manifests survive. GitHub shorthand entries are probed withgh; pass--createto create a missing repository first (default private). Nothing is cloned; runwspace install <name>afterwards.wspace remove <repo>— delete the entry whose effective name matches. Surgical edit; local checkouts are never deleted.wspace update— fetch remotes and fast-forward only clean default branches, including the workspace root's own checkout when it is a git repository. Untracked workspace content (repos/,worktrees/) does not mark the root dirty.--workspace <name>updates only the named sub-workspace and leaves the root out.wspace validate— validate the manifest without touching any repository.wspace workspaces [--json]— list discovered sub-workspaces with repo counts.check,install, andupdateaccept--workspace <name>to scope the command to one sub-workspace.
A manifest keeps ordinary repositories and workspace repositories in separate
arrays. Workspace checkouts live in workspacesDirectory when it is set;
otherwise they share repositoriesDirectory with ordinary repositories. Both
arrays accept the same shorthand and object entry forms. A workspaces entry is
cloned at <workspacesDirectory>/<name> (or <repositoriesDirectory>/<name>
when unset) and must contain a valid workspace.json manifest; its child
repositories use that child manifest's own repos/ directory. This makes the
checkout location deterministic without guessing whether a repository is also a
workspace.
{
"schemaVersion": 4,
"owner": "acme",
"workspacesDirectory": "workspaces",
"repositories": ["shared-reference"],
"workspaces": ["platform-workspace"]
}Shorthand rules: owner/name overrides the top-level owner per entry; exactly
one slash is allowed; and url and owner are mutually exclusive on object
entries.
Use wspace add --as-workspace to add a workspace entry. install and check
verify that declared workspace repositories contain a valid child manifest, and
commands report ordinary repositories and workspace repositories without
collisions.
wspace install clones all missing entries from both arrays. A declared
workspace is validated as a Git repository containing workspace.json; once
present, its child repositories are resolved against that child workspace's own
repos/ directory. --workspace <name> scopes operations to repositories owned
by that child workspace.
Schema v4 keeps ordinary repositories and workspace repositories in separate
arrays. This is intentional: repositoriesDirectory remains the source of truth
for ordinary checkout locations, and the optional workspacesDirectory
separates workspace checkouts when the manifest declares one. The arrays use the
same shorthand and object entry forms, and names must be unique across both
arrays.
An ordinary repository's local checkout directory is always
<repositoriesDirectory>/<name>; a workspace repository's is
<workspacesDirectory>/<name> when configured, otherwise
<repositoriesDirectory>/<name>. name is the post-expansion label: ownership
and hosts live in URLs, never in paths. Names therefore cannot contain slashes,
backslashes, or path traversal. Two entries conflict only when they resolve to
the same checkout path — including a shorthand colliding with another entry's
expanded name within one workspace. The same name may appear in different
workspaces because each workspace's checkouts live in its own directory
(./workspaces/wazootech/repos/memory and ./repos/memory can coexist).
To check out a repository under a different label than its shorthand name, write
the explicit form with your chosen label as name:
{
"name": "wazootech__memsdk",
"url": "https://github.com/wazootech/memsdk.git"
}The aliased copy is an ordinary explicit-url entry.
Manifest discovery has been simplified to workspace.json only. The
wspace.json and repos.json filename fallbacks and .yaml / .yml format
support have been removed. Migrate by renaming your manifest file to
workspace.json and converting any YAML manifests to JSON. The CLI auto-detects
the manifest by walking up from the current directory (like
git rev-parse --show-toplevel). Pass --manifest <path> to override
auto-detection.
The wspace agent skill packages the same workspace
discipline into a loadable skill for coding agents (Claude Code, Cursor,
OpenCode, Gemini, and others). It is not a thin wrapper around the CLI — it
encodes a set of opinionated software engineering practices that apply to any
multi-repo workspace:
- Worktree isolation as default. The skill makes "never edit the canonical checkout" the only path, not an opt-in. Eliminates an entire class of "oops I was on main" incidents across any multi-repo setup.
- Single-round-trip discovery.
wspace check --jsonreplaces per-repolsandgit statusprobing. Fewer tool calls means faster time to the first useful action and less context consumed per session. - Pipeline with verifiable exit conditions. Each step ends on a checkable artifact — a clean worktree, green CI, a merged PR — not agent reasoning about whether things look right.
- Goal loop with hard boundaries. The FRAME-SCAN-CLAIM-EXECUTE-REFLECT loop, with deploy, publish, and human-in-the-loop hard stops, is a reusable autonomy pattern for driving any multi-repo backlog to completion.
- Token and context economy. Batch commands into single shell calls, hand off plan artifacts between phases (not full conversations), and leave per-repo command syntax in reference files loaded on demand.
npx skills add wazootech/workspace-cli@wspaceThe skill reads the workspace manifest and CLI the same way a human would — but it never needs to be taught the conventions twice.
Install from JSR as the wspace binary:
deno install -g -A --name wspace jsr:@wazoo/workspace/cliUse the /cli subpath export — the runnable CLI entry — not the bare
jsr:@wazoo/workspace package (which exposes the library and produces a no-op
wspace when installed globally). -A grants the read/write/run permissions
wspace needs; omit it if you prefer to grant specific flags (e.g.
--allow-read --allow-write --allow-run=git) or use Prompts.
Or build a local binary:
deno task buildRequires a Deno runtime (v2+). The wspace binary has no runtime dependencies.
deno task ciRuns deno fmt --check, deno lint, deno check, and deno test (includes
integration tests against real local git repositories).