---
name: managing-workspaces
description: Use when the user is working with a multi-repo **workspace directory** (a parent dir holding several cloned repos side by side) and wants routine multi-repo git or shell operations — cloning a set of repos together, pulling them all, checking branch/dirty/ahead-behind status across everything, running the same command in all or some of them, or doing an advisory pre-action check before touching shared branches. Triggers on phrases like "clone these N repos", "pull all my repos", "status across all the services", "run X in every repo", "run this in just auth and billing", "which repos are dirty", "check before I push". This skill teaches the orchestrator (you) the `ws workspace|status|preflight|pull-all|each|some` commands, their quoting rules, and the safety boundaries between read-only polling and fan-out execution. Use this skill for routine multi-repo ops; for parallel *investigation* or coordinated *refactors*, hand off to `orchestrating-swarms`.
---

# Managing workspaces

A **workspace** is just a parent directory containing several git repos as sibling subdirectories:

```
~/workspaces/lafourchette/
├── auth-service/
├── user-service/
├── booking-service/
└── gateway/
```

Every `ws` command in this skill takes that parent dir as its first argument. Commands fan out in parallel to every `*/` that has a `.git/` inside — unknown subdirs (notes, tmp files, the swarm's own `.workspace/` state dir) are skipped automatically.

## Decision: which command?

| You want to… | Command |
|---|---|
| Bootstrap a new workspace from a list of GitHub repos | `ws workspace <dir> <org/repo>...` |
| See branch, dirty, and ahead/behind default for every repo | `ws status <dir>` |
| Same, plus latest CI status (slower, uses GitHub API) | `ws status <dir> --ci` |
| Check whether it's safe to act on repos — clean tree, synced upstream, no merge conflicts vs default | `ws preflight <dir> [repo]` |
| Refresh remote-tracking refs without merging (so `ws status` is accurate) | `ws fetch-all <dir>` |
| Fast-forward pull every repo | `ws pull-all <dir>` |
| Run the same command in every repo | `ws each <dir> <cmd>` |
| Run a command in a specific subset of repos | `ws some <dir> <repo1> <repo2> -- <cmd>` |

If the user's task is "locate something across these repos" or "apply the same edit in all of them under coordination with conflict-avoidance", that's not a workspace op — hand off to `orchestrating-swarms`.

## The commands

### `ws workspace <dir> <org/repo>...`

Clones each `<org>/<repo>` into `<dir>/<repo>` in parallel. Uses `gh repo clone`, so `gh auth login` must have run. Failures are logged per repo; the command doesn't abort on a single clone failure.

```
ws workspace ~/workspaces/payments myorg/billing-api myorg/billing-web myorg/billing-worker
```

### `ws status <dir> [--ci]`

Per-repo overview: current branch, dirty/clean, and ahead/behind vs `origin/<default>`. `--ci` adds the latest check-run status (one API call per repo — don't use this in tight loops).

Use this as the first thing when entering an unfamiliar workspace. It's also the *ground truth* reference when reconciling what a swarm claims to have done against what the git state actually shows.

### `ws preflight <dir> [repo]`

Advisory checks — tree cleanliness, upstream sync, merge-conflict preview against the default branch (uses `git merge-tree` where available). This is read-only; it does not modify state.

Run before any fan-out write operation (`pull-all`, `each`/`some` with a mutating command, or an executor swarm). It's cheap and surfaces the repos that will fight you.

If you pass a single `<repo>` name, it checks only that one — useful before focused work on one repo in a bigger workspace.

### `ws fetch-all <dir>`

`git fetch --all --prune` in every repo, in parallel. Read-only — touches remote-tracking refs (`origin/*`) but never local branches or working trees. Use this before `ws status` when you want ahead/behind counts measured against the *current* remote, not your last fetch. Cheap; no merge risk.

### `ws pull-all <dir>`

`git pull --ff-only` in every repo, in parallel. Non-fast-forward cases fail per repo without aborting the others. Use after `preflight` if any repo showed as behind.

### `ws each <dir> <cmd> [args...]`

Runs the same command in every repo (parallel). Output is grouped per-repo so interleaving doesn't shred readability.

```
ws each ~/ws git status -s
ws each ~/ws gh pr list --state open
ws each ~/ws npm test
```

**Pipes and shell features need `bash -c`.** The arguments after `<dir>` are executed directly, not through a shell — so `ws each ~/ws git log | head` runs `git log` in each repo and then pipes the *combined output* through `head`, which is almost never what you want. For per-repo pipes:

```
ws each ~/ws bash -c "git log --oneline | head -5"
```

Same rule for redirections, globs that must expand per-repo, and compound commands.

### `ws some <dir> <repo1> [repo2...] -- <cmd> [args...]`

Same as `each`, but narrowed to the listed repos. The `--` separator is mandatory — without it the parser can't tell where repo names end and the command begins.

```
ws some ~/ws api-gateway auth-service -- git status -s
ws some ~/ws auth-service -- npm test
ws some ~/ws api-gateway -- bash -c "grep -r TODO src/"
```

Unknown repo names print a warning and are skipped; the command runs on the rest.

## Safety

`each`, `some`, and `pull-all` are fan-out executors. Anything you pass runs in N parallel shells. A few implications:

- **A mutating `each`/`some` command hits every selected repo with no rollback.** `ws each ~/ws git reset --hard origin/main` will dutifully blow away uncommitted work across every repo in the workspace. Run `ws status` first to see what's dirty, and prefer `ws some` with an explicit list when the change is mutating.
- **`preflight` before fan-out writes.** A repo with an unresolved merge conflict, an unpushed commit, or a detached HEAD will often fail loudly — but sometimes silently in a way that only shows up later. Preflight surfaces these cheaply.
- **CI-heavy scripts × `--ci`.** `ws status --ci` makes one API call per repo. Don't call it on a 30-repo workspace from inside a loop.
- **`gh` vs `git` commands.** `each`/`some` can run either; `gh` subcommands need `gh auth login` to have run in the invoking shell's identity, not per-repo.

Prefer read-only verification (`status`, `preflight`, `each` with `git log`/`grep`/`cat`) over fan-out writes unless you're confident the change is uniform and idempotent.

## Handoff to orchestrating-swarms

Workspace commands let you *observe* a set of repos and *execute identical commands* across them. They do not coordinate between agents, split work by scope, or audit their own output. The moment the task becomes:

- "Find where X happens, but I don't know in which repo" — **investigator-swarm** (`ws investigate`)
- "Apply coordinated but non-identical changes across repos" — **swarm-agent** (`ws swarm`)

you want the `orchestrating-swarms` skill. The common pre-swarm flow lives at the seam between the two skills:

```
ws status <dir>           # is everything clean and on the expected branch?
ws preflight <dir>        # any repo that will fight a write?
ws pull-all <dir>         # only if preflight showed behind repos
# → now you're ready to launch
ws investigate <dir> N --goal "…" --scope "…"
```

See `orchestrating-swarms` for launch, N-sizing, and post-run synthesis.

## Common mistakes

**Forgetting `--` in `ws some`.** `ws some ~/ws api auth git status` has no separator — the script can't tell `git` from a repo name. You'll get a clear error; add `--` before the command.

**Piping at the `ws each` level.** `ws each ~/ws git log --oneline | head` pipes *all repos' combined output* through `head` — you get the first 10 lines of whichever repo happened to print first. Use `bash -c "..."` for per-repo pipes.

**Running fan-out writes without preflight.** A `ws each ~/ws git checkout main && git pull` across a workspace with in-progress feature branches will leave some repos in an unexpected state. `ws preflight` first, then narrow with `ws some` if only some repos are ready.

**Using `ws` commands on a swarm's workspace dir mid-run.** The `.workspace/` state dir inside the workspace is the swarms' coordination substrate. These commands skip it automatically (no `.git/` inside), but don't go poking into it by hand while a swarm is active — the agents are reading and writing those files for coordination.

## Reference

- `scripts/ws-workspace.sh`, `ws-status.sh`, `ws-preflight.sh`, `ws-pull-all.sh`, `ws-each.sh`, `ws-some.sh` — the actual implementations.
- `justfile` — top-level recipe definitions and groupings.
- `orchestrating-swarms` skill — when workspace ops aren't enough and you need peer-coordinated investigation or execution.
