bullswarm 0.21.0 → 0.22.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 (37) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +67 -49
  3. package/bin/check-v2-evidence.js +26 -0
  4. package/bin/check-v2-plan.js +36 -0
  5. package/connectors/opencode2.json +1 -0
  6. package/docs/dynamic-workflow-v2-execution-plan.md +825 -0
  7. package/docs/experiments/2026-08-29-dogfood-bullswarm-builds-bullswarm.md +27 -0
  8. package/docs/experiments/2026-08-31-v2-component-probes.md +52 -0
  9. package/package.json +1 -1
  10. package/skill/SKILL.md +2 -2
  11. package/skill/references/operations.md +11 -9
  12. package/src/cli.js +23 -8
  13. package/src/help.js +50 -38
  14. package/src/lib/run-heartbeat.js +59 -0
  15. package/src/lib/watch.js +34 -0
  16. package/src/workflow/action-validator.js +411 -0
  17. package/src/workflow/cli.js +124 -162
  18. package/src/workflow/dashboard.js +338 -29
  19. package/src/workflow/draft-cli.js +2 -2
  20. package/src/workflow/events.js +8 -3
  21. package/src/workflow/evidence-output.js +187 -0
  22. package/src/workflow/goal.js +24 -162
  23. package/src/workflow/ledger.js +261 -0
  24. package/src/workflow/ownership.js +133 -0
  25. package/src/workflow/runner.js +1 -17
  26. package/src/workflow/runs-cli.js +44 -1
  27. package/src/workflow/short-id.js +6 -2
  28. package/src/workflow/steering.js +7 -4
  29. package/src/workflow/v2-dispatch.js +277 -0
  30. package/src/workflow/v2-outcome.js +288 -0
  31. package/src/workflow/v2-planner.js +259 -0
  32. package/src/workflow/v2-presentation.js +50 -0
  33. package/src/workflow/v2-runtime.js +797 -0
  34. package/src/workflow/v2-scheduler.js +159 -0
  35. package/src/workflow/v2-state.js +578 -0
  36. package/src/workflow/v2-workspace.js +103 -0
  37. package/src/workflow/watch-cli.js +62 -9
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # bullswarm changelog
2
2
 
3
+ ## 0.22.0 — autonomous Dynamic Workflow V2
4
+
5
+ - Autonomous goals now run on the V2 kernel: agents propose bounded programs
6
+ and requirement-scoped evidence, while Bullswarm deterministically owns
7
+ proposal validation, scheduling, workspace ownership, retries, the evidence
8
+ ledger, completion, and the stable result envelope. Retired autonomous V1
9
+ runs are intentionally not migrated; authored graph workflows remain a
10
+ separate supported engine.
11
+
12
+ - Worker and evidence contracts now use durable candidate files plus local
13
+ schema validators, preventing malformed agent output from entering workflow
14
+ state. Public V2 results are atomically published, recoverable after an
15
+ interrupted terminal write, deeply validated when read, and expose only a
16
+ stable failure summary shape.
17
+
18
+ - The interactive workflow application now combines the workflow list and
19
+ responsive run browser. Its main view presents a phase-aware timeline,
20
+ Workflow Planner milestones, live workers with their latest streamed event,
21
+ and a concise next action; technical prompts, sessions, usage, and artifact
22
+ paths remain available on demand. Narrow/mobile terminals use the same
23
+ hierarchy without requiring a separate command surface.
24
+
25
+ - `bullswarm run --heartbeat` and the default workflow watch provide compact,
26
+ interval-based progress instead of streaming raw agent output. Rich help and
27
+ the packaged agent skill document how to inspect, watch, browse, and obtain a
28
+ stable terminal result.
29
+
30
+ - Autonomous V2 `maxAgents`, `maxActions`, and `maxExpansionRounds` are now
31
+ soft planning targets instead of hard termination or proposal-rejection
32
+ limits. The planner sees usage and remaining-target signals and is urged to
33
+ consolidate optional work, while the kernel continues the smallest essential
34
+ program past a target. `concurrency` remains an execution bound on
35
+ simultaneous work, not on the total program size.
36
+
37
+ - OpenCode event-stream failures are now classified as transient provider
38
+ interruptions before structured-output validation runs. A recoverable
39
+ transport or schema attempt is recorded as `interrupted` while Bullswarm
40
+ performs its bounded mechanical retry; only an unrecovered final attempt is
41
+ recorded as `failed`, keeping provider instability distinct from agent work
42
+ rejection.
43
+
3
44
  ## 0.21.0 — unified TUI shell and LLM-first delegation
4
45
 
5
46
  - The interactive workflow viewer is now one application shell instead of
package/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # bullswarm
2
2
 
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.
3
+ Route work across coding-agent CLIs. For a goal, Bullswarm chooses a capable
4
+ Workflow Planner, validates its bounded generic action program, routes work and
5
+ evidence agents by quota, and computes completion from a durable requirement
6
+ ledger without an initiating agent authoring a graph.
6
7
  Every delegate output is judged by content before it counts.
7
8
 
8
9
  For agents, `/bullswarm` (or `$bullswarm` where skills use that syntax) is the
@@ -22,11 +23,12 @@ bullswarm workflow draft step add --help
22
23
  `workflow goal` launches a durable background runner, prints operating commands,
23
24
  and returns by default. Add `--watch` to immediately follow low-noise progress
24
25
  until terminal, or `--foreground` to keep execution owned by the initiating
25
- terminal. Open the full-screen Phase → Agent → Activity viewer at any time with
26
- `bullswarm workflow tui <shortId>`; use Up/Down, Enter, Esc, and `q` to detach.
27
- Wide terminals use two
28
- contextual panes (phases + agents, then agents + activity); narrow and mobile
29
- terminals give each level the full screen automatically.
26
+ terminal. Open the unified workflow home with bare `bullswarm workflow`, or
27
+ jump directly to one run with `bullswarm workflow tui <shortId>`. The default
28
+ detail view is a human timeline with Live agents and a plain-language Next
29
+ line; `v` reveals technical state. Wide terminals use a workflow sidebar plus
30
+ detail pane, while narrow/mobile terminals show one pane at a time. `q`
31
+ detaches safely.
30
32
 
31
33
  ## The doctrine (non-negotiable)
32
34
 
@@ -36,9 +38,9 @@ terminals give each level the full screen automatically.
36
38
  2. **Pace by meter.** The scheduling resource is the subscription window:
37
39
  elapsed% minus used%, most-behind pool wins. Pace may only promote a
38
40
  *cheaper* pool. Lanes are work-nature, never hard-coded to pools.
39
- 3. **Delegate output is evidence, never authority.** A goal orchestrator may
40
- synthesize completion, but only after the deterministic runtime accepts its
41
- bounded plan and durable verification evidence.
41
+ 3. **Delegate output is evidence, never authority.** The Workflow Planner may
42
+ propose actions, but only the deterministic kernel validates the program,
43
+ accepts requirement-scoped evidence, and computes completion.
42
44
  4. **Quarantine re-probes.** A benched pool must be able to return to service
43
45
  automatically; a lane is never allowed to silently go down.
44
46
 
@@ -93,6 +95,9 @@ bullswarm health # re-judge saved outputs; catch gate failures
93
95
  | `strategy` | Discover models, record subscription value, recommend or assign high/medium/low effort routes |
94
96
  | `doctor` | Machine-readable readiness report; self-heals on first call |
95
97
  | `workflow` | Start an autonomous goal, or run / validate / draft / inspect explicit workflows and their live instances. |
98
+ | `runs` | Short alias for `workflow runs`, including list, show, result, delete, and cleanup operations. |
99
+ | `version` / `--version` | Print the installed Bullswarm version. |
100
+ | `release` | Run the guarded local version-bump, commit, and tag workflow used before CI publishes to npm. |
96
101
 
97
102
  ### Delegate classification
98
103
 
@@ -180,28 +185,36 @@ bullswarm workflow goal \
180
185
  --cwd ~/some-repo --watch
181
186
  ```
182
187
 
183
- Bullswarm first honors an approved high-tier provider/model assignment when it
184
- remains eligible, otherwise it selects an eligible `workflow-planning`
185
- orchestrator by live quota surplus. The orchestrator is one durable control-plane
186
- conversation: Grok and Claude resume the same provider session at later
187
- checkpoints, while Bullswarm keeps each turn separately auditable for routing,
188
- usage, and recovery. It observes durable evidence, proposes bounded actions,
189
- and decides when another expansion or verification is necessary. Bullswarm
190
- validates the proposal, owns agent/process selection, routes workers, and calls
191
- the orchestrator again until completion, cancellation, failure, approval, or a
192
- hard graph-growth safeguard. No initial phases, prompts, JSON schema, or agent choice are
193
- required from the user.
194
-
195
- Planner actions carry forward-only kebab-case phase names. A finished phase is
196
- sealed: later planner turns must create a new phase for repair or verification,
197
- so the TUI cannot jump backward or append work beneath a completed phase.
188
+ `--max-agents`, `--max-actions`, and `--max-expansion-rounds` are soft V2
189
+ planning targets. They encourage the Workflow Planner to consolidate optional
190
+ work, but the kernel never stops or rejects essential work merely because a
191
+ target was reached. `--concurrency` still bounds simultaneous dispatches so
192
+ the scheduler can batch a wider useful program safely.
193
+
194
+ Bullswarm first runs optional read-only reconnaissance, then invokes one
195
+ logical, resumable Workflow Planner conversation. The planner proposes a
196
+ complete bounded program of generic actions. Work actions produce artifacts;
197
+ evidence actions independently judge named requirements. The kernel rejects
198
+ malformed, cyclic, overlapping, or needlessly serialized proposals before
199
+ dispatch, runs dependency-ready file-disjoint actions concurrently, and
200
+ updates the requirement ledger from schema-valid evidence. Only real
201
+ consolidated gaps re-enter the planner. There are no formal reviewer or repair
202
+ roles and no automatic semantic repair/reverify loop.
203
+
204
+ The planner does not author phases or declare success/failure. The kernel
205
+ derives stable presentation stages for the TUI and computes the final V2
206
+ result. Old autonomous run directories are not migrated or resumed;
207
+ explicitly naming one fails before any paid dispatch. Fixed JSON workflows and
208
+ drafts remain a separate authored-graph feature with their existing step
209
+ types.
198
210
 
199
211
  The detached response includes a short ID and exact observation commands:
200
212
 
201
213
  ```bash
202
214
  bullswarm workflow runs show <shortId>
203
215
  bullswarm workflow watch <shortId> # low-noise live progress + terminal timing
204
- bullswarm workflow tui <shortId> # printable phase/action/attempt tree
216
+ bullswarm workflow # unified human workflow home
217
+ bullswarm workflow tui <shortId> # jump directly to one run timeline
205
218
  bullswarm workflow tui --json <shortId>
206
219
  bullswarm workflow events --json <shortId> --after 0
207
220
  bullswarm workflow action show --json <shortId> <actionId>
@@ -216,8 +229,8 @@ bullswarm workflow goal --resume <shortId> --json
216
229
  `--orchestrator <pool>` expresses a preference and immediately falls back to
217
230
  another eligible pool if that provider is quota-gated or unavailable. Ordinary
218
231
  use can leave selection on `auto`. For controlled provider QA only,
219
- `--strict-orchestrator <pool>` requires that exact pool and may wait for its
220
- quota window. Controlled comparisons can additionally pin the exact planner
232
+ `--strict-orchestrator <pool>` requires that exact pool and fails if it is not
233
+ available. Controlled comparisons can additionally pin the exact planner
221
234
  and worker routes without changing global strategy:
222
235
 
223
236
  ```bash
@@ -226,8 +239,7 @@ bullswarm workflow goal "Implement and verify the change" --cwd . \
226
239
  --worker-pool opencode2 --worker-model kaihk/gpt-5.6-luna
227
240
  ```
228
241
 
229
- The worker lock covers the scout, ordinary runs, fan-out items, repairs,
230
- re-verification, and runtime extraction helpers. A pool that cannot guarantee
242
+ The worker lock covers scout, work actions, and evidence actions. A pool that cannot guarantee
231
243
  the requested model is ineligible rather than silently substituting another
232
244
  model.
233
245
 
@@ -240,13 +252,18 @@ per provider — the first as the primary `opencode2` pool, each additional one
240
252
  as its own `opencode2:<id>` pool — which is what the `--worker-model
241
253
  kaihk/gpt-5.6-luna` example above locks onto.
242
254
 
243
- `--max-agents` and `--max-workflow-seconds` are
244
- advisory planning targets; `--max-expansion-rounds` is also an advisory
245
- convergence target. Hard structural safeguards are adjusted with
246
- `--max-actions` and `--max-items-per-expansion`.
255
+ `--max-agents`, `--max-actions`, and `--max-expansion-rounds` are soft V2
256
+ planning targets: they guide the planner toward a small program but do not
257
+ hard-stop useful work. `--concurrency` is the actual bound on simultaneous
258
+ dependency-ready dispatches. There is no default wall-clock timeout: fresh
259
+ semantic/transport heartbeats allow a useful worker to continue, while silence
260
+ is inspected rather than blindly killed.
247
261
  Interactive setup also records a worktree-isolation
248
262
  preference (`agent-decides`, `off`, or `required`); Bullswarm communicates that
249
- policy to the orchestrator without imposing repository topology itself.
263
+ policy to the V2 kernel. Unless explicitly set to `off`, mutating autonomous
264
+ actions use isolated worktrees; the kernel checks actual changed paths against
265
+ declared ownership before integration. `off` serializes shared-workspace
266
+ writers and still enforces the changed-path boundary.
250
267
 
251
268
  ## Building a workflow from the shell
252
269
 
@@ -308,12 +325,11 @@ Values accept ISO timestamps, local `YYYY-MM-DD` dates, `today`, `yesterday`,
308
325
 
309
326
  After a workflow reaches a terminal state, agents should consume
310
327
  `workflow runs result <id> --json` instead of probing `state.json`, task files,
311
- or provider-specific output. The versioned `bullswarm.workflow.result.v1`
312
- envelope retains the primary `delivery`, adds a `deliveries[]` frontier when
313
- parallel workers jointly form the outcome, and identifies their strongest
314
- matching verification verdict. It also includes progress, step logs, tokens, and an explicitly
315
- complete-or-partial tool-call total. `runs show` remains the low-level debugging
316
- surface.
328
+ or provider-specific output. Autonomous V2 returns the versioned
329
+ `bullswarm.workflow.result.v2` envelope with kernel-computed status, fresh
330
+ requirement evidence, action/artifact records, explicit gaps, usage, and
331
+ verification qualification. Fixed authored workflows retain their existing
332
+ result envelope. `runs show` remains the low-level debugging surface.
317
333
  Goal launch output includes an `instructions` handoff with four named paths:
318
334
  `agentInspect` for a machine-readable snapshot, `watch` for low-noise progress,
319
335
  `humanTui` for the interactive browser, and `result` for the terminal delivery.
@@ -435,11 +451,11 @@ runtime value and uses its matching connector rate metadata for the attempt's
435
451
  cost estimate. Unknown or provider-hidden model identity remains explicitly
436
452
  unknown.
437
453
 
438
- ### Adaptive workflows
454
+ ### Authored adaptive graphs
439
455
 
440
- Static workflows remain zero-extra-LLM orchestration. An adaptive workflow adds
441
- an explicit `decide` step, advisory resource targets, and structural expansion
442
- limits:
456
+ This is part of the separately authored fixed-graph engine, not the autonomous
457
+ V2 `workflow goal` path. A graph may add an explicit `decide` step, advisory
458
+ resource targets, and structural expansion limits:
443
459
 
444
460
  ```json
445
461
  {
@@ -466,8 +482,9 @@ limits:
466
482
  }
467
483
  ```
468
484
 
469
- `maxAgents`, `maxWorkflowSeconds`, and `maxExpansionRounds` are advisory inputs
470
- to the orchestrator. Approaching them strongly biases the planner toward
485
+ For an authored adaptive graph, `maxAgents`, `maxWorkflowSeconds`, and
486
+ `maxExpansionRounds` are advisory inputs to its decide step. Approaching them
487
+ strongly biases that step toward
471
488
  consolidating existing artifacts and returning the best useful outcome;
472
489
  crossing them is recorded but never stops a worker, skips verification, or
473
490
  fails a run. `maxActions` and `maxItemsPerExpansion` remain hard structural
@@ -476,7 +493,8 @@ rather than discarding the run as a blanket failure. Delegates have no
476
493
  implicit wall-clock timeout; set a step's `timeoutSec` (or direct-run
477
494
  `--timeout`) only when an operator explicitly wants a hard termination timer.
478
495
 
479
- An autonomous `complete` remains strictly verified. A planner `stop` still
496
+ Within this authored-graph engine, `complete` remains strictly verified. A
497
+ decide-step `stop` still
480
498
  delivers a completed outcome when a useful delivery exists: unresolved
481
499
  verification concerns and the stopping reason ride along as `outcome.concerns`
482
500
  and `outcome.reason`, attributes of that completed outcome rather than a
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'node:fs';
4
+ import { validateEvidenceOutput } from '../src/workflow/evidence-output.js';
5
+
6
+ function parseArgs(args) {
7
+ if (args.length !== 4 || args[0] !== '--contract' || args[2] !== '--value' || !args[1] || !args[3] || args[1].startsWith('--') || args[3].startsWith('--')) return null;
8
+ return { contractPath: args[1], valuePath: args[3] };
9
+ }
10
+
11
+ const parsed = parseArgs(process.argv.slice(2));
12
+ if (!parsed) {
13
+ console.error('Usage: check-v2-evidence --contract <contract.json> --value <candidate.json>');
14
+ process.exit(2);
15
+ }
16
+
17
+ try {
18
+ const contract = JSON.parse(readFileSync(parsed.contractPath, 'utf8'));
19
+ const value = JSON.parse(readFileSync(parsed.valuePath, 'utf8'));
20
+ const result = validateEvidenceOutput(value, contract);
21
+ process.stdout.write(`${JSON.stringify({ ok: result.ok, errors: result.errors })}\n`);
22
+ process.exit(result.ok ? 0 : 1);
23
+ } catch (error) {
24
+ process.stdout.write(`${JSON.stringify({ ok: false, errors: [error.message] })}\n`);
25
+ process.exit(1);
26
+ }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { validateV2PlannerResponse } from '../src/workflow/v2-planner.js';
5
+ import { deserializeV2DurableState } from '../src/workflow/v2-state.js';
6
+ import { extractScoutUnitIds } from '../src/workflow/goal.js';
7
+
8
+ function parseArgs(args) {
9
+ if (args.length !== 6 || args[0] !== '--state' || args[2] !== '--boundary' || args[4] !== '--value') return null;
10
+ const [, statePath, , boundary, , valuePath] = args;
11
+ if (!statePath || !valuePath || !['initial', 'gaps', 'steering'].includes(boundary)) return null;
12
+ if (statePath.startsWith('--') || valuePath.startsWith('--')) return null;
13
+ return { statePath, boundary, valuePath };
14
+ }
15
+
16
+ const parsed = parseArgs(process.argv.slice(2));
17
+ if (!parsed) {
18
+ console.error('Usage: check-v2-plan --state <state.json> --boundary <initial|gaps|steering> --value <candidate.json>');
19
+ process.exit(2);
20
+ }
21
+
22
+ try {
23
+ const state = deserializeV2DurableState(readFileSync(parsed.statePath, 'utf8'));
24
+ const value = JSON.parse(readFileSync(parsed.valuePath, 'utf8'));
25
+ const scoutPath = state.preflight.scout.outputFile;
26
+ const requiredScoutUnits = parsed.boundary === 'initial' && scoutPath && existsSync(scoutPath)
27
+ ? extractScoutUnitIds(readFileSync(scoutPath, 'utf8'))
28
+ : [];
29
+ validateV2PlannerResponse(value, state, { boundary: parsed.boundary, requiredScoutUnits });
30
+ process.stdout.write(`${JSON.stringify({ ok: true, errors: [] })}\n`);
31
+ process.exit(0);
32
+ } catch (error) {
33
+ const errors = Array.isArray(error?.issues) ? error.issues : [error.message];
34
+ process.stdout.write(`${JSON.stringify({ ok: false, errors })}\n`);
35
+ process.exit(1);
36
+ }
@@ -13,6 +13,7 @@
13
13
  "format": "jsonl",
14
14
  "args": ["--format", "json"],
15
15
  "silenceThresholdSec": 600,
16
+ "failureTypes": ["error"],
16
17
  "rules": [
17
18
  { "rootMatch": { "path": "type", "equals": "tool_use" }, "idPaths": ["part.callID", "part.id"], "kindPaths": ["part.tool"], "summaryPaths": ["part.state.input.command", "part.state.input.file_path", "part.state.input.path", "part.state.title"], "statusPath": "part.state.status" },
18
19
  { "rootMatch": { "path": "type", "equals": "text" }, "idPaths": ["part.id"], "kind": "response", "summaryPaths": ["part.text"], "status": "completed" }