bullswarm 0.4.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/AGENTS.md +39 -1
  2. package/CHANGELOG.md +202 -0
  3. package/GOAL.md +135 -0
  4. package/README.md +223 -6
  5. package/connectors/_schema.json +23 -0
  6. package/connectors/claude-code.json +12 -1
  7. package/connectors/codex.json +13 -1
  8. package/connectors/command-code.json +17 -1
  9. package/connectors/echo.json +12 -0
  10. package/connectors/grok.json +11 -1
  11. package/connectors/opencode2.json +11 -1
  12. package/docs/dynamic-workflow-handoff.md +952 -0
  13. package/docs/dynamic-workflow-qa.md +107 -0
  14. package/docs/workflow-agent-usability-audit-2026-08-27.md +196 -0
  15. package/docs/workflow-design.md +195 -0
  16. package/fixtures/failures/01-rate-limit-head.json +6 -0
  17. package/fixtures/failures/03-pure-intent.json +6 -0
  18. package/fixtures/failures/04-cnf.json +6 -0
  19. package/fixtures/failures/05-unauthorized.json +6 -0
  20. package/fixtures/failures/06-short-conn.json +6 -0
  21. package/fixtures/failures/07-empty.json +6 -0
  22. package/fixtures/failures/08-tool-starved.json +6 -0
  23. package/fixtures/failures/09-auth-short.json +6 -0
  24. package/fixtures/failures/10-intent-short.json +6 -0
  25. package/fixtures/failures/11-503.json +6 -0
  26. package/fixtures/failures/12-blocked.json +6 -0
  27. package/fixtures/failures/13-announcement-477b.json +7 -0
  28. package/fixtures/real/01-rate-limit-discussion.json +7 -0
  29. package/fixtures/real/02-intent-opener.json +7 -0
  30. package/fixtures/real/03-dts-tokens.json +7 -0
  31. package/fixtures/real/04-rename.json +6 -0
  32. package/fixtures/real/05-lookup.json +6 -0
  33. package/fixtures/real/06-tests.json +6 -0
  34. package/fixtures/real/07-boilerplate.json +6 -0
  35. package/fixtures/real/09-smoke.json +6 -0
  36. package/fixtures/real/10-review.json +6 -0
  37. package/fixtures/real/11-convert.json +6 -0
  38. package/fixtures/real/12-tidy.json +6 -0
  39. package/package.json +7 -2
  40. package/skill/SKILL.md +363 -31
  41. package/src/cli.js +70 -22
  42. package/src/lib/config.js +8 -0
  43. package/src/lib/route.js +24 -5
  44. package/src/lib/state.js +1 -0
  45. package/src/lib/strategy.js +218 -0
  46. package/src/lib/usage.js +171 -0
  47. package/src/lib/watch.js +66 -9
  48. package/src/setup.js +79 -3
  49. package/src/strategy-cli.js +244 -0
  50. package/src/workflow/cli.js +510 -16
  51. package/src/workflow/dashboard.js +291 -0
  52. package/src/workflow/decision.js +152 -0
  53. package/src/workflow/draft-cli.js +451 -0
  54. package/src/workflow/draft.js +270 -0
  55. package/src/workflow/events.js +66 -0
  56. package/src/workflow/goal.js +129 -0
  57. package/src/workflow/runner.js +470 -16
  58. package/src/workflow/runs-cli.js +189 -0
  59. package/src/workflow/runtime.js +837 -70
  60. package/src/workflow/semaphore.js +56 -0
  61. package/src/workflow/short-id.js +267 -0
  62. package/src/workflow/template.js +26 -1
  63. package/src/workflow/tui.js +26 -0
  64. package/src/workflow/validate.js +120 -3
  65. package/workflows/adaptive-code-review.json +45 -0
  66. package/workflows/agent-model-comparison.json +49 -0
  67. package/workflows/connector-audit.json +60 -0
  68. package/workflows/smoke-two-step.json +41 -0
  69. package/workflows/verify-and-cap.json +62 -0
package/AGENTS.md CHANGED
@@ -17,14 +17,52 @@ content. Published as `bullswarm` on npm.
17
17
  3. Connector quirks live in `connectors/*.json`, never in core logic.
18
18
  4. Quarantine always auto-releases; recursion depth is core-owned via env
19
19
  (`BULLSWARM_DEPTH`).
20
+ 5. Workflow dispatches must honor the same guarantees as single runs:
21
+ `BULLSWARM_DEPTH` is propagated, burst-gated pools are excluded, and
22
+ auth verdicts quarantine the pool + append to the shared decision log
23
+ (R6/R7/R8 in `src/workflow/runtime.js`).
24
+ 6. Adversarial verification is a first-class primitive: a `verify` step
25
+ reads a prior outFile and demands a JSON `{ok, concerns, summary}`
26
+ verdict before downstream steps can trust the work (R-skeptic).
27
+ 7. Workflows can be built incrementally from the shell
28
+ (`bullswarm workflow draft create/phase/step/set/...`). Drafts are
29
+ stored under `~/.bullswarm/drafts/<name>/` and are runnable by name
30
+ without an upfront JSON. JSON is still the durable artifact — drafts
31
+ are JSON documents, just built one mutation at a time.
32
+ 8. Goal-driven execution is zero-graph by default: `bullswarm workflow goal`
33
+ internalizes the planner contract, chooses the orchestrator and workers,
34
+ persists the generated workflow, and can detach so observation never
35
+ depends on the initiating agent or CLI process.
20
36
 
21
37
  ## Development
22
38
 
23
39
  ```bash
24
- npm test # 61+ tests, no network needed (meters read from cache)
40
+ npm test # 195 tests, no network needed (meters read from cache)
25
41
  node bin/bullswarm.js doctor --json # readiness report
42
+ node bin/bullswarm.js workflow list # discover workflows
43
+ node bin/bullswarm.js workflow runs # ongoing workflow instances
44
+ node bin/bullswarm.js workflow runs --all # including historical
45
+ node bin/bullswarm.js workflow validate <file> # dry-run
46
+ BULLSWARM_HOME=/tmp/bs node bin/bullswarm.js workflow run <file> # sandboxed run
47
+ # Build a workflow from the shell:
48
+ bullswarm workflow draft create my-audit
49
+ bullswarm workflow draft phase add my-audit discover
50
+ bullswarm workflow draft step add my-audit discover list-files --type run --prompt 'List files'
51
+ bullswarm workflow draft run my-audit
52
+ # Operate on a run by shortId (6 chars) or full runId (`wf-...`):
53
+ bullswarm workflow runs show <shortId>
54
+ bullswarm workflow runs delete <shortId> --yes
26
55
  ```
27
56
 
57
+ ## Using bullswarm from another agent
58
+
59
+ If you are an agent that wants to offload bounded work via bullswarm,
60
+ read `skill/SKILL.md` — that's the agent-facing user guide. It covers
61
+ when to reach for `run` vs `workflow draft`, the verify-step pattern,
62
+ how to write prompts that pass the content gate, and the failure modes
63
+ you'll hit. The skill is published alongside the package and is the
64
+ canonical reference for the CLI surface.
65
+
28
66
  - Zero runtime dependencies. Node >= 18. Tests must never require network:
29
67
  prime `~/.bullswarm/meters/*.json` caches with fresh timestamps if needed.
30
68
  - Every verb must work non-interactively (no TTY). The interactive wizard is
package/CHANGELOG.md ADDED
@@ -0,0 +1,202 @@
1
+ # bullswarm changelog
2
+
3
+ ## 0.9.0 — resilient dynamic workflow routing
4
+
5
+ - Added cooperative `SIGTERM`/`SIGINT` handling, durable `interrupted` states,
6
+ dead/stale owner reconciliation, and clean resume after interruption.
7
+ - Added capability-context filtering for model recommendations plus an explicit
8
+ `strategy apply --yes` approval gate and TTL-based automatic refresh.
9
+ - Added setup-time worktree policy and strategy-autopilot choices.
10
+ - Added per-attempt routing reasons/candidate surplus to durable events, state,
11
+ decision logs, and the printable workflow tree.
12
+ - Added top-level `runs` and `--version` aliases, complete `workflow goal`
13
+ budget help, and correct phase/terminal display for completed runs.
14
+
15
+ ## 0.8.0 — autonomous goals, model strategy, and auditable usage
16
+
17
+ - Added `workflow goal` for bounded observe-plan-execute loops without an
18
+ upfront graph, including planner-owned expansion, completion policy,
19
+ detachment, resume, cancellation, ordered events, and durable action and
20
+ attempt ledgers.
21
+ - Added first-class `decide` and adversarial `verify` actions with strict JSON
22
+ contracts, capability-aware routing, bounded retries/escalation, and hard
23
+ expansion/dispatch/time limits.
24
+ - Added `strategy refresh/show/set-subscription/assign` to discover models from
25
+ installed CLIs, combine connector-owned dated price/benchmark metadata with
26
+ live quota surplus, and persist high/medium/low effort preferences.
27
+ - Added connector-owned model selection plus `--effort` routing for ordinary
28
+ runs and workflow actions. Safety eligibility always overrides preferences.
29
+ - Added per-attempt agent/model, standard-read/cache-read/cache-write/output
30
+ token estimates, API-equivalent cost, subscription-normalized quota, and
31
+ honest partial totals when a provider omits model or usage data.
32
+ - Added `workflow tui <runId>` as a printable historical phase/action/attempt
33
+ tree in both TTY and non-TTY environments, alongside JSON state/events.
34
+ - Expanded the offline suite to 195 tests. A fresh-home real-provider trial
35
+ autonomously fixed and independently verified a failing Node fixture; a
36
+ deliberately undersized dispatch budget also stopped truthfully rather than
37
+ claiming completion.
38
+
39
+ ## 0.7.0 — short run IDs + workflow runs
40
+
41
+ Workflow runs were opaque (`wf-mtapqmfm-ad9ba7` everywhere) and
42
+ there was no way to list or operate on past runs except by
43
+ file-system diving. v0.7.0 adds:
44
+
45
+ - **6-character short IDs** (Crockford-style 32-char alphabet, no
46
+ `0/1/i/l/o` for visual clarity). Every new run gets a `shortId`
47
+ on both `state.json` and `report.json`. The full `wf-...` runId
48
+ stays the durable handle.
49
+ - **`bullswarm workflow runs ...`** sub-verb:
50
+ - `runs` (default = ongoing only) — list with a `●`/`○` marker
51
+ - `runs --all` — ongoing + historical
52
+ - `runs --historical` — only historical
53
+ - `runs --name <wf>` — filter by workflow
54
+ - `runs --limit N` — cap result count
55
+ - `runs show <id>` — dump `state.json` + `report.json`. Accepts
56
+ shortId, full runId, or run-dir path.
57
+ - `runs delete <id> --yes` — remove a run directory. Refuses
58
+ ongoing runs without `--force`.
59
+ - **Resume by short ID**: `bullswarm workflow run <wf> --resume
60
+ <shortId>` resolves the shortId to the full runId before any
61
+ dispatch. Bogus tokens fail fast, before workflow load.
62
+ - **`isOngoing(runDir, state)`** helper: classifies a run as
63
+ ongoing when `state.finishedAt` is unset AND `state.json` was
64
+ modified within the last 90 s. After the 90 s window a run is
65
+ treated as historical even if `finishedAt` was never written
66
+ (e.g. process killed before terminal `persist()`).
67
+
68
+ ### New files
69
+
70
+ - `src/workflow/short-id.js` — Crockford-style generator, resolver,
71
+ `isOngoing`, `listRuns`
72
+ - `src/workflow/runs-cli.js` — `cmdRuns` dispatch
73
+ - `tests/workflow-runs.test.js` — 16 new tests
74
+
75
+ ### Tests
76
+
77
+ - 16 new tests covering shortId generation, resolution, lock-free
78
+ ongoing detection, list filtering, show, delete, and the resume
79
+ pre-flight.
80
+ - Full suite is 147 green (131 prior + 16 new), stable across 3
81
+ stress runs.
82
+ - Verified end-to-end by `cmd -p --yolo` against a real CLI
83
+ installation: every step of the runbook passed.
84
+
85
+ ## 0.6.0 — incremental workflow drafts (CLI builder)
86
+
87
+ The static `workflow run <file>` shape required every workflow to be
88
+ authored as a JSON file in advance. That's not "dynamic" — it's a script
89
+ of record. v0.6.0 introduces `bullswarm workflow draft ...`, a
90
+ sub-verb group that lets you build a workflow interactively from the
91
+ shell, one mutation at a time. Drafts persist under
92
+ `~/.bullswarm/drafts/<name>/` and are promoted to first-class
93
+ workflows (discoverable, runnable by name, validatable) the moment
94
+ they're created.
95
+
96
+ ### New CLI surface
97
+
98
+ ```
99
+ bullswarm workflow draft create <name> [--description ...] [--input k=v]...
100
+ bullswarm workflow draft show <name>
101
+ bullswarm workflow draft list
102
+ bullswarm workflow draft phase add <name> <phase>
103
+ bullswarm workflow draft phase remove <name> <phase>
104
+ bullswarm workflow draft step add <name> <phase> <step-id> --type run|fanout|verify [--lane ... --prompt ... --add-dir ... --pool ... --items-from ... --review ... --concurrency N --timeout N --on-error ... --step-template <json>]
105
+ bullswarm workflow draft step remove <name> <phase> <step-id>
106
+ bullswarm workflow draft step set <name> <phase> <step-id> <field> --value <text>
107
+ bullswarm workflow draft set <name> <field> --value <text>
108
+ bullswarm workflow draft validate <name>
109
+ bullswarm workflow draft export <name> <out-file>
110
+ bullswarm workflow draft delete <name> --yes
111
+ bullswarm workflow draft run <name> [--input k=v]... [--resume id] [--json] [--quiet]
112
+ ```
113
+
114
+ - Every mutation re-validates immediately and persists the verdict on
115
+ `meta.json.lastValidation`. `bullswarm workflow list` shows drafts
116
+ with a `(draft)` tag.
117
+ - `bullswarm workflow run <draft-name>` and `workflow validate
118
+ <draft-name>` accept a draft name the same way they accept a JSON
119
+ filename — the new `workflowDirs()` entry `~/.bullswarm/drafts/`
120
+ makes drafts first-class.
121
+ - `bullswarm workflow draft export <name> <file>` promotes a draft
122
+ to a checked-in JSON for version control.
123
+ - Partial drafts (zero phases, or a phase with zero steps) are
124
+ treated as BUILDING, not INVALID — the validator's
125
+ `phases-must-be-non-empty` rule is downgraded to a warning during
126
+ construction. Real schema violations (bad lane, duplicate step id,
127
+ etc.) still return nonzero.
128
+ - `delete` requires `--yes` so a stray arrow-key can't nuke a draft.
129
+ - The `BULLSWARM_HOME` env var redirects drafts to a sandbox under
130
+ any temp dir, so the same `autoSetup` flow agents use elsewhere
131
+ works here.
132
+
133
+ ### Tests
134
+
135
+ - 25 new tests in `tests/workflow-draft.test.js`. Two layers:
136
+ module-level (no spawn) for every mutation, CLI-level (spawnSync)
137
+ for the user-facing contract.
138
+ - Full suite is now 131 green (106 prior + 25 new).
139
+
140
+ ### Files
141
+
142
+ - New: `src/workflow/draft.js` — storage, atomic writes, validation hook
143
+ - New: `src/workflow/draft-cli.js` — `cmdDraft` dispatch + flag parsing
144
+ - New: `tests/workflow-draft.test.js`
145
+ - Modified: `src/workflow/cli.js` (added `draft` sub-verb, drafts in
146
+ `workflowDirs()` and `discover()`)
147
+
148
+ ## 0.5.0 — gap-closure release
149
+
150
+ Workflow parity with Claude Code dynamic workflows plus deep-QA hardening.
151
+ All 10 gaps identified in the v0.4.0 audit are closed; 23 new tests
152
+ added; full suite is 105 green (82 prior + 23 new).
153
+
154
+ ### Workflow runtime (R-numbered doctrine)
155
+
156
+ - **R4 — global concurrency limiter**: a real `Semaphore` (`src/workflow/semaphore.js`) is shared by every `runSingle` and every fanout worker. Per-fanout worker count is capped at `min(per-fanout, limiter.permits, items.length)`. A `step.blocked` event fires when items queue behind the cap.
157
+ - **R6 — recursion-guard propagation**: every workflow dispatch computes `childDepthEnv(parentEnv)` and passes it to `watchOnce`. The runtime asserts `assertDepthAllowed(coreState, parentEnv)` before each dispatch. A workflow that itself spawns `bullswarm` is refused at the core's depth limit instead of recursing forever. `src/lib/watch.js` now honors caller-supplied `opts.env` so the depth env actually reaches the child.
158
+ - **R7 — quarantine + decision log on workflow auth failures**: when a dispatch inside a workflow returns `quarantineHint: true`, the runtime calls `quarantinePool(state, poolName, why, now)` against the core state file and appends a `source: "workflow"` entry to the shared `decisionLog` so `bullswarm health` and `pools` see workflow runs. The live `pools` view is updated so the next dispatch in the same run does not re-select the benched pool.
159
+ - **R8 — burst-gate exclusion in workflows**: `preparePools` now drops any pool with `burstGate === true` (5h ≥ 90 %), matching the single-run path.
160
+ - **R10 — fingerprint-aligned fanout resume**: every fanout result is now stamped with `sha1(JSON.stringify(item)).slice(0,12)`. On resume, items are matched by fingerprint first; positional alignment is a fallback for state.json from prior versions. Reordering, adding, or removing items no longer breaks resume.
161
+ - **R9 — outputText truncation**: `recordOutput` caps `state.outputs[id].outputText` at `OUTPUT_TEXT_CAP_BYTES = 64 KB`. The on-disk outFile always holds the full transcript. Persisted state.json is now bounded.
162
+
163
+ ### New step type: `verify` (skeptic)
164
+
165
+ - Adversarial review of a prior step. Schema: `{ type: "verify", review: "outputs.<prior>.outFile", lane, prompt?, timeoutSec? }`. The runtime reads the prior outFile, inlines it into a structured prompt asking for `RETURN ONLY {"ok": <bool>, "concerns": [...], "summary": ...}`, dispatches through the standard pool-routed pipeline, and parses the first JSON object in the response. Step is `ok:true` only if dispatch verifies AND the JSON `ok` is `true`. The parsed `verify` object is recorded on `state.outputs[id].verify` so downstream steps can reference `concerns` and `summary`.
166
+ - Validated: `review` must resolve to a known prior outFile or a declared input; `inputs.<k>.required` is now type-checked and runtime-enforced.
167
+ - See `workflows/verify-and-cap.json` for an end-to-end example.
168
+
169
+ ### New settings
170
+
171
+ - `settings.maxAgents` — hard cap; a step that would push dispatch count past the cap fails with `why: "spend guard: maxAgents=... reached"`.
172
+ - `settings.warnAtAgents` — advisory; a `workflow.large` event fires once when the threshold is crossed. TUI renders it as `⚠ Large workflow: N dispatches ≥ threshold M`.
173
+ - `settings.concurrency` is now validated to be `≤ 16`, matching Claude Code's runtime cap.
174
+ - `inputs.<k>.required: true` is now a hard pre-flight refusal. `runWorkflow` throws `required input "<k>" missing` before any dispatch.
175
+
176
+ ### New runtime events
177
+
178
+ - `item.skipped` — emitted by fanout resume; was dropped silently in TTY mode. Now rendered as `⏭ <stepId>[i] ok from previous run (resume)`.
179
+ - `step.blocked` — emitted when items queue behind the global cap; rendered as `⋈ N item(s) queued behind concurrency cap in <stepId>`.
180
+ - `workflow.large` — emitted once when the dispatch threshold is crossed.
181
+
182
+ ### CLI
183
+
184
+ - `BULLSWARM_HOME` env var now overrides the workflow CLI's `BULLSWARM_DIR` (previously hardcoded to `~/.bullswarm`). Matches the meter registry.
185
+ - `--input k=v` accepts JSON-encoded values so arrays and objects can be passed: `--input 'items=["a","b"]'`. The legacy string form is unchanged.
186
+
187
+ ### TUI
188
+
189
+ - `item.skipped`, `step.blocked`, and `workflow.large` are all rendered in human mode (previously `item.skipped` was TTY-invisible).
190
+
191
+ ### Tests
192
+
193
+ - 23 new tests in `tests/workflow-gaps.test.js`, one per gap closure.
194
+ - 105 total tests, all green, no network, ~1 s.
195
+
196
+ ### Files
197
+
198
+ - New: `src/workflow/semaphore.js`
199
+ - New: `tests/workflow-gaps.test.js`
200
+ - New: `workflows/verify-and-cap.json`
201
+ - New: `CHANGELOG.md`
202
+ - Modified: `src/workflow/runtime.js`, `src/workflow/runner.js`, `src/workflow/validate.js`, `src/workflow/tui.js`, `src/workflow/cli.js`, `src/lib/watch.js`
package/GOAL.md ADDED
@@ -0,0 +1,135 @@
1
+ # bullswarm — Goal Statement
2
+
3
+ **Status:** PROTOTYPE · **Owner:** cowcow02 · **Created:** 2026-08-21
4
+
5
+ ## One sentence
6
+
7
+ A standalone CLI that lets *any* coding agent offload work to *any other* coding
8
+ agent CLI on the same machine — routing by lane, pacing by subscription meter,
9
+ and verifying by content — so no provider's quota expires unused and no agent's
10
+ "success" is taken at face value.
11
+
12
+ ## Why this exists
13
+
14
+ Every agent CLI assumes it is the center of the universe. Multi-subscription
15
+ developers (Claude Max + Codex + Grok + …) watch quota expire on some pools
16
+ while others are exhausted mid-task, and every delegate CLI can exit 0 while
17
+ having done nothing. No existing router treats subscription windows as the
18
+ scheduling resource; proxy routers spend API credits instead of subscriptions;
19
+ prompt-policy layers can't compel dispatch. bullswarm sits *above* all agents as
20
+ the neutral coordinator vendors will never build.
21
+
22
+ ## Outcome
23
+
24
+ A working prototype installed at `~/.bullswarm/` with:
25
+
26
+ 1. **`bullswarm` CLI** with four verbs (`setup` detailed in #8):
27
+ - `setup` — interactive front door: discover → enable → route → write
28
+ - `run` — route → dispatch → watch → verify → one JSON verdict
29
+ (`ok`, `keepOnClaude`, `why`, `pick.command`, `contentUsableDespiteExit`)
30
+ - `health` — re-judge saved outputs against verdicts; surface gate failures
31
+ and quarantine clusters after every round
32
+ - `pools` — show each pool's meter state, pace position, quarantine status
33
+ 2. **Connector registry** (`~/.bullswarm/connectors/*.json`): declarative per-CLI
34
+ spawn command, auth-failure signatures, output extraction, verify contract,
35
+ quirk fields (e.g. PWD resolution). Seeded with codex, grok,
36
+ command-code, opencode2 — extracted from the proven `/offload` skill.
37
+ 3. **Meter layer**: per-pool window definition (5h / weekly / none) with
38
+ programmatic readers where providers expose usage, manual declaration
39
+ (`--meter pool=window,pct`) where they don't. Unmetered pools pace as
40
+ time-proportional and are labeled as such.
41
+ 4. **Pacing brain**: time-adjusted pace (elapsed% − used%; most-behind wins),
42
+ incumbency margin, cost guard (pace may only promote a cheaper pool),
43
+ lanes by work nature (analyze/build/chore) — never a hard-coded lane→pool map.
44
+ 5. **Verify gate**: content-based judgment ported intact from delegate-watch —
45
+ exit code never trusted alone, announcement-vs-work splitting, failure
46
+ patterns scoped to first 400 chars (whole text under 600), fixture suite
47
+ green before any release.
48
+ 6. **Recursion guard**: depth limit owned by the core; an offloaded agent that
49
+ calls bullswarm cannot exceed configured depth.
50
+ 7. **MCP server**: exposes `run`/`health`/`pools` so Claude Code, Codex, Cursor
51
+ or any MCP client can offload without shell plumbing.
52
+ 8. **Setup wizard as the front door**: bare `bullswarm` with no config (or
53
+ `bullswarm setup`) launches an interactive guide that:
54
+ - **discovers** installed agent CLIs (binary on PATH + config dir present +
55
+ cheap auth probe — never credential entry), showing quota/burn-rate state
56
+ per pool immediately; burn rate starts empty and is labeled "learning"
57
+ until the decision log fills it;
58
+ - lets the user **toggle which discovered pools to enable**;
59
+ - **suggests a routing table** (lane → pool defaults from enabled pools)
60
+ presented as an editable artifact, not a questionnaire;
61
+ - writes `~/.bullswarm/` config + connectors, idempotent and re-runnable
62
+ (`bullswarm setup` repairs);
63
+ - can generate an agent-facing integration block for CLAUDE.md / AGENTS.md,
64
+ shown as a diff with explicit approval before any write, delimited by
65
+ versioned `bullswarm:begin/end` markers (pilotfish pattern);
66
+ - a thin companion skill (`bullswarm-setup`) ships alongside so agents can
67
+ recommend running `/bullswarm:setup` to users — the skill nudges, the CLI
68
+ owns the flow.
69
+
70
+ ## Success proofs
71
+
72
+ The prototype is done when ALL hold:
73
+
74
+ - [x] `bullswarm run --lane analyze --add-dir <repo> --task-file t.md --json`
75
+ returns a verdict whose shape matches the delegate-watch contract, using
76
+ a real pool, end to end, on this machine.
77
+ - [x] The verify gate passes its full fixture suite (≥17 fixtures:
78
+ true failures AND real outputs) unchanged in behavior vs. `/offload`.
79
+ - [x] `bullswarm pools` reflects a manually declared meter change within one
80
+ run, and pace ordering flips the pick when a pool crosses the margin.
81
+ - [x] A wrong-repo scenario (stale PWD) produces a correct-repo dispatch for
82
+ every connector whose quirk field declares it.
83
+ - [x] `bullswarm health` flags a planted FAILED-verdict-but-good-output case
84
+ and a two-quarantine cluster.
85
+ - [x] An MCP client (Claude Code) completes one offload round via the MCP
86
+ server with zero shell commands.
87
+ - [x] Recursion guard stops a self-calling delegate at the configured depth.
88
+ - [x] Bare `bullswarm` on a machine with no `~/.bullswarm/` launches the
89
+ wizard; discovery lists at least the four seeded connectors with correct
90
+ found/not-found status, and completing it produces a working `run`.
91
+ - [x] The wizard's CLAUDE.md/AGENTS.md integration step shows a diff and
92
+ writes nothing without explicit approval; re-running setup is idempotent
93
+ (no duplicate marker blocks).
94
+ - [x] `bullswarm setup` on an already-configured machine reports current state
95
+ and repairs a deliberately broken connector file.
96
+
97
+ ## Invariants
98
+
99
+ - Judge by CONTENT, not exit code. A non-zero exit is never a success;
100
+ `ok:true` requires passing verification.
101
+ - Never hard-code lane→pool mappings; pools serve lanes only via runtime
102
+ selection over declared capability.
103
+ - Delegate output is input to verify, never the answer. Final synthesis,
104
+ architecture decisions, and anything needing live conversation context stay
105
+ with the caller.
106
+ - Quarantine must have a re-probe path; a recovered pool must return to
107
+ service automatically (this fixes the known `/offload` gap).
108
+ - Connector quirks live in connector files, never in core logic.
109
+ - Stealth/retention-hostile models are opt-in per connector, flagged in the
110
+ registry, never defaults.
111
+
112
+ ## Non-goals (prototype)
113
+
114
+ - No hosted service, no daemon required for basic operation.
115
+ - No per-host hook integrations beyond MCP.
116
+ - No measured routing table yet (smart-router-style pass@k benchmarking is
117
+ post-prototype).
118
+ - No savings ledger yet (post-prototype).
119
+ - Windows support deferred; macOS/Linux first.
120
+
121
+ ## Authority envelope
122
+
123
+ Build freely inside `~/Repo/bullswarm`. Installing to `~/.bullswarm/` and
124
+ reading existing `~/.claude/skills/offload/*` sources for extraction is
125
+ authorized. Do NOT modify the live `/offload` skill during extraction — copy,
126
+ never move. No publishing (npm/GitHub push) without explicit instruction.
127
+
128
+ ## Provenance
129
+
130
+ Extracted from the working `/offload` system (~/.claude/skills/offload/):
131
+ delegate-route.mjs (routing brain), delegate-watch.mjs (verify+watch),
132
+ delegate-health.mjs (re-judging), SKILL.md (operational doctrine). The four
133
+ 2026-08-21 failure modes (wrong-repo silence, three verify-gate bugs, invisible
134
+ workflow health, exit-1-after-success) are the regression baseline this
135
+ prototype must never reintroduce.
package/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # bullswarm
2
2
 
3
- Route work across coding-agent CLIs. The frontier agent keeps orchestration,
4
- judgment, and synthesis; bounded work goes to whichever subscription has the
5
- most quota left; every delegate output is judged by content before it counts.
3
+ Route work across coding-agent CLIs. For a goal, Bullswarm can choose a capable
4
+ orchestrator, build and expand the plan, route bounded worker actions by quota,
5
+ verify the result, and finish without an initiating agent authoring a graph.
6
+ Every delegate output is judged by content before it counts.
6
7
 
7
8
  ## The doctrine (non-negotiable)
8
9
 
@@ -12,9 +13,9 @@ most quota left; every delegate output is judged by content before it counts.
12
13
  2. **Pace by meter.** The scheduling resource is the subscription window:
13
14
  elapsed% minus used%, most-behind pool wins. Pace may only promote a
14
15
  *cheaper* pool. Lanes are work-nature, never hard-coded to pools.
15
- 3. **Delegate output is input, never the answer.** Final synthesis,
16
- architecture decisions, and anything needing live conversation context
17
- stays with the caller.
16
+ 3. **Delegate output is evidence, never authority.** A goal orchestrator may
17
+ synthesize completion, but only after the deterministic runtime accepts its
18
+ bounded plan and durable verification evidence.
18
19
  4. **Quarantine re-probes.** A benched pool must be able to return to service
19
20
  automatically; a lane is never allowed to silently go down.
20
21
 
@@ -30,7 +31,9 @@ npm install -g bullswarm # or: node bin/bullswarm.js directly from a checkout
30
31
  bullswarm # first run: interactive setup wizard
31
32
  bullswarm setup # re-run or repair
32
33
  bullswarm pools # meter state, pace position, quarantine status
34
+ bullswarm strategy refresh --apply --yes # approve capability-aware tier autopilot
33
35
  bullswarm run --lane analyze --add-dir ~/some-repo --task-file /tmp/t.md --json
36
+ bullswarm workflow goal "Fix the failing tests and verify the change" --cwd ~/some-repo
34
37
  bullswarm health # re-judge saved outputs; catch gate failures
35
38
  ```
36
39
 
@@ -42,6 +45,220 @@ bullswarm health # re-judge saved outputs; catch gate failures
42
45
  | `run` | route → dispatch → watch → verify → one JSON verdict |
43
46
  | `health` | Re-judge saved outputs against their verdicts; surface verify-gate failures and quarantine clusters |
44
47
  | `pools` | Show each pool's meter state, pace position, quarantine status |
48
+ | `strategy` | Discover models, record subscription value, recommend or assign high/medium/low effort routes |
49
+ | `doctor` | Machine-readable readiness report; self-heals on first call |
50
+ | `workflow` | Start an autonomous goal, or run / validate / draft / inspect explicit workflows and their live instances. |
51
+
52
+ ## Model strategy and invocation telemetry
53
+
54
+ Bullswarm can inventory the models exposed by installed agent CLIs and combine
55
+ connector-declared, dated pricing/benchmark metadata with live quota surplus:
56
+
57
+ ```bash
58
+ bullswarm strategy refresh
59
+ bullswarm strategy show --json
60
+ bullswarm strategy apply --yes --refresh-hours 24
61
+ bullswarm strategy auto status
62
+ bullswarm strategy set-subscription command-code \
63
+ --plan GOAT --monthly-usd 10 --included-usd 70 --quota-window monthly
64
+ bullswarm strategy assign high --pool claude-code --model claude-opus-4-6
65
+ bullswarm run --effort high --lane analyze --task-file /tmp/task.md --json
66
+ ```
67
+
68
+ Interactive setup asks whether to enable strategy autopilot; non-interactive
69
+ setup requires the explicit `setup --yes --strategy` flag. Recommendations are
70
+ context-filtered before ranking: high requires analysis plus workflow-planning,
71
+ medium requires build/edit capabilities, and low targets bounded chores. An
72
+ approved policy refreshes stale discovery before later runs and re-applies the
73
+ best eligible models on its configured interval. Disable it with
74
+ `strategy auto off --yes`. Discovery commands, model argument syntax, pricing,
75
+ and benchmark declarations remain connector-owned. Unknown license value,
76
+ prices, and benchmarks stay `null` rather than being guessed. An assignment is
77
+ only a preference: quarantine, exhaustion, burst gates, and capability checks
78
+ still win.
79
+
80
+ Every run and workflow attempt reports its selected agent/model and estimated
81
+ usage. When a delegate does not expose counters, Bullswarm labels its UTF-8
82
+ byte/4 token estimate. The breakdown separates standard read, cache read,
83
+ cache write, and output; API-equivalent cost and normalized subscription quota
84
+ remain unknown unless the connector and user-provided subscription data can
85
+ support them. `workflow tui --json <id>` exposes the aggregate and the full
86
+ phase/step/attempt tree.
87
+
88
+ ## One-command autonomous goals
89
+
90
+ For normal multi-step work, give Bullswarm the goal—not a JSON graph:
91
+
92
+ ```bash
93
+ # Foreground: streams progress and returns when terminal.
94
+ bullswarm workflow goal \
95
+ "Fix the failing tests with the smallest correct change and verify them" \
96
+ --cwd ~/some-repo
97
+
98
+ # Detached: the initiating CLI exits; the workflow continues independently.
99
+ bullswarm workflow goal \
100
+ "Audit and repair the parser, then run its acceptance tests" \
101
+ --cwd ~/some-repo --detach --json
102
+ ```
103
+
104
+ Bullswarm first honors an approved high-tier provider/model assignment when it
105
+ remains eligible, otherwise it selects an eligible `workflow-planning`
106
+ orchestrator by live quota surplus. The orchestrator observes durable evidence, proposes bounded actions,
107
+ and decides when another expansion or verification is necessary. Bullswarm
108
+ validates the proposal, owns agent/process selection, routes workers, and calls
109
+ the orchestrator again until completion, cancellation, failure, approval, or a
110
+ budget limit. No initial phases, prompts, JSON schema, or agent choice are
111
+ required from the user.
112
+
113
+ The detached response includes a short ID and exact observation commands:
114
+
115
+ ```bash
116
+ bullswarm workflow runs show <shortId>
117
+ bullswarm workflow tui <shortId> # printable phase/action/attempt tree
118
+ bullswarm workflow tui --json <shortId>
119
+ bullswarm workflow events --json <shortId> --after 0
120
+ bullswarm workflow action show --json <shortId> <actionId>
121
+ ```
122
+
123
+ Resume a process-interrupted autonomous run from its persisted workflow:
124
+
125
+ ```bash
126
+ bullswarm workflow goal --resume <shortId> --json
127
+ ```
128
+
129
+ `--orchestrator <pool>` exists for controlled testing; ordinary use should
130
+ leave selection on `auto`. Hard limits can be adjusted with `--max-agents`,
131
+ `--max-expansion-rounds`, `--max-actions`, `--max-items-per-expansion`, and
132
+ `--max-workflow-seconds`. Interactive setup also records a worktree-isolation
133
+ preference (`agent-decides`, `off`, or `required`); Bullswarm communicates that
134
+ policy to the orchestrator without imposing repository topology itself.
135
+
136
+ ## Building a workflow from the shell
137
+
138
+ Use an explicit draft when the graph itself is a durable contract and should
139
+ not be planner-defined. `bullswarm workflow draft ...` lets you assemble it one
140
+ mutation at a time. No upfront JSON required. Drafts persist under
141
+ `~/.bullswarm/drafts/<name>/` and become first-class workflows
142
+ (discoverable, runnable by name) the moment they exist.
143
+
144
+ ```bash
145
+ bullswarm workflow draft create audit-code \
146
+ --description "Audit the source code" --input targetDir=.
147
+ bullswarm workflow draft phase add audit-code discover
148
+ bullswarm workflow draft phase add audit-code review
149
+ bullswarm workflow draft step add audit-code discover list-files \
150
+ --type run --lane chore --prompt "List every .js file in src/" \
151
+ --addDir '{{inputs.targetDir}}'
152
+ bullswarm workflow draft step add audit-code review per-file \
153
+ --type fanout --items-from 'outputs.list-files.outFile' \
154
+ --lane analyze --concurrency 2 \
155
+ --step-template '{"lane":"analyze","addDir":"{{inputs.targetDir}}","prompt":"Review {{item}}"}'
156
+ bullswarm workflow draft show audit-code # inspect the JSON
157
+ bullswarm workflow draft run audit-code # execute it
158
+ bullswarm workflow draft export audit-code workflows/audit-code.json # promote to file
159
+ ```
160
+
161
+ `step add` re-validates after every mutation; partial drafts (zero
162
+ phases, etc.) are treated as building, not invalid. `set` and
163
+ `step set` patch fields in place. `delete` requires `--yes`.
164
+
165
+ ## Operating on workflow runs
166
+
167
+ Every run gets a 6-character shortId (Crockford-style alphabet,
168
+ no `0/1/i/l/o`). The full `wf-...` runId stays the durable handle.
169
+
170
+ ```bash
171
+ bullswarm workflow runs # ongoing only (default)
172
+ bullswarm workflow runs --all # ongoing + historical
173
+ bullswarm workflow runs --historical # only historical
174
+ bullswarm workflow runs --name audit-code # filter by workflow
175
+ bullswarm workflow runs --limit 20 # cap the result count
176
+ bullswarm workflow runs show <shortId> # state + report + summary
177
+ bullswarm runs show <shortId> # top-level shorthand
178
+ bullswarm workflow runs delete <shortId> --yes # remove the run dir
179
+
180
+ # Resume by shortId — runs the same logic as the full runId
181
+ bullswarm workflow run audit-code --resume <shortId>
182
+ ```
183
+
184
+ ### Live workflow dashboard
185
+
186
+ `workflow tui` is the interactive, Claude-style `/workflows` view. It watches
187
+ ongoing runs from disk and supports `j`/`k` or arrow-key selection, Enter for
188
+ details, `c` to request a cooperative stop, `r` to refresh, and `q` to quit.
189
+
190
+ ```bash
191
+ bullswarm workflow tui
192
+ ```
193
+
194
+ The same dashboard is agent-friendly and never requires a TTY when used with
195
+ JSON/control flags:
196
+
197
+ ```bash
198
+ bullswarm workflow tui --json # ongoing dashboard rows
199
+ bullswarm workflow tui --json --all # ongoing + historical runs
200
+ bullswarm workflow tui --json <shortId> # inspect one run
201
+ bullswarm workflow tui --json --cancel <id> # request cooperative stop
202
+ bullswarm workflow capabilities --json # pools, lanes, models, meters, limits
203
+ bullswarm workflow inspect <file-or-name> # workflow shape and semantics
204
+ bullswarm workflow events --json <id> --after 20
205
+ bullswarm workflow action show --json <id> <actionId>
206
+ bullswarm workflow approval approve --json <id> # then resume the run
207
+ ```
208
+
209
+ Cancellation is persisted as `cancelling`, terminates an active child process,
210
+ records its termination signal and latency evidence, then commits `cancelled`.
211
+ `SIGTERM` and `SIGINT` use the same cooperative child termination path but
212
+ commit a distinct resumable `interrupted` state. On every workflow command,
213
+ active states with a dead/stale owner are automatically reconciled to
214
+ `interrupted` instead of remaining falsely `running`.
215
+
216
+ Each attempt records the phase/action, selected pool and model, effort tier,
217
+ routing reason, all eligible candidates with quota surplus, timestamps,
218
+ artifact paths, outcome, and reported-or-estimated token/cost/quota usage.
219
+ `workflow tui <id>` renders this breakdown for completed runs as well as live
220
+ ones; `workflow tui --json <id>` exposes the durable audit document.
221
+
222
+ ### Adaptive workflows
223
+
224
+ Static workflows remain zero-extra-LLM orchestration. An adaptive workflow adds
225
+ an explicit `decide` step and hard limits:
226
+
227
+ ```json
228
+ {
229
+ "mode": "adaptive",
230
+ "settings": {
231
+ "maxAgents": 12,
232
+ "maxExpansionRounds": 3,
233
+ "maxActions": 20,
234
+ "maxItemsPerExpansion": 8,
235
+ "maxWorkflowSeconds": 1800
236
+ },
237
+ "phases": [{
238
+ "name": "review",
239
+ "steps": [
240
+ { "id": "initial", "type": "run", "prompt": "Inspect the code." },
241
+ {
242
+ "id": "planner",
243
+ "type": "decide",
244
+ "requiresCapabilities": ["workflow-planning", "strong-analysis"],
245
+ "prompt": "Judge sufficiency and propose only bounded missing work."
246
+ }
247
+ ]
248
+ }]
249
+ }
250
+ ```
251
+
252
+ The planner returns versioned JSON. It may propose `needs_more_work` with
253
+ bounded `run`, inline-`fanout`, or `verify` actions. The deterministic runtime
254
+ validates IDs, dependencies, operation types, capabilities, and budgets before
255
+ appending anything. It executes ready actions, observes their durable results,
256
+ and calls the planner again. `events.jsonl`, `state.json`, the TUI, and JSON
257
+ inspection expose the same plan, actions, attempts, decisions, budgets, and
258
+ artifacts. See `workflows/adaptive-code-review.json` for a complete example.
259
+ Planner actions cannot set `pool`, `addDir`, or `taskFile`. If those need to be
260
+ fixed by the initiator, declare them under the `decide` step's `actionDefaults`;
261
+ otherwise eligible capable pools are ranked by live quota surplus.
45
262
 
46
263
  ## The verdict
47
264