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.
- package/CHANGELOG.md +41 -0
- package/README.md +67 -49
- package/bin/check-v2-evidence.js +26 -0
- package/bin/check-v2-plan.js +36 -0
- package/connectors/opencode2.json +1 -0
- package/docs/dynamic-workflow-v2-execution-plan.md +825 -0
- package/docs/experiments/2026-08-29-dogfood-bullswarm-builds-bullswarm.md +27 -0
- package/docs/experiments/2026-08-31-v2-component-probes.md +52 -0
- package/package.json +1 -1
- package/skill/SKILL.md +2 -2
- package/skill/references/operations.md +11 -9
- package/src/cli.js +23 -8
- package/src/help.js +50 -38
- package/src/lib/run-heartbeat.js +59 -0
- package/src/lib/watch.js +34 -0
- package/src/workflow/action-validator.js +411 -0
- package/src/workflow/cli.js +124 -162
- package/src/workflow/dashboard.js +338 -29
- package/src/workflow/draft-cli.js +2 -2
- package/src/workflow/events.js +8 -3
- package/src/workflow/evidence-output.js +187 -0
- package/src/workflow/goal.js +24 -162
- package/src/workflow/ledger.js +261 -0
- package/src/workflow/ownership.js +133 -0
- package/src/workflow/runner.js +1 -17
- package/src/workflow/runs-cli.js +44 -1
- package/src/workflow/short-id.js +6 -2
- package/src/workflow/steering.js +7 -4
- package/src/workflow/v2-dispatch.js +277 -0
- package/src/workflow/v2-outcome.js +288 -0
- package/src/workflow/v2-planner.js +259 -0
- package/src/workflow/v2-presentation.js +50 -0
- package/src/workflow/v2-runtime.js +797 -0
- package/src/workflow/v2-scheduler.js +159 -0
- package/src/workflow/v2-state.js +578 -0
- package/src/workflow/v2-workspace.js +103 -0
- 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
|
|
4
|
-
|
|
5
|
-
|
|
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
|
|
26
|
-
`bullswarm workflow tui <shortId
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
terminals
|
|
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.**
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
|
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
|
|
220
|
-
|
|
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
|
|
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
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
|
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.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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
|
-
###
|
|
454
|
+
### Authored adaptive graphs
|
|
439
455
|
|
|
440
|
-
|
|
441
|
-
an explicit `decide` step, advisory
|
|
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
|
|
470
|
-
|
|
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
|
-
|
|
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" }
|