From f57f57bc33234de6dc2fca13a05d4c52f85f7c15 Mon Sep 17 00:00:00 2001 From: Ethan Davidson <31261035+EthanThatOneKid@users.noreply.github.com> Date: Tue, 11 Aug 2026 10:06:17 -0700 Subject: [PATCH 1/5] feat: add wspace agent skill --- deno.json | 2 +- skills/wspace/SKILL.md | 97 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 skills/wspace/SKILL.md diff --git a/deno.json b/deno.json index c71da3d..96c083d 100644 --- a/deno.json +++ b/deno.json @@ -20,6 +20,6 @@ "test": "deno test --allow-read --allow-write --allow-run" }, "publish": { - "include": ["src/", "schema/", "LICENSE", "README.md"] + "include": ["src/", "schema/", "skills/", "LICENSE", "README.md"] } } diff --git a/skills/wspace/SKILL.md b/skills/wspace/SKILL.md new file mode 100644 index 0000000..65e1347 --- /dev/null +++ b/skills/wspace/SKILL.md @@ -0,0 +1,97 @@ +--- +name: wspace +description: Manage multi-repo Wazoo workspaces, feature worktrees, conservative default-branch updates, and secret sync using the git-native wspace CLI. Use when managing multi-repo workflows, creating or removing feature worktrees, checking workspace baseline health, syncing environment secrets, or running wspace commands. +--- + +# `wspace` Workspace Skill + +Use this skill to orchestrate multi-repo development, isolate tasks in Git +worktrees, refresh default branch baselines safely, and synchronize environment +secrets using `wspace` (the Wazoo Workspace CLI). + +## Quick Start + +Execute all workspace commands from the workspace root (where `repos.json` +resides): + +```sh +# 1. Inspect workspace baseline health +wspace check + +# 2. Fast-forward clean default branches safely +wspace update + +# 3. Create isolated feature worktree anchored to origin/ +wspace worktree add +# (Or using raw git): git -C repos/ worktree add "$PWD/worktrees//" -b + +# 4. Propagate local secrets to checkouts and worktrees +wspace env sync + +# 5. Push branch & open PR (from inside worktrees//) +git push -u origin +gh pr create + +# 6. List fully merged stale worktrees & clean up +wspace worktree list --stale +wspace worktree remove +``` + +## Worktree Lifecycle & Workflows + +### Workflow 1: Feature Worktree Creation & Isolation + +When starting work on a feature, bug fix, or agent task: + +1. **Baseline Health Check**: Run `wspace check`. Verify that the repository is + clean or on a default branch. +2. **Refresh Upstreams**: Run `wspace update` to fetch remotes and fast-forward + clean default branches (`merge --ff-only`). +3. **Provision Worktree**: + - Primary CLI command: `wspace worktree add ` + - Direct Git command: + `git -C repos/ worktree add "$PWD/worktrees//" -b ` + - _Baseline Rule_: `wspace worktree add` automatically branches from + `origin/` (via `origin/HEAD`) using `--no-track`, preventing + accidental forks from dirty local `HEAD`s. + - _Path Rule_: Always use `$PWD` when running `git -C repos/` so + worktrees resolve to `worktrees//` at the workspace root + rather than nested under `repos//`. +4. **Sync Secrets**: Run `wspace env sync` (or `--dry-run` to preview) to copy + secrets from `secrets//` into the new worktree. +5. **Develop & Commit**: Perform changes strictly inside + `worktrees///`. Keep `repos//` clean. + +### Workflow 2: Push, PR & Worktree Cleanup + +1. **Push & Create PR**: Inside `worktrees///`, run: + ```sh + git push -u origin + gh pr create + ``` +2. **Identify Stale Worktrees**: After PR merge, run + `wspace worktree list --stale`. + - _Staleness Criteria_: Identifies worktrees whose branch has no unique + commits beyond `origin/` (fully merged) or whose branch ref is + deleted. +3. **Teardown Worktree**: Run `wspace worktree remove `. + - _Note_: Removes the worktree, prunes stale git references, and cleans up + empty parent directories (`worktrees//`). + +### Workflow 3: Machine Inspection for Agents + +When an AI agent needs to verify environment integrity before cross-repo edits: + +- Call `wspace check --json` to receive structured state (`CLEAN`, `DIRTY`, + `FEATURE_CLEAN`, `DIVERGED`, `MISSING`, `UNMANAGED`). +- If any repository returns error states (`DIRTY`, `DIVERGED`, `MISSING`), halt + or request user resolution before modifying code. + +## Guiding Principles + +- **Root Anchor**: Workspace root is the single source of truth; all paths + resolve relative to the directory containing `repos.json`. +- **Conservative Mutation**: `wspace update` never resets, rebases, stashes, or + rewrites history. It skips dirty or feature branches. +- **Central Secret Vault**: Never write `.env` files directly in `repos/` or + `worktrees/`. Always edit `secrets//` and run `wspace env sync`. From 02c03cfa2b5cff9a67d86efeaa0dfd0b571059d4 Mon Sep 17 00:00:00 2001 From: Ethan Davidson <31261035+EthanThatOneKid@users.noreply.github.com> Date: Tue, 11 Aug 2026 10:09:01 -0700 Subject: [PATCH 2/5] docs: add GITHUB_TOKEN fallback note to wspace skill --- skills/wspace/SKILL.md | 1 + 1 file changed, 1 insertion(+) diff --git a/skills/wspace/SKILL.md b/skills/wspace/SKILL.md index 65e1347..32856cb 100644 --- a/skills/wspace/SKILL.md +++ b/skills/wspace/SKILL.md @@ -67,6 +67,7 @@ When starting work on a feature, bug fix, or agent task: 1. **Push & Create PR**: Inside `worktrees///`, run: ```sh git push -u origin + # Note: Clear dummy GITHUB_TOKEN if subshell causes 401: env GITHUB_TOKEN="" gh pr create gh pr create ``` 2. **Identify Stale Worktrees**: After PR merge, run From 9b8ae2bb53199c1d20f3107309897eb20e648ea4 Mon Sep 17 00:00:00 2001 From: Ethan Davidson <31261035+EthanThatOneKid@users.noreply.github.com> Date: Tue, 11 Aug 2026 10:10:18 -0700 Subject: [PATCH 3/5] docs: align status states in wspace skill with src/status.ts types --- skills/wspace/SKILL.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/skills/wspace/SKILL.md b/skills/wspace/SKILL.md index 32856cb..8c0eb1a 100644 --- a/skills/wspace/SKILL.md +++ b/skills/wspace/SKILL.md @@ -83,10 +83,12 @@ When starting work on a feature, bug fix, or agent task: When an AI agent needs to verify environment integrity before cross-repo edits: -- Call `wspace check --json` to receive structured state (`CLEAN`, `DIRTY`, - `FEATURE_CLEAN`, `DIVERGED`, `MISSING`, `UNMANAGED`). -- If any repository returns error states (`DIRTY`, `DIVERGED`, `MISSING`), halt - or request user resolution before modifying code. +- Call `wspace check --json` to receive structured state per repo (`CLEAN`, + `DIRTY`, `FEATURE_CLEAN`, `DIVERGED`, `UNKNOWN`, `MISSING`, `INVALID`, + `WORKTREE_DIRTY`, `ERROR`). +- If `wspace check` exits with `1` or returns any state other than `CLEAN` or + `FEATURE_CLEAN`, halt or request user resolution before applying multi-repo + edits. ## Guiding Principles From 011ba3e5d3b73eb283c23314b1ca1fa66fb96dae Mon Sep 17 00:00:00 2001 From: Ethan Davidson <31261035+EthanThatOneKid@users.noreply.github.com> Date: Tue, 11 Aug 2026 10:11:47 -0700 Subject: [PATCH 4/5] docs: align wspace skill with Wazoo docs style guide --- skills/wspace/SKILL.md | 84 ++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/skills/wspace/SKILL.md b/skills/wspace/SKILL.md index 8c0eb1a..c279e08 100644 --- a/skills/wspace/SKILL.md +++ b/skills/wspace/SKILL.md @@ -1,87 +1,83 @@ --- name: wspace -description: Manage multi-repo Wazoo workspaces, feature worktrees, conservative default-branch updates, and secret sync using the git-native wspace CLI. Use when managing multi-repo workflows, creating or removing feature worktrees, checking workspace baseline health, syncing environment secrets, or running wspace commands. +description: Manage multi-repo Wazoo workspaces, feature worktrees, conservative default-branch updates, and secret sync using wspace CLI. Use when managing multi-repo workflows, creating feature worktrees, checking baseline health, syncing secrets, or running wspace commands. --- -# `wspace` Workspace Skill +# `wspace` workspace skill -Use this skill to orchestrate multi-repo development, isolate tasks in Git -worktrees, refresh default branch baselines safely, and synchronize environment -secrets using `wspace` (the Wazoo Workspace CLI). +Orchestrate multi-repo development, isolate tasks in Git worktrees, refresh +default branch baselines safely, and synchronize environment secrets using +`wspace`. -## Quick Start +## Quick start -Execute all workspace commands from the workspace root (where `repos.json` -resides): +Execute all workspace commands from the workspace root containing `repos.json`: ```sh -# 1. Inspect workspace baseline health +# Inspect workspace baseline health wspace check -# 2. Fast-forward clean default branches safely +# Fast-forward clean default branches safely wspace update -# 3. Create isolated feature worktree anchored to origin/ +# Create isolated feature worktree anchored to origin/ wspace worktree add # (Or using raw git): git -C repos/ worktree add "$PWD/worktrees//" -b -# 4. Propagate local secrets to checkouts and worktrees +# Propagate local secrets to checkouts and worktrees wspace env sync -# 5. Push branch & open PR (from inside worktrees//) +# Push branch and open PR from inside worktrees// git push -u origin -gh pr create +env GITHUB_TOKEN="" gh pr create -# 6. List fully merged stale worktrees & clean up +# List fully merged stale worktrees and clean up wspace worktree list --stale wspace worktree remove ``` -## Worktree Lifecycle & Workflows +## Worktree lifecycle and workflows -### Workflow 1: Feature Worktree Creation & Isolation +### Feature worktree creation and isolation -When starting work on a feature, bug fix, or agent task: +To start work on a feature, bug fix, or agent task: -1. **Baseline Health Check**: Run `wspace check`. Verify that the repository is +1. **Baseline health check**: Run `wspace check` to verify the repository is clean or on a default branch. -2. **Refresh Upstreams**: Run `wspace update` to fetch remotes and fast-forward +2. **Refresh upstreams**: Run `wspace update` to fetch remotes and fast-forward clean default branches (`merge --ff-only`). -3. **Provision Worktree**: - - Primary CLI command: `wspace worktree add ` - - Direct Git command: - `git -C repos/ worktree add "$PWD/worktrees//" -b ` - - _Baseline Rule_: `wspace worktree add` automatically branches from +3. **Provision worktree**: Run `wspace worktree add ` or + `git -C repos/ worktree add "$PWD/worktrees//" -b `. + - **Baseline rule**: `wspace worktree add` automatically branches from `origin/` (via `origin/HEAD`) using `--no-track`, preventing - accidental forks from dirty local `HEAD`s. - - _Path Rule_: Always use `$PWD` when running `git -C repos/` so + accidental forks from dirty local `HEAD` references. + - **Path rule**: Always use `$PWD` when running `git -C repos/` so worktrees resolve to `worktrees//` at the workspace root rather than nested under `repos//`. -4. **Sync Secrets**: Run `wspace env sync` (or `--dry-run` to preview) to copy +4. **Sync secrets**: Run `wspace env sync` (or `--dry-run` to preview) to copy secrets from `secrets//` into the new worktree. -5. **Develop & Commit**: Perform changes strictly inside +5. **Develop and commit**: Perform changes strictly inside `worktrees///`. Keep `repos//` clean. -### Workflow 2: Push, PR & Worktree Cleanup +### Push, PR, and worktree cleanup -1. **Push & Create PR**: Inside `worktrees///`, run: +1. **Push and create PR**: Inside `worktrees///`, run: ```sh git push -u origin - # Note: Clear dummy GITHUB_TOKEN if subshell causes 401: env GITHUB_TOKEN="" gh pr create - gh pr create + env GITHUB_TOKEN="" gh pr create ``` -2. **Identify Stale Worktrees**: After PR merge, run +2. **Identify stale worktrees**: After PR merge, run `wspace worktree list --stale`. - - _Staleness Criteria_: Identifies worktrees whose branch has no unique + - **Staleness criteria**: Identifies worktrees whose branch has no unique commits beyond `origin/` (fully merged) or whose branch ref is deleted. -3. **Teardown Worktree**: Run `wspace worktree remove `. - - _Note_: Removes the worktree, prunes stale git references, and cleans up - empty parent directories (`worktrees//`). +3. **Teardown worktree**: Run `wspace worktree remove `. + - **Cleanup**: Removes the worktree, prunes stale git references, and cleans + up empty parent directories (`worktrees//`). -### Workflow 3: Machine Inspection for Agents +### Machine inspection for agents -When an AI agent needs to verify environment integrity before cross-repo edits: +To verify workspace integrity before cross-repo edits: - Call `wspace check --json` to receive structured state per repo (`CLEAN`, `DIRTY`, `FEATURE_CLEAN`, `DIVERGED`, `UNKNOWN`, `MISSING`, `INVALID`, @@ -90,11 +86,11 @@ When an AI agent needs to verify environment integrity before cross-repo edits: `FEATURE_CLEAN`, halt or request user resolution before applying multi-repo edits. -## Guiding Principles +## Guiding principles -- **Root Anchor**: Workspace root is the single source of truth; all paths +- **Root anchor**: The workspace root is the single source of truth; all paths resolve relative to the directory containing `repos.json`. -- **Conservative Mutation**: `wspace update` never resets, rebases, stashes, or +- **Conservative mutation**: `wspace update` never resets, rebases, stashes, or rewrites history. It skips dirty or feature branches. -- **Central Secret Vault**: Never write `.env` files directly in `repos/` or +- **Central secret vault**: Never write `.env` files directly in `repos/` or `worktrees/`. Always edit `secrets//` and run `wspace env sync`. From aba040895d1ec534afec331f311fae4c87f7e13a Mon Sep 17 00:00:00 2001 From: Ethan Davidson <31261035+EthanThatOneKid@users.noreply.github.com> Date: Tue, 11 Aug 2026 10:14:40 -0700 Subject: [PATCH 5/5] feat: support optional target repository filtering in wspace init --- README.md | 5 +++-- skills/wspace/SKILL.md | 3 +++ src/cli.ts | 30 +++++++++++++++++++++++++----- tests/integration_test.ts | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5dfbbc9..ca22e3d 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,9 @@ Design principles: - `wspace check` — read-only baseline check. Reports `CLEAN`, `DIRTY`, `FEATURE_CLEAN`, `DIVERGED`, `UNKNOWN`, `MISSING`, and `UNMANAGED` states. -- `wspace init` — clone missing repositories from the manifest. Prints a warning - that fresh clones lack gitignored files and repo-specific setup. +- `wspace init []` — 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 update` — fetch remotes and fast-forward only clean default branches. - `wspace worktree add []` — create a git worktree under `worktrees///`, branching from the repo's default-branch diff --git a/skills/wspace/SKILL.md b/skills/wspace/SKILL.md index c279e08..e1cefcb 100644 --- a/skills/wspace/SKILL.md +++ b/skills/wspace/SKILL.md @@ -17,6 +17,9 @@ Execute all workspace commands from the workspace root containing `repos.json`: # Inspect workspace baseline health wspace check +# Clone missing repositories (or a specific subset of repos) +wspace init [repo1 repo2 ...] + # Fast-forward clean default branches safely wspace update diff --git a/src/cli.ts b/src/cli.ts index 2dd42f5..f88f478 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -52,8 +52,8 @@ function usage(): void { Usage: wspace check [--json] - wspace init [--json] - wspace sync [--json] + wspace init [] [--json] + wspace sync [] [--json] wspace update [--json] wspace worktree add [] wspace worktree list [--stale] [--json] @@ -243,10 +243,26 @@ async function cloneMissing( g: GitRunner, manifest: WorkspaceManifest, paths: ManifestPaths, + targets: string[] = [], ): Promise<{ name: string; state: string; detail?: string }[]> { await Deno.mkdir(paths.repositoriesDirectory, { recursive: true }); + let repositories = manifest.repositories; + if (targets.length > 0) { + const validNames = new Set(manifest.repositories.map((r) => r.name)); + for (const name of targets) { + if (!validNames.has(name)) { + return [{ + name, + state: "UNKNOWN_REPO", + detail: `Repository "${name}" not found in manifest`, + }]; + } + } + const targetSet = new Set(targets); + repositories = repositories.filter((r) => targetSet.has(r.name)); + } const rows: { name: string; state: string; detail?: string }[] = []; - for (const repository of manifest.repositories) { + for (const repository of repositories) { const repoPath = resolveRepositoryPath(repository, paths); if (await exists(repoPath)) { if (await exists(join(repoPath, ".git"))) { @@ -290,7 +306,10 @@ async function runCommand( } case "sync": case "init": { - const rows = await cloneMissing(g, manifest, paths); + const targets = opts.subcommand + ? [opts.subcommand, ...opts.positional] + : []; + const rows = await cloneMissing(g, manifest, paths, targets); if (opts.json) { console.log(JSON.stringify(rows, null, 2)); } else { @@ -300,7 +319,8 @@ async function runCommand( (r) => r.state === "CLONE_FAILED" || r.state === "PATH_BLOCKED" || - r.state === "INVALID", + r.state === "INVALID" || + r.state === "UNKNOWN_REPO", ); if (opts.command === "init" && !failed) { console.error( diff --git a/tests/integration_test.ts b/tests/integration_test.ts index aac1010..1562892 100644 --- a/tests/integration_test.ts +++ b/tests/integration_test.ts @@ -362,6 +362,42 @@ Deno.test("wspace init clones missing repositories", async () => { } }); +Deno.test("wspace init clones only specified subset of repositories", async () => { + const dir = await Deno.makeTempDir(); + try { + await makeRepoWithMain(dir, "a"); + await makeRepoWithMain(dir, "b"); + await makeRepoWithMain(dir, "c"); + await Deno.remove(join(dir, "b"), { recursive: true }); + await Deno.remove(join(dir, "c"), { recursive: true }); + const manifestPath = join(dir, "repos.json"); + await Deno.writeTextFile( + manifestPath, + JSON.stringify({ + repositories: [ + { name: "a", url: join(dir, "a.git"), path: join(dir, "a") }, + { name: "b", url: join(dir, "b.git"), path: join(dir, "b") }, + { name: "c", url: join(dir, "c.git"), path: join(dir, "c") }, + ], + }), + ); + const code = await run(["init", "b", "--manifest", manifestPath]); + assertEquals(code, 0); + assertEquals( + await exists(join(dir, "b", ".git")), + true, + "specified repo b should be cloned", + ); + assertEquals( + await exists(join(dir, "c", ".git")), + false, + "unspecified repo c should not be cloned", + ); + } finally { + await Deno.remove(dir, { recursive: true }); + } +}); + Deno.test("wspace check reports CLEAN via CLI", async () => { const dir = await Deno.makeTempDir(); try {