shiploop
Health Uyari
- License — License: Apache-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Basarisiz
- rm -rf — Recursive force deletion command in install.sh
- rm -rf — Recursive force deletion command in scaffold.sh
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
Lightweight orchestration layer that makes Claude Code faster and more token-efficient — model orchestration, subagent delegation, and worker branching. Adds capability, not bloat.
shiploop
A self-improving multi-agent harness for Interactive Coding Agents. It grinds a ticket backlog across every repo in your product: a fresh headless agent per ticket, guarded auto-merge on green CI, and a durable lesson written into your tracked CLAUDE.md after every resolved ticket.
Built to spend fewer tokens
One goal: the fewest tokens per shipped ticket. This section lists only the levers that move that number by multiples. Dozens of smaller economies exist in the code — cached lookups, retired validations, cleanup of abandoned resources — and they're real, but they're rounding errors next to these five.
Model orchestration. The dominant cost variable is which model runs a ticket, and the spread is wide: on this maintainer's backlog a resolved ticket costs roughly $0.59 on haiku, $2.22 on sonnet, $8.94 on opus. So the harness does not try to predict the right tier — it bets cheap and pays for the expensive model only when the cheap one has already demonstrably failed. Every ticket starts at a floor (
GOVERN_WORKER_MODEL, defaultsonnet) and a classified failure escalates it once to a ceiling (GOVERN_WORKER_ESCALATION_MODEL, defaultopus), never further. That asymmetry is the whole trade: failed attempts die early and cheap (they average a fifth of the tokens of a successful one), so a wrong cheap guess costs far less than a right expensive one. Escalation is also classified rather than reflexive — an infrastructure or CI failure retries at the same tier with the log attached, running out of budget raises the tier, and only a genuine judgment failure buys both a bigger model and more thinking.This replaced an earlier design where a cheap scout pass scored each ticket into a tier. It was removed because it was measured and didn't work: 4 of the 5 verdicts it ever produced were
opus/high, and 3 tickets it sizedopusthen succeeded atsonneton the first attempt. It was a rubber stamp, not arbitrage. The scout still runs — it just surveys now, and doesn't size.A lane that spends no model at all. The largest arbitrage available isn't opus→sonnet, it's model→no model, which is unbounded rather than a 4–15× ratio. A real share of any backlog is mechanical: flip a default, add a key, bump a version, delete a stale line, apply a known rename. The scout already runs and already reads real code, so it emits a candidate patch as one extra field on a call that was happening anyway — never a second model invocation.
deterministic-apply.shthen applies that patch, verifies it, and opens the PR with zero model turns spent on the fix. Every doubt falls through to an ordinary worker: kill switch off, empty patch, a path outside the scout's verified list, a patch spanning two sub-repos, a dirty tree,git apply --checkfailing, no verify command configured, or the verify command failing. Falling through costs exactly one normal worker — the status quo — while a wrong patch costs a bad PR, a CI cycle, and your attention, so the guards are deliberately over-strict. Off by default (GOVERN_DETERMINISTIC).Tool schemas get trimmed, and that compounds every turn. Measured on a real spawn, tool definitions were 51.7% of the entire request — larger than the conversation itself. Most of it was unusable by a headless worker: the
Workflowschema alone was 13.1% of the request. Passing an explicit tool list cuts tool bytes by 66.7% and the whole request by −34.5% (164,795 → 107,985 bytes; full methodology in PROOF.md §5). This matters more than the raw percentage suggests, because a worker session runs ~218 turns and that overhead is re-sent on every one of them. On by default now, capability-probed so an older CLI just skips it.Work that can't succeed never starts. Before spawning anything: is this repo's CI already red, is this ticket waiting on another that isn't done, is the disk nearly full, is this a check whose setup isn't wired yet? Any yes and it skips. And if your workspace runs the harness on itself, a separate gate asks whether the hub is already ahead of you on the files the ticket names — if another fleet pushed the identical fix up, you get told to pull it down instead of a worker re-deriving it from scratch. All of this is file and git reads: no model call, no network. A session you never start is the cheapest one there is, and skipping one avoids the entire ticket cost rather than shaving a percentage off it.
A retry resumes instead of restarting. Exploration is most of what a ticket costs, and before this a failed attempt bought you literally nothing. Now the worktree is preserved, so attempt two doesn't re-clone or re-explore, and it inherits the previous attempt's work: a scratchpad of which files turned out to matter and what was already ruled out, plus a structured handoff block (ruled out / stopped at / would try next) injected as "start here". Both are capped and both are handed over explicitly marked as untrusted evidence, not instructions — a wrong conclusion from attempt one shouldn't become gospel for attempt two. They live in the worktree, git-ignored, and never reach a PR.
Batching, with a caveat. One worker can take several tickets whose scout-measured file paths actually overlap, so it explores that area once instead of once per ticket. Default is 2 (
GOVERN_BATCH_MAX). Be honest about this one: the mechanism is sound and exploration really is where the money goes, but no production A/B measurement exists. A 5-ticket batch is nowhere near 5× cheaper than 5 workers. The cap was raised off 1 only after batching was re-keyed onto measured file overlap rather than a topic guess.
Three things worth knowing up front. The driver itself is free — the bash that picks tickets, tracks state, and merges PRs never calls a model, so tokens burn only inside the workers it spawns. Running four workers at once is the default (GOVERN_PARALLEL_DEFAULT), which gets more done per hour but costs four times as much at once and makes no single ticket cheaper. And several protections above only apply when the governor pulls from your backlog itself: name specific ticket numbers and you get neither batching nor the give-up-after-repeated-failures brake.
The scaffolding around all this
Two layers get built for you: a workspace once, and a fresh worker per ticket.
The workspace. /shiploop:setup wraps your existing repo rather than absorbing it — your code moves into a subfolder and stays its own git repo with its full history, and the workspace scaffolds around it. The path you cd into doesn't change. Everything that appears next to it is plain text you can read and edit:
your-project/
<your-repo>/ # your code, untouched, still its own git repo
queue/tickets.md # the backlog, one `## #N` per ticket
governor/ # doctrine, escalations, improvements
scripts/ # bash: status / dev / doctor / worktrees / govern
scripts/lib/workspace.sh # the ONE config file; every knob lives here
CLAUDE.md # git-tracked memory; every resolved ticket adds a lesson
The scripts are the harness, and they're all bash. run-loop.sh is the driver: it owns state and control flow deterministically and never calls a model. spawn-worker.sh builds a worker's prompt and launches it. config-check.sh validates your entire config with zero tokens and no Claude auth. Because the orchestration layer is deterministic bash rather than an agent, the parts that decide what to do cost nothing; only the parts that do the work spend anything.
The worktree is what makes parallelism safe. One ticket gets one git worktree, cut fresh from an up-to-date main with a branch named for the ticket in each sub-repo actually in scope; sub-repos out of scope get a read-only detached checkout so a worker can read them but not touch them. Workers can't collide, no run inherits the last one's bad state, and context stays flat instead of accumulating across tickets. On failure the worktree is kept for the retry to resume from; it's only removed once the work lands, and never while it holds commits you haven't pushed.
The worker is a fresh headless claude -p session inside that worktree. It gets a fixed prompt skeleton, your operator doctrine from governor/preferences.md, the ticket text, the scout's verified file paths as a warm start, and — on a retry — the previous attempt's handoff. It's also deliberately denied things: no MCP servers, no slash commands, no personal user-settings layer, and a trimmed tool list. That's not just thrift. A single-purpose headless worker has no use for scheduling, notification, or orchestration tools, and every schema it can't use is dead weight re-sent on all ~218 of its turns. It works, opens a PR, and writes a structured report the bash driver reads to decide what happens next.
Autonomy is bounded by the trust ladder below, not by the scaffolding — workers run with permissions bypassed by design, scoped to a throwaway worktree and the branch it pushes.
Install
# In Claude Code:
/plugin marketplace add anshss/shiploop
/plugin install shiploop@shiploop
This installs the plugin once, globally: commands appear as /shiploop:setup, /shiploop:flows, etc. in every session — the ticket loop itself isn't a command, it's natural language ("work through the queue") onto scripts/govern/run-loop.sh (see Quickstart). Each project you want shiploop on then gets its own one-time setup (next section). Prefer a clone? git clone https://github.com/anshss/shiploop.git ~/.claude/skills/shiploop && bash ~/.claude/skills/shiploop/install.sh. Same commands, same layout.
Quickstart
1. Set it up on your project: one command, one round of questions
Open Claude Code in the project you want shiploop to work on, and run setup:
cd ~/code/your-project && claude
/shiploop:setup
Setup detects what the folder is and adapts:
- An existing repo → wrap-in-place. Your repo moves into a subfolder and the workspace scaffolds around it. The path you
cdinto stays the same, full history travels as one unit verified byte-identical, and a generated.wrap-undo.shreverses everything until it all verifies. - A folder of repos (or an empty one) → fresh scaffold. Each subfolder with its own
.gitbecomes a sub-repo. One repo is a fine workspace. Add more later. - An existing workspace → upgrade, component by component, without touching your config.
It detects everything first (sub-repos, ports, dev commands, package manager), asks its questions in one batched round, then runs to completion. You end up with the workspace laid out in The scaffolding above.
Nothing you own gets clobbered on an upgrade: your README.md, CLAUDE.md, scripts/lib/workspace.sh, and the governor's operator files (preferences.md, decisions-log.md, escalations.md, improvements.md) are either never overwritten or refuse to be without an explicit --yes; .gitignore is append-only. A wrap-in-place writes a .wrap-undo.sh before it moves anything, verifies your repo's HEAD, branch, working-tree status, and submodule state are identical after the move, and rolls back on any mismatch.
2. See your product's risk map: 10 minutes, nothing deploys
/shiploop:flows extract # inventory every user-facing path that might break
/shiploop:flows list # your risk map: proven / untested / stale / failed
Extract fans out one agent per surface, and the inventory is staged for your approval: it opens no PRs, merges nothing, rents no compute. On a fresh extract everything is UNTESTED: that list is exactly the map of what you don't yet know works. Proving a path (/shiploop:flows file <id>) can deploy, so it's dry by default: nothing files until --yes, --max-deploys N caps a batch, and --all-stale/--all-untested refuse unless the orphan-sweep (GOVERN_DEPLOY_SWEEP_CMD) is wired.
3. File one ticket, watch it ship
From the workspace root:
scripts/govern/file-ticket.sh "Fix empty-state copy on /settings" # into queue/tickets.md
bash scripts/govern/config-check.sh # free smoke test, no tokens, no Claude auth
Then just say "work on that ticket" (or "work through the queue" for the whole backlog) — Claude
maps it straight onto scripts/govern/run-loop.sh: fresh worker → edits → PR → waits for CI.
New workspaces start on the pr-only rung: workers open PRs, the governor never merges. You click merge. When you've read enough of a repo's PRs to trust the pattern, add it to GOVERN_MERGE_REPOS and its green-CI PRs auto-merge, guarded (Trust).
How it works
The governor is a pure-bash driver (scripts/govern/run-loop.sh): it owns state and control flow deterministically and spends near-zero Claude context. Model tokens burn only inside the fresh headless workers it spawns.
- One ticket = one fresh headless session in its own git worktree. Context stays flat, workers ship in parallel without collisions, no run inherits the last one's bad state.
- Cheap floor, escalate once. Every ticket dispatches at
GOVERN_WORKER_MODEL(defaultsonnet); a classified failure escalates it exactly once toGOVERN_WORKER_ESCALATION_MODEL(defaultopus). No per-ticket prediction, because prediction was tried and measured as a rubber stamp. A cheap scout pass (haiku) still runs before dispatch, but it now only surveys — verified file paths, whether tests cover the area, whether history holds a precedent commit — which the worker gets as a warm start, the batching layer keys on, and the zero-model lane uses as its patch source. Its result is cached per run, so a retry never re-scouts. - A periodic supervisor (another cheap fresh session) audits the run and can halt it. Hard-stops land in
governor/escalations.mdfor you. - It gets better over time. Every resolved ticket promotes its durable lesson into the right
CLAUDE.mdbefore the entry is deleted: memory you can read, diff, and edit. Harness improvements accrete ingovernor/improvements.md(observe → propose → triage; never auto-applied to safety rails), and the hub channel (/shiploop:update//shiploop:push) moves mechanism fixes between your workspace and the template repo. Always via human-reviewed PR.
Trust
Autonomy is a ladder, not a switch. One knob, GOVERN_AUTONOMY in scripts/lib/workspace.sh, controls it:
| Rung | Behavior |
|---|---|
observe |
Workers do real work but every PR opens as a draft; nothing merges |
pr-only |
(default on new scaffolds) Normal PRs; a human clicks merge |
auto |
Auto-merge on green-or-no-checks CI, but only for repos on GOVERN_MERGE_REPOS (empty by default) |
What makes the top rung safe to reach for:
- Three-factor merge guard. A PR auto-merges only if its author is the governor's own worker identity, its branch matches the governor's naming, and its head is not from a fork. Any factor missing → stays open for a human.
- Hard-stops. Destructive git, prod data, destructive schema, secrets: the doctrine in
governor/preferences.mdmakes a worker park + escalate instead of acting. - Bounded blast radius. Workers run
claude -p --permission-mode bypassPermissionsby design, scoped to a throwaway worktree plus the branch it pushes;.githooks/pre-pushrejects any harness-repo push except a sanctioned governor run. - Fail-closed evidence gates on the self-improvement and sync ports:
bash -n, a forbidden-identity-strings gate, and a scaffold-test baseline diff. Any failure escalates instead of merging.
Cost, observed: $3.03 median / $4.49 mean per resolved ticket ($1.34-$12.00 range, N=32 tracked tickets), from Claude Code's own reported cost, not an estimate. See PROOF.md for the full distribution and methodology. That sample predates the current cheap-floor default and skews opus-heavy on self-referential harness tickets, so treat it as an upper bound rather than an average — a sonnet floor observed ~$2.22/ticket. config-check.sh is the only truly free smoke ($0, no auth); scripts/govern/run-loop.sh --dry-run (say "dry-run the queue") runs a real worker in plan mode. Zero side effects, but it costs tokens. For your first run: keep the allowlist empty, watch one ticket end-to-end, and set a spend cap in your Anthropic dashboard.
Commands
| Command | What it does |
|---|---|
/shiploop:setup |
Scaffold or upgrade a workspace: wrap-in-place inside an existing repo, or from a parent folder of repos |
| (say "work on <tickets>" / "work through the queue") | Ship your backlog: natural language onto the bash-driven ticket loop (scripts/govern/run-loop.sh), end to end |
/shiploop:flows |
Inventory (extract), inspect (list), and validate (file) your product's user-facing paths |
/shiploop:update |
Pull the latest hub templates into this workspace (workspace.sh is never overwritten) |
/shiploop:push |
Port local mechanism improvements back to the hub as a human-reviewed PR (never auto-merges) |
bash scripts/doctor.sh warns when your workspace lags the hub by N releases.
Configuration
Everything lives in one file: scripts/lib/workspace.sh. Advanced lanes ship off so a fresh install is inert until you opt in:
| Knob | Default | Turns on |
|---|---|---|
GOVERN_AUTONOMY |
pr-only |
Trust-ladder rung (observe / pr-only / auto); absent = auto for pre-knob installs |
GOVERN_MERGE_REPOS |
empty | Per-repo auto-merge allowlist (requires auto) |
GOVERN_WORKER_MODEL |
sonnet |
First-attempt floor: the tier every ticket dispatches at. A ticket's own Model:/Effort: fields no longer participate in dispatch |
GOVERN_WORKER_ESCALATION_MODEL |
opus |
Escalate-once ceiling: the tier a classified judgment failure retries at. A ticket never escalates twice |
GOVERN_DETERMINISTIC |
0 (off) |
Zero-model lane: let the scout's mechanical patch resolve a ticket with no model turns on the fix. Over-strict guards; every doubt falls through to a normal worker |
GOVERN_SCOUT |
on | Pre-dispatch survey (verified file paths, coverage, precedent commit) used as a worker warm start, the batching key, and the zero-model patch source. It does not pick the tier |
GOVERN_SCOUT_MODEL |
haiku |
Tier the scout pass itself runs at — recon should cost a rounding error |
GOVERN_SCOUT_TIMEOUT |
180 |
Seconds the scout pass may run before it is abandoned; dispatch proceeds without a survey |
GOVERN_PARALLEL_DEFAULT |
4 |
Tickets a plain run-loop.sh works at once: N > 1 runs N concurrent backlog drivers (N× the spend); per-run --parallel[=N] / --serial override it |
GOVERN_SUPERVISOR_FLUSH |
on | Out-of-loop supervisor passes so a fan-out keeps the sequential review rhythm: a per-driver run-tail flush plus one whole-run review over the pool (0 to suppress both) |
GOVERN_RETRY_NOTES_MAX_BYTES |
16000 |
Byte cap on the findings scratchpad (.governor-notes.md) a retry inherits from the previous attempt; the full file stays on disk in the preserved worktree |
GOVERN_WORKER_TOOLS |
default (on) |
Tool-schema trim: passes --tools <recommended list> to every worker, cutting the measured 51.7% of the request that tool JSON occupies down to 26.3% (−34.5% request bytes; see PROOF.md §5). Or give your own space/comma-separated list. Capability-probed, so an older CLI just skips it |
WSP_LINT_FIX_CMD |
empty | Pre-commit lint/format fix across sub-repos |
GOVERN_LOCAL_FIRST_REPOS |
empty | Repos with no prod DB: additive migrations merge instead of parking |
GOVERN_PUBLIC_REPOS |
auto-detect | Public repos get neutral sl-<hex> branches, no ticket ids on PRs |
GOVERN_PR_TICKET_REF |
0 (ids suppressed) |
1 puts the internal ticket id back in PR titles/bodies/commit subjects. By default every worker is told to keep #N off the PR and the run-loop scrubs title+body as a backstop; branches stay ticket-<N> either way. The opt-out never applies to a public repo |
GOVERN_EXTERNALIZE_REPO / _SUBREPO |
empty | Stage low-severity OSS tickets as public "good first issue"s, filed only on your approval |
GOVERN_UPSTREAM_HARNESS_REPO / _DIR |
empty | The /shiploop:push sync channel to your hub fork |
WSP_PR_FOOTER |
on | "shipped by shiploop" attribution line on worker PRs (off to suppress) |
Permissions
| Knob | Default | Turns on |
|---|---|---|
GOVERN_PERMISSION_MODE |
bypassPermissions |
The --permission-mode every headless worker runs under. The default lets a worker act without prompting — which is what makes an unattended run possible, and also the single widest grant in the harness. Tighten it if you want workers to stop at the permission boundary; note that a mode which prompts will stall a headless run rather than fail it |
GOVERN_WORKER_MCP |
0 (off) |
Give workers the workspace's MCP servers. Off by default: MCP tool schemas are re-sent on every turn, so this is a standing per-turn cost |
Hard bounds — how a run is guaranteed to end
| Knob | Default | Turns on |
|---|---|---|
GOVERN_MAX_TICKETS |
20 |
Tickets one driver will work before stopping. Per driver — a parallel backlog run's real ceiling is N × this |
GOVERN_MAX_BAD_STREAK |
4 |
Consecutive parked/failed tickets before the run halts itself |
GOVERN_MAX_RUNTIME |
0 (no cap) |
Wall-clock seconds. There is no time bound unless you set one |
GOVERN_WORKER_TIMEOUT |
3600 (1h) |
Seconds one worker may run before it is killed rather than left stalled |
GOVERN_WORKER_MAX_TOKENS |
0 (unlimited) |
Token ceiling per worker; crossing it kills the worker with a distinct budget-exceeded outcome |
GOVERN_MIN_FREE_GB |
5 |
Free-disk floor checked before spawning; below it the run stops rather than filling the volume |
CI, retries, and cadence
| Knob | Default | Turns on |
|---|---|---|
GOVERN_CI_INTERVAL |
30 |
Seconds between CI polls while awaiting checks |
GOVERN_CI_MAX_TRIES |
60 |
Polls before CI is treated as never-settling (≈30 min at the default interval) |
GOVERN_CI_FIX_TRIES |
1 |
Attempts a worker gets at fixing its own red CI before the ticket parks |
GOVERN_CONFLICT_FIX_TRIES |
1 |
Attempts at resolving a merge conflict before parking |
GOVERN_INFRA_RETRY |
1 |
Retries for an infrastructure-class failure (API/transport). Retried at the same model tier, not escalated |
GOVERN_INTERRUPT_RETRY |
1 |
Retries for a worker killed mid-flight |
GOVERN_SUPERVISOR_EVERY |
5 |
Tickets between periodic supervisor reviews |
GOVERN_SUPERVISOR_MODEL |
sonnet |
Tier the supervisor pass runs at |
GOVERN_BATCH_MAX |
2 |
Tickets with overlapping scout-measured file paths that one worker may take as a group, exploring once and opening one PR. Kept low because no production A/B measurement of batching exists yet; 1 disables it |
Binaries
| Knob | Default | Turns on |
|---|---|---|
GOVERN_CLAUDE_BIN |
claude |
Path to the Claude Code CLI — set it for a non-standard install or to pin a version |
GOVERN_GH_BIN |
gh |
Path to the GitHub CLI |
Knobs not listed here (GOVERN_TICKETS_FILE, GOVERN_QUEUE_DIR, GOVERN_LOG_ROOT, GOVERN_LOCK*, GOVERN_TEMPLATE_DIR, and similar path overrides) exist for test and scaffold plumbing. They are overridable but are not tuning surface — treat them as internal.
Requirements
- Claude Code CLI: Act 1 (setup + extract) needs only this, git, and
jq jq: hard-required; the scaffolder and governor fail closed without itghCLI, authenticated, for the governor (opens PRs, reads CI); not needed for the risk map- git ≥ 2.20, bash ≥ 4 (macOS's 3.2 also works, templates are guarded for both)
How it compares
Devin, Cursor, Copilot, and Claude Code all do one task you hand them well. shiploop is the layer above: it runs a backlog across a fleet (a manager, not another IC). If your bottleneck is one hard task, use those. If it's a growing queue of small-to-medium changes across N repos, and you'd rather do the spec work than the shipping, use this.
Proof
281 tickets auto-found and resolved on the maintainer's production multi-repo product, of 290 governor-authored PRs merged (0 confirmed reverts). The harness audits, fixes, and releases itself through the same loop. Every governor edge case found in the field ports back into these templates with a regression test, and the hermetic suite goes RED in CI before a breaking change can merge. See PROOF.md for the full sanitized evidence artifact: auto-merge/human-merge split, revert rate, cost-per-ticket distribution, and the exact re-runnable queries behind every number.
Contributing
See CONTRIBUTING.md. Everything the scaffolder installs lives under templates/; the slash commands under commands/; hermetic governor tests under templates/govern/test/ (hub-only — the suite is not installed into a workspace).
License
Apache License 2.0. Includes an express patent grant and a
trademark reservation; redistributions must carry the NOTICE file
and state any changes made. Releases up to and including v1.15.1 were
published under the MIT license and remain available under those terms.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi