bullswarm 0.20.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 (42) hide show
  1. package/CHANGELOG.md +100 -1
  2. package/README.md +104 -54
  3. package/bin/check-v2-evidence.js +26 -0
  4. package/bin/check-v2-plan.js +36 -0
  5. package/connectors/opencode2.json +3 -2
  6. package/docs/dynamic-workflow-v2-execution-plan.md +825 -0
  7. package/docs/experiments/2026-08-29-dogfood-bullswarm-builds-bullswarm.md +189 -0
  8. package/docs/experiments/2026-08-31-v2-component-probes.md +52 -0
  9. package/docs/integration-audit-2026-08-31.md +411 -0
  10. package/package.json +1 -1
  11. package/skill/SKILL.md +13 -5
  12. package/skill/references/operations.md +11 -4
  13. package/src/cli.js +23 -8
  14. package/src/delegate.js +120 -3
  15. package/src/help.js +58 -43
  16. package/src/lib/opencode-kaihk.js +16 -4
  17. package/src/lib/run-heartbeat.js +59 -0
  18. package/src/lib/watch.js +34 -0
  19. package/src/workflow/action-validator.js +411 -0
  20. package/src/workflow/cli.js +124 -162
  21. package/src/workflow/dashboard.js +827 -145
  22. package/src/workflow/draft-cli.js +2 -2
  23. package/src/workflow/events.js +8 -3
  24. package/src/workflow/evidence-output.js +187 -0
  25. package/src/workflow/goal.js +24 -162
  26. package/src/workflow/ledger.js +261 -0
  27. package/src/workflow/ownership.js +133 -0
  28. package/src/workflow/runner.js +9 -24
  29. package/src/workflow/runs-cli.js +44 -1
  30. package/src/workflow/short-id.js +6 -2
  31. package/src/workflow/status.js +2 -1
  32. package/src/workflow/steering.js +7 -4
  33. package/src/workflow/tui.js +30 -7
  34. package/src/workflow/v2-dispatch.js +277 -0
  35. package/src/workflow/v2-outcome.js +288 -0
  36. package/src/workflow/v2-planner.js +259 -0
  37. package/src/workflow/v2-presentation.js +50 -0
  38. package/src/workflow/v2-runtime.js +797 -0
  39. package/src/workflow/v2-scheduler.js +159 -0
  40. package/src/workflow/v2-state.js +578 -0
  41. package/src/workflow/v2-workspace.js +103 -0
  42. package/src/workflow/watch-cli.js +62 -9
package/CHANGELOG.md CHANGED
@@ -1,12 +1,111 @@
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
+
44
+ ## 0.21.0 — unified TUI shell and LLM-first delegation
45
+
46
+ - The interactive workflow viewer is now one application shell instead of
47
+ several screens with their own rules. The workflows list, a run, a phase and
48
+ an agent are four depths of one hierarchy: every screen carries the same
49
+ persistent breadcrumb at the top (`Workflows › hdtdxs · timeline-segments ›
50
+ Verify › verify-renderer`), which drops its deepest segments first when the
51
+ terminal is too narrow to hold the whole path. All four depths share key
52
+ bindings generated from a single key-map definition: Up/Down (or k/j) move
53
+ within the current level, Enter and Right (or l) go one level in, Esc and
54
+ Left (or h) go one level out, and Tab/Shift+Tab jump to the next or previous
55
+ workflow, re-entering the sibling at the same depth when the equivalent phase
56
+ exists. The drill-down layout is uniform too — a left sidebar listing the
57
+ current level beside a right pane previewing the highlighted item — at every
58
+ depth and on narrow terminals as well, including the run list, which was a
59
+ full-width table with no preview pane before.
60
+
61
+ - Workflow timelines now render in phase-segmented sections with continued
62
+ headers for interleaved phases, grouped Preflight scout/planner milestones,
63
+ elapsed or running phase state, and consistent desktop, narrow, and scroll
64
+ continuation behavior without per-line phase prefixes. Phase-completion
65
+ summary rows are retained, so rows such as `└─✓ completed 4/4` remain visible
66
+ beneath their phase headers.
67
+
68
+ - Non-interactive `workflow tui <run-id>` output now includes the same static
69
+ segmented timeline as the interactive viewer, alongside the historical detail
70
+ tree, so real command output can be used to inspect and verify the layout.
71
+
72
+ - Documentation now describes concerns as an attribute of a completed
73
+ outcome — `outcome.concerns` on a delivered result — rather than
74
+ presenting `completed_with_concerns` as its own terminal status to handle
75
+ separately from `completed`. Run records that carry the
76
+ `completed_with_concerns` status value, including legacy runs recorded
77
+ before this framing, remain fully readable: `runs result`, the TUI, and
78
+ `workflow watch` still read it exactly like `completed` — a delivered
79
+ result with concerns to review, never a failure.
80
+
81
+ - Delegation classification now starts with deterministic signals and, in
82
+ automatic execution, lets an LLM refine the choice between a single delegate
83
+ and a workflow. `--dry-run` performs that same bounded low-effort
84
+ classification request (one analyze-lane, low-effort dispatch) before
85
+ printing the plan, so the preview matches what a live run would decide — it
86
+ never dispatches the work itself. `--classify deterministic` bypasses that
87
+ refinement and remains the instant, no-dispatch preview; `--classify llm`
88
+ requires the refinement and fails if no usable LLM decision is available.
89
+ An explicit `--mode single|workflow` remains the caller's choice and bypasses
90
+ automatic LLM classification.
91
+
92
+ - OpenCode connector portability: `connectors/opencode2.json` no longer
93
+ hardcodes `--model kaihk/gpt-5.6-luna` in `spawn.cmd`. A plain OpenCode
94
+ install with no KaiHK provider configured now dispatches with OpenCode's
95
+ own default model instead of failing to resolve a KaiHK-only model.
96
+ `src/lib/opencode-kaihk.js` still injects the explicit
97
+ `--model <providerId>/gpt-5.6-luna` for each discovered KaiHK provider, so
98
+ the primary `opencode2` pool and any extra `opencode2:<id>` pools keep
99
+ dispatching with their pinned per-provider model exactly as before.
100
+
3
101
  ## 0.20.0 — common agent delegation entry point
4
102
 
5
103
  - `/bullswarm` and `bullswarm delegate` now give agents one transparent entry
6
104
  point for arbitrary self-contained tasks: classify the request as one bounded
7
105
  delegate or an autonomous workflow, show the reason and conceptual plan, then
8
106
  execute the selected engine. Explicit mode and lane overrides remain
9
- available, and `--dry-run --json` exposes the decision without dispatching.
107
+ available, and `--dry-run --json` exposes the decision after its bounded
108
+ classification request without dispatching the work itself.
10
109
  - Workflow decisions persist the suggested conceptual plan alongside the
11
110
  original intent, while the packaged skill keeps the common path concise and
12
111
  moves operational detail into a focused reference.
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
 
@@ -73,7 +75,7 @@ bullswarm pools # meter state, pace position, quarantine status
73
75
  bullswarm strategy refresh --apply --yes # approve capability-aware tier autopilot
74
76
  bullswarm delegate --cwd ~/some-repo --prompt "Explain the parser" # one agent
75
77
  bullswarm delegate --cwd ~/some-repo --prompt "Audit all commands, fix help, and independently verify" # workflow
76
- bullswarm delegate --dry-run --json --cwd ~/some-repo --prompt "Your task" # decision + plan only
78
+ bullswarm delegate --dry-run --json --cwd ~/some-repo --prompt "Your task" # bounded classification + decision/plan; no work dispatch
77
79
  bullswarm run --lane analyze --add-dir ~/some-repo --task-file /tmp/t.md --json
78
80
  bullswarm run --lane analyze --add-dir ~/some-repo --prompt "Inspect the parser" --json
79
81
  bullswarm workflow goal "Fix the failing tests and verify the change" --cwd ~/some-repo
@@ -93,6 +95,25 @@ 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. |
101
+
102
+ ### Delegate classification
103
+
104
+ With the default `--mode auto`, `delegate` first uses deterministic task
105
+ signals, then uses an LLM to refine the choice between a single delegate and a
106
+ workflow during execution. If that optional refinement is unavailable or
107
+ unusable, automatic mode uses the deterministic decision.
108
+
109
+ Use `--classify deterministic` to bypass the LLM refinement — this is the
110
+ instant, no-dispatch preview. Use `--classify llm` when an LLM decision is
111
+ required: the command fails if it cannot obtain a usable one. In automatic
112
+ mode, `--dry-run` still performs that same bounded low-effort classification
113
+ request (one analyze-lane, low-effort dispatch) and prints the resulting
114
+ decision — it never dispatches the work itself. An explicit `--mode single` or
115
+ `--mode workflow` is the caller's decision and bypasses automatic LLM
116
+ classification.
96
117
 
97
118
  Discover and validate workflow definitions without executing them:
98
119
 
@@ -164,28 +185,36 @@ bullswarm workflow goal \
164
185
  --cwd ~/some-repo --watch
165
186
  ```
166
187
 
167
- Bullswarm first honors an approved high-tier provider/model assignment when it
168
- remains eligible, otherwise it selects an eligible `workflow-planning`
169
- orchestrator by live quota surplus. The orchestrator is one durable control-plane
170
- conversation: Grok and Claude resume the same provider session at later
171
- checkpoints, while Bullswarm keeps each turn separately auditable for routing,
172
- usage, and recovery. It observes durable evidence, proposes bounded actions,
173
- and decides when another expansion or verification is necessary. Bullswarm
174
- validates the proposal, owns agent/process selection, routes workers, and calls
175
- the orchestrator again until completion, cancellation, failure, approval, or a
176
- hard graph-growth safeguard. No initial phases, prompts, JSON schema, or agent choice are
177
- required from the user.
178
-
179
- Planner actions carry forward-only kebab-case phase names. A finished phase is
180
- sealed: later planner turns must create a new phase for repair or verification,
181
- 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.
182
210
 
183
211
  The detached response includes a short ID and exact observation commands:
184
212
 
185
213
  ```bash
186
214
  bullswarm workflow runs show <shortId>
187
215
  bullswarm workflow watch <shortId> # low-noise live progress + terminal timing
188
- 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
189
218
  bullswarm workflow tui --json <shortId>
190
219
  bullswarm workflow events --json <shortId> --after 0
191
220
  bullswarm workflow action show --json <shortId> <actionId>
@@ -200,8 +229,8 @@ bullswarm workflow goal --resume <shortId> --json
200
229
  `--orchestrator <pool>` expresses a preference and immediately falls back to
201
230
  another eligible pool if that provider is quota-gated or unavailable. Ordinary
202
231
  use can leave selection on `auto`. For controlled provider QA only,
203
- `--strict-orchestrator <pool>` requires that exact pool and may wait for its
204
- 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
205
234
  and worker routes without changing global strategy:
206
235
 
207
236
  ```bash
@@ -210,16 +239,31 @@ bullswarm workflow goal "Implement and verify the change" --cwd . \
210
239
  --worker-pool opencode2 --worker-model kaihk/gpt-5.6-luna
211
240
  ```
212
241
 
213
- The worker lock covers the scout, ordinary runs, fan-out items, repairs,
214
- 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
215
243
  the requested model is ineligible rather than silently substituting another
216
- model. `--max-agents` and `--max-workflow-seconds` are
217
- advisory planning targets; `--max-expansion-rounds` is also an advisory
218
- convergence target. Hard structural safeguards are adjusted with
219
- `--max-actions` and `--max-items-per-expansion`.
244
+ model.
245
+
246
+ The `opencode2` connector itself does not require a KaiHK provider: its base
247
+ spawn command carries no hardcoded model, so a plain OpenCode installation
248
+ dispatches with OpenCode's own configured default. When
249
+ `~/.config/opencode/opencode.json` has one or more KaiHK providers configured,
250
+ Bullswarm discovers them and pins an explicit `--model <providerId>/gpt-5.6-luna`
251
+ per provider — the first as the primary `opencode2` pool, each additional one
252
+ as its own `opencode2:<id>` pool — which is what the `--worker-model
253
+ kaihk/gpt-5.6-luna` example above locks onto.
254
+
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.
220
261
  Interactive setup also records a worktree-isolation
221
262
  preference (`agent-decides`, `off`, or `required`); Bullswarm communicates that
222
- 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.
223
267
 
224
268
  ## Building a workflow from the shell
225
269
 
@@ -281,12 +325,11 @@ Values accept ISO timestamps, local `YYYY-MM-DD` dates, `today`, `yesterday`,
281
325
 
282
326
  After a workflow reaches a terminal state, agents should consume
283
327
  `workflow runs result <id> --json` instead of probing `state.json`, task files,
284
- or provider-specific output. The versioned `bullswarm.workflow.result.v1`
285
- envelope retains the primary `delivery`, adds a `deliveries[]` frontier when
286
- parallel workers jointly form the outcome, and identifies their strongest
287
- matching verification verdict. It also includes progress, step logs, tokens, and an explicitly
288
- complete-or-partial tool-call total. `runs show` remains the low-level debugging
289
- 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.
290
333
  Goal launch output includes an `instructions` handoff with four named paths:
291
334
  `agentInspect` for a machine-readable snapshot, `watch` for low-noise progress,
292
335
  `humanTui` for the interactive browser, and `result` for the terminal delivery.
@@ -408,11 +451,11 @@ runtime value and uses its matching connector rate metadata for the attempt's
408
451
  cost estimate. Unknown or provider-hidden model identity remains explicitly
409
452
  unknown.
410
453
 
411
- ### Adaptive workflows
454
+ ### Authored adaptive graphs
412
455
 
413
- Static workflows remain zero-extra-LLM orchestration. An adaptive workflow adds
414
- an explicit `decide` step, advisory resource targets, and structural expansion
415
- 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:
416
459
 
417
460
  ```json
418
461
  {
@@ -439,8 +482,9 @@ limits:
439
482
  }
440
483
  ```
441
484
 
442
- `maxAgents`, `maxWorkflowSeconds`, and `maxExpansionRounds` are advisory inputs
443
- 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
444
488
  consolidating existing artifacts and returning the best useful outcome;
445
489
  crossing them is recorded but never stops a worker, skips verification, or
446
490
  fails a run. `maxActions` and `maxItemsPerExpansion` remain hard structural
@@ -449,11 +493,17 @@ rather than discarding the run as a blanket failure. Delegates have no
449
493
  implicit wall-clock timeout; set a step's `timeoutSec` (or direct-run
450
494
  `--timeout`) only when an operator explicitly wants a hard termination timer.
451
495
 
452
- An autonomous `complete` remains strictly verified. A planner `stop` produces
453
- `completed_with_concerns` when a useful delivery exists, including unresolved
454
- verification concerns and the stopping reason; it produces `blocked` only
455
- when no useful delivery exists. `workflow runs result` treats the qualified
456
- delivery as ready while reporting `verified:false`.
496
+ Within this authored-graph engine, `complete` remains strictly verified. A
497
+ decide-step `stop` still
498
+ delivers a completed outcome when a useful delivery exists: unresolved
499
+ verification concerns and the stopping reason ride along as `outcome.concerns`
500
+ and `outcome.reason`, attributes of that completed outcome rather than a
501
+ separate terminal status. `stop` produces `blocked` only when no useful
502
+ delivery exists. `workflow runs result` treats the completed outcome as ready
503
+ while reporting `verified:false`. The status value `completed_with_concerns`
504
+ still appears on some runs — including legacy ones recorded before this
505
+ framing — and every consumer reads it exactly like `completed`: a delivered
506
+ result with concerns to review, never a failure.
457
507
 
458
508
  The planner returns versioned JSON. It may propose `needs_more_work` with
459
509
  bounded `run`, inline-`fanout`, or `verify` actions. The deterministic runtime
@@ -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
+ }
@@ -3,7 +3,7 @@
3
3
  "bin": "opencode",
4
4
  "configDirs": ["~/.config/opencode"],
5
5
  "spawn": {
6
- "cmd": ["opencode", "run", "--auto", "--model", "kaihk/gpt-5.6-luna", "{taskFile}"],
6
+ "cmd": ["opencode", "run", "--auto", "{taskFile}"],
7
7
  "cwdMode": "pwd",
8
8
  "$comment-cwdMode": "QUIRK: resolves its project from $PWD, not the spawn cwd. The watcher MUST set env.PWD and spawn with cwd inside the target repo, or it will silently analyse the wrong repository and answer confidently about it."
9
9
  },
@@ -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" }
@@ -21,7 +22,7 @@
21
22
  { "match": { "path": "type", "equals": "text" }, "path": "part.text", "mode": "concat", "separator": "\n" }
22
23
  ]
23
24
  },
24
- "$comment-auto": "--auto is required for headless workflow dispatch: task files live under ~/.bullswarm, outside the target repo, and OpenCode otherwise pauses for an interactive permission approval. --model pins the QA/runtime pool to Luna instead of the CLI default.",
25
+ "$comment-auto": "--auto is required for headless workflow dispatch: task files live under ~/.bullswarm, outside the target repo, and OpenCode otherwise pauses for an interactive permission approval. The base connector intentionally leaves --model unset so a plain OpenCode installation uses its own default; opencode-kaihk.js adds --model <providerId>/gpt-5.6-luna only for discovered KaiHK providers, after which modelSelection can replace it for assignments and step locks.",
25
26
  "$comment-exit1": "known failure mode: writes a complete correct answer, then dies with a Console-sync auth error and exit 1. The verdict sets contentUsableDespiteExit instead of discarding the work.",
26
27
  "meter": { "type": "none" },
27
28
  "costRank": 1,