/setup
Scaffold a new shiploop workspace or upgrade one. Routine bumps -> /update; push fixes upstream -> /push.
> /plugin marketplace add anshss/shiploop> /plugin install shiploop@shiploop
Command definition
setup.md# sonnet on purpose: every judgment-heavy step is delegated to a deterministic script
# (detect-inputs.sh, wrap.sh --preflight/--yes, scaffold.sh) with explicit exit codes,
# so the command itself is orchestration — and per-turn latency is the dominant cost
# of a live onboarding (a measured run spent ~7 min on model turns vs ~30s in tools).
model: sonnet
effort: medium
description: Scaffold a new shiploop workspace or upgrade one. Routine bumps -> /update; push fixes upstream -> /push.
You are the meta-repo setup command. You convert the current folder into — or upgrade an existing — **meta-repo workspace**: an npm/pnpm/yarn/bun root (`ROOT_PM`, operator's choice) wrapping N independent git sub-repos, with cross-cutting tooling, parallel worktrees, a ticket queue, a governor (autonomous ticket loop), and the SessionStart/End/Stop hooks.
The full pattern is documented in the plugin's `SKILL.md` (read if you need context). All mechanical file writes are executed by `scaffold.sh` — you own the interview and judgment; it owns byte-level writes, deterministically and idempotently.
Locate the plugin
Templates and `scaffold.sh` live together. Resolve `PLUGIN_ROOT` in priority order: 1. `${CLAUDE_PLUGIN_ROOT}` (plugin run) 2. `~/.claude/skills/shiploop/` (legacy clone-into-skills) 3. `~/.claude/plugins/**` cache lookup by plugin name
`SCAFFOLD=$PLUGIN_ROOT/scaffold.sh`.
Architecture (read once)
Every mechanism script sources ONE config file, `scripts/lib/workspace.sh` (repo names, dev commands, ports, GitHub org, worktree base, merge-allowlist). Mechanism scripts are therefore identical across installs — a bump just refreshes them from templates and only ever (re)generates `workspace.sh`. **Never hand-edit a mechanism script; put the value in `workspace.sh`.**
Interview doctrine — ONE pause
1. **Detect first, ask second.** Run EVERY detection (mode, sub-repos, ports, dev commands, org, root PM, worktree base, visibility) AND — in wrap mode — `wrap.sh --preflight` BEFORE the first question. Preflight is read-only and surfaces every `REFUSE`/`NEEDS-CONFIRM` item up front. 2. **One batched interview.** Ask everything in a SINGLE `AskUserQuestion` call (4-question limit is enough — see per-mode specs below). Print the detected-defaults table BEFORE the call; detected values aren't questions — override via "Other". 3. **Then run to completion without pausing.** Legitimate post-interview stops are ONLY: wrap.sh exit 1 (rolled back), exit 4 (name collision preflight missed), or a NEW exit-5 item preflight could not have seen. Never re-ask something the interview covered.
Workspace layout scaffold.sh produces:
<root>/
package.json scripts/lib/workspace.sh queue/tickets.md
.gitignore scripts/lib/{workspace,session-state,preflight,githooks}.sh
.worktrees/.gitkeep scripts/{doctor,dev,sync,tail}.sh queue/tickets-parked.md
governor/*.md scripts/{check-main-on-main,ticket-sweep-reminder,session-snapshot,router-posture-*}.sh
.claude/settings.json scripts/worktree/* + worktree/lib/registry.sh
.claude/commands/*.md scripts/govern/* + govern/lib/common.sh
CLAUDE.md learnings.md .githooks/{pre-push,prepare-commit-msg}
README.md (workspace landing page — "<name> on Shiploop"; never overwritten)---
Phase 0 — Detect the mode
Print `── meta-repo setup ──`, then `pwd` and `ls -la`.
WRAP="$PLUGIN_ROOT/templates/lib/wrap.sh"
MODE="$(bash "$WRAP" --detect --workspace-dir "$(pwd)")"
echo "mode: $MODE"
| `$MODE` | Context | Do | |---|---|---| | `upgrade` | `scripts/lib/workspace.sh` present | **BUMP MODE** → Phase B | | `fresh` | not inside any git repo | **FRESH MODE** → Phase 1 | | `wrap` | AT the root of a git repo, `.git` is a directory | **WRAP OFFER** → Phase W | | `refuse:gitfile` | `.git` is a FILE (linked worktree/submodule) | STOP — wrapping corrupts the main repo's back-pointers; out of scope for v1 | | `refuse:below-root` | inside a git repo, below its root | STOP — "cd to the repo root and re-run" (print root path) | | `refuse:bare` | bare repository | STOP — nothing to wrap |
`fresh` with **zero** sub-repos detected in Phase 1 does not stop — it routes to **Phase G** (greenfield), which materializes the first sub-repo itself.
Back-compat: an older meta-repo predating `scripts/lib/workspace.sh` but with a `package.json` whose `"doctor"` script is `"bash scripts/doctor.sh"` is still **upgrade** even though `--detect` returns `fresh` — treat as BUMP MODE (scaffold.sh re-parameterizes the core scripts). Very old installs also carry the retired `"status"`/`"branch"`/`"switch"`/`"pull"`/`"push"`/`"health"` aliases; scaffold's purge removes the scripts they point at, so drop those lines from `package.json` in the same pass.
Phase W — Wrap-in-place (`$MODE == wrap`)
Gather everything first (W0), then run the single interview (W1). Do NOT ask anything before W1.
W0 — Detect + preflight (ONE combined bash call)
Chain detection and preflight in a SINGLE call — don't hand-run per-value probes or split turns:
DET="$(bash "$PLUGIN_ROOT/templates/lib/detect-inputs.sh" --workspace-dir "$(pwd)" --mode wrap)"
printf '%s\n' "$DET" # root_pm= / worktree_base= / org= / repo=<NAME>|<port>|<cmd>|<visibility> / repos_spec=
NAME="$(printf '%s\n' "$DET" | sed -n 's/^repo=\([^|]*\).*/\1/p' | head -1)"
bash "$WRAP" --preflight --workspace-dir "$(pwd)" --name "$NAME" # read-only; surfaces every REFUSE / NEEDS-CONFIRM
`repo=` carries the wrap subfolder name (`NAME`, from `origin` else folder name — where the repo lands: `<path>/<NAME>/`), its port + dev command, and visibility (`PUBLIC` unlocks auto-externalization; `unknown` = no `gh`, treat as private). Only override a detected value you can SEE is wrong.
Preflight is fail-closed; a single **prunable** worktree no longer refuses (auto-pruned), only LIVE linked work
Read more
# sonnet on purpose: every judgment-heavy step is delegated to a deterministic script # (detect-inputs.sh, wrap.sh --preflight/--yes, scaffold.sh) with explicit exit codes, # so the command itself is orchestration — and per-turn latency is the dominant cost # of a live onboarding (a measured run spent ~7 min on model turns vs ~30s in tools). model: sonnet effort: medium description: Scaffold a new shiploop workspace or upgrade one. Routine bumps -> /update; push fixes upstream -> /push.
You are the meta-repo setup command. You convert the current folder into — or upgrade an existing — **meta-repo workspace**: an npm/pnpm/yarn/bun root (`ROOT_PM`, operator's choice) wrapping N independent git sub-repos, with cross-cutting tooling, parallel worktrees, a ticket queue, a governor (autonomous ticket loop), and the SessionStart/End/Stop hooks.
The full pattern is documented in the plugin's `SKILL.md` (read if you need context). All mechanical file writes are executed by `scaffold.sh` — you own the interview and judgment; it owns byte-level writes, deterministically and idempotently.
Locate the plugin
Templates and `scaffold.sh` live together. Resolve `PLUGIN_ROOT` in priority order: 1. `${CLAUDE_PLUGIN_ROOT}` (plugin run) 2. `~/.claude/skills/shiploop/` (legacy clone-into-skills) 3. `~/.claude/plugins/**` cache lookup by plugin name
`SCAFFOLD=$PLUGIN_ROOT/scaffold.sh`.
Architecture (read once)
Every mechanism script sources ONE config file, `scripts/lib/workspace.sh` (repo names, dev commands, ports, GitHub org, worktree base, merge-allowlist). Mechanism scripts are therefore identical across installs — a bump just refreshes them from templates and only ever (re)generates `workspace.sh`. **Never hand-edit a mechanism script; put the value in `workspace.sh`.**
Interview doctrine — ONE pause
1. **Detect first, ask second.** Run EVERY detection (mode, sub-repos, ports, dev commands, org, root PM, worktree base, visibility) AND — in wrap mode — `wrap.sh --preflight` BEFORE the first question. Preflight is read-only and surfaces every `REFUSE`/`NEEDS-CONFIRM` item up front. 2. **One batched interview.** Ask everything in a SINGLE `AskUserQuestion` call (4-question limit is enough — see per-mode specs below). Print the detected-defaults table BEFORE the call; detected values aren't questions — override via "Other". 3. **Then run to completion without pausing.** Legitimate post-interview stops are ONLY: wrap.sh exit 1 (rolled back), exit 4 (name collision preflight missed), or a NEW exit-5 item preflight could not have seen. Never re-ask something the interview covered.
Workspace layout scaffold.sh produces:
<root>/
package.json scripts/lib/workspace.sh queue/tickets.md
.gitignore scripts/lib/{workspace,session-state,preflight,githooks}.sh
.worktrees/.gitkeep scripts/{doctor,dev,sync,tail}.sh queue/tickets-parked.md
governor/*.md scripts/{check-main-on-main,ticket-sweep-reminder,session-snapshot,router-posture-*}.sh
.claude/settings.json scripts/worktree/* + worktree/lib/registry.sh
.claude/commands/*.md scripts/govern/* + govern/lib/common.sh
CLAUDE.md learnings.md .githooks/{pre-push,prepare-commit-msg}
README.md (workspace landing page — "<name> on Shiploop"; never overwritten)---
Phase 0 — Detect the mode
Print `── meta-repo setup ──`, then `pwd` and `ls -la`.
WRAP="$PLUGIN_ROOT/templates/lib/wrap.sh" MODE="$(bash "$WRAP" --detect --workspace-dir "$(pwd)")" echo "mode: $MODE"
| `$MODE` | Context | Do | |---|---|---| | `upgrade` | `scripts/lib/workspace.sh` present | **BUMP MODE** → Phase B | | `fresh` | not inside any git repo | **FRESH MODE** → Phase 1 | | `wrap` | AT the root of a git repo, `.git` is a directory | **WRAP OFFER** → Phase W | | `refuse:gitfile` | `.git` is a FILE (linked worktree/submodule) | STOP — wrapping corrupts the main repo's back-pointers; out of scope for v1 | | `refuse:below-root` | inside a git repo, below its root | STOP — "cd to the repo root and re-run" (print root path) | | `refuse:bare` | bare repository | STOP — nothing to wrap |
`fresh` with **zero** sub-repos detected in Phase 1 does not stop — it routes to **Phase G** (greenfield), which materializes the first sub-repo itself.
Back-compat: an older meta-repo predating `scripts/lib/workspace.sh` but with a `package.json` whose `"doctor"` script is `"bash scripts/doctor.sh"` is still **upgrade** even though `--detect` returns `fresh` — treat as BUMP MODE (scaffold.sh re-parameterizes the core scripts). Very old installs also carry the retired `"status"`/`"branch"`/`"switch"`/`"pull"`/`"push"`/`"health"` aliases; scaffold's purge removes the scripts they point at, so drop those lines from `package.json` in the same pass.
Phase W — Wrap-in-place (`$MODE == wrap`)
Gather everything first (W0), then run the single interview (W1). Do NOT ask anything before W1.
W0 — Detect + preflight (ONE combined bash call)
Chain detection and preflight in a SINGLE call — don't hand-run per-value probes or split turns:
DET="$(bash "$PLUGIN_ROOT/templates/lib/detect-inputs.sh" --workspace-dir "$(pwd)" --mode wrap)" printf '%s\n' "$DET" # root_pm= / worktree_base= / org= / repo=<NAME>|<port>|<cmd>|<visibility> / repos_spec= NAME="$(printf '%s\n' "$DET" | sed -n 's/^repo=\([^|]*\).*/\1/p' | head -1)" bash "$WRAP" --preflight --workspace-dir "$(pwd)" --name "$NAME" # read-only; surfaces every REFUSE / NEEDS-CONFIRM
`repo=` carries the wrap subfolder name (`NAME`, from `origin` else folder name — where the repo lands: `<path>/<NAME>/`), its port + dev command, and visibility (`PUBLIC` unlocks auto-externalization; `unknown` = no `gh`, treat as private). Only override a detected value you can SEE is wrong.
Preflight is fail-closed; a single **prunable** worktree no longer refuses (auto-pruned), only LIVE linked work
Other commands on shiploop.
More commands from other plugins.
build
CommandImplement tasks incrementally — build, test, verify, commit. Add "auto" to run the whole plan in one approved pass.

