Swarm mode — cyberine run --mode swarm (plan -> parallel-chunk implement -> merge)
For tasks that decompose cleanly into disjoint chunks — large multi-file refactors, sweep updates
across many files, any scope where one worker would burn tool rounds but N workers can split the
work in parallel — use --mode swarm. The orchestrator decomposes the task, fans out one worker
per chunk in isolated worktrees, then merges all the diffs into a single landing.
When to use swarm vs compete (--mode omitted = compete, the previous default):
compete (default) | swarm | |
|---|---|---|
| Topology | one task -> N agents in parallel -> DiffJudge picks ONE winning diff | plan -> N parallel chunks -> SwarmMergeJudge merges ALL diffs |
| Best for | single design choice with multiple implementations to compare (refactor an auth module, add one tool, fix one bug) | mass multi-file scope that decomposes into disjoint chunks (sweep a refactor across many files, update all dependencies, split a large feature across subsystems) |
| Workers | CYBERINE_BUILD_FLEET (all eligible writers race) | CYBERINE_SWARM_FLEET (one worker per chunk; disjoint ownsFiles per chunk) |
| Judge chain | ['diff', 'behavior'] (full apply + typecheck + verifyCmd gate) | ['diff'] (SwarmMergeJudge sequential apply + typecheck + integration-fix retry) |
| Escalation | none — step errors and the run ends | M5: a failed swarm run auto-redispatches in compete mode with the failure lessons appended |
| Output | the winning diff (one) | the merged diff (union of every chunk) |
The flow (plan -> cluster(lanes) -> per-lane workers -> merge). The workflow is
src/engine/swarmTaskWorkflow.ts:
- plan — at module load the schema-forced
SwarmPlannermakes ONE LLM call (DeepSeek-direct preferred, OpenRouter fallback) and decomposesCYBERINE_TASKinto aSwarmPlanof disjoint chunks. Each chunk carriesownsFiles(the glob of files it is allowed to edit),prompt(chunk-specific instructions), anddependsOn(DAG edges — see step 2 for the runtime guarantee). The plan also carries asharedContractthat is spliced into every chunk prompt so the chunks stay consistent on types, function signatures, and naming. No live-tree mutation in this step. - cluster (lanes) —
clusterChunks(T263) builds a lane graph whose edges are the UNION (or selection —CYBERINE_SWARM_GROUP_BY) of file-overlap edges anddependsOnedges. Connected components of that graph becomeSwarmLanes; the chunks inside one lane share a worktree and run serially in topological order so a dependent chunk sees its upstream chunk's commits IN TREE.packLanes(T264) bin-packs the lanes under a governor cap (CYBERINE_SWARM_LANES; auto = fleet size). See "Lane grouping" for the invariant and theCYBERINE_SWARM_GROUP_BY/CYBERINE_SWARM_LANES/CYBERINE_SWARM_MAX_LANE_SIZEknobs. - swarm (per-lane workers) —
isolate: true+swarmChunks: <plan>+swarmUseLaneRunner: true(the T269 wiring) routes throughrunSwarmLaneRunner(T265), which provisions ONE worktree per lane and dispatches the lane's chunks serially viachunkDispatch(round-robin pick from the fleet). After each chunk the runner commits (swarm-lane(<laneId>): chunk <id> [title] (i/N)) so the next chunk in the lane sees the prior chunks' work IN TREE; on chunk hard-fail the lane aborts perfailureMode: 'stop'and the committed prefix is kept. Lanes run in parallel under the cap. Per-chunk retry-once + per-lane failure handling (T266) surfaces gaps loudly. - merge —
LaneMergeJudge(T267) sequentially applies every lane's cumulative diff to a clean integration worktree offHEAD, gates onnpm run typecheck(the default; override withCYBERINE_VERIFY_CMD), and on failure runs an LLM-driven integration-fix pass (CYBERINE_SWARM_MERGE_RETRIES=1default;0fail-fast). When the merge passes, the merged diff is emitted as the step'swinnerOutput— same land-gate contract as compete (apply it withcyberine apply <runId>orcyberine land <runId>). - review (downstream step) — a cheap adversarial reviewer (
opencode plan+loop-deepseek-direct) reads the merged diff and emits aVERDICT: <approve|risk>digest to surface cross-chunk issues typecheck alone cannot catch (wiring drift, dead code, contract drift, semantic garbage).
The command. --mode swarm is the only knob the CLI exposes; the rest is env vars:
# Swarm mode — plan -> parallel-chunk implement -> merge
cyberine run --mode swarm "refactor the auth module across all files"
cyberine run --mode swarm --bg "update all dependency versions" # detached (shows in cyberine agents)
# Env equivalent (priority: --mode flag > CYBERINE_MODE env)
CYBERINE_MODE=swarm cyberine run --bg "split the audit subsystem"
# Compete mode (default; --mode omitted is the same thing)
cyberine run "fix the off-by-one in pagination"
cyberine run --mode compete "refactor the auth module" # explicit: full fleet race + BehaviorJudge gate
# Override the swarm worker fleet (defaults to the built-in swarm worker list)
CYBERINE_SWARM_FLEET="opencode-deepseek,claude,codex" \
cyberine run --mode swarm "..."Planner failure is non-fatal. When the planner cannot run (no DEEPSEEK_API_KEY /
OPENROUTER_API_KEY, network failure, schema parse error, empty CYBERINE_TASK), the workflow
falls back to a single-chunk single-worker plan and restricts the fleet to ONE worker — N workers
on one chunk would conflict at apply time (every diff targets the same files; only the first
applies). A stderr note is printed so the operator notices. The run still completes end-to-end.
Run the swarm workflow directly (no cyberine run parent) for dogfooding:
CYBERINE_TASK="Add a sandbox-pinned grep_files tool as src/tools/grep.ts" \
CYBERINE_SWARM_FLEET="opencode-deepseek,claude,codex" \
npm run wf -- src/engine/swarmTaskWorkflow.tsEnv knobs (full defaults in the canonical table below): CYBERINE_SWARM_FLEET (worker list,
falls back to CYBERINE_BUILD_FLEET then the default swarm list), CYBERINE_SWARM_MAX_CHUNKS
(planner cap, [2, 16], default min(8, max(2, fleet length || 4))),
CYBERINE_SWARM_MERGE_RETRIES (SwarmMergeJudge integration-fix retry budget, default 1; 0
disables).
OpenTelemetry GenAI export — CYBERINE_OTEL_ENDPOINT (kyv0t)
run.json/events.jsonl is a proprietary, Cyberine-only format with no interop. Setting CYBERINEOTELENDPOINT turns on an exporter that maps RunStore run/step/worker events onto spans and ships them...
Lane grouping — when lanes help vs flat fan-out
The T269 lane runner is the default swarm executor in --mode swarm. It runs the plan through clusterChunks + packLanes BEFORE workers fan out, so the chunks a worker can see on disk follow the...