opencode-swarm 6.13.3 → 6.14.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/README.md +85 -32
- package/dist/cli/index.js +8 -5
- package/dist/index.js +43 -20
- package/dist/tools/phase-complete.d.ts +16 -0
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ This checks that everything is wired up correctly.
|
|
|
76
76
|
|
|
77
77
|
### Configure Models (Optional)
|
|
78
78
|
|
|
79
|
-
By default, Swarm uses
|
|
79
|
+
By default, Swarm v6.14+ uses free OpenCode Zen models (no API key required). You can override any agent's model by creating `.opencode/swarm.json` in your project. See the [LLM Provider Guide](#llm-provider-guide) for all options.
|
|
80
80
|
|
|
81
81
|
```json
|
|
82
82
|
{
|
|
@@ -127,6 +127,60 @@ Use `/swarm status` at any time to see where things stand.
|
|
|
127
127
|
|
|
128
128
|
---
|
|
129
129
|
|
|
130
|
+
## LLM Provider Guide
|
|
131
|
+
|
|
132
|
+
Swarm works with any LLM provider supported by OpenCode. Different agents benefit from different models — the architect needs strong reasoning, the coder needs strong code generation, and the reviewer benefits from a model different from the coder (to catch blind spots).
|
|
133
|
+
|
|
134
|
+
### Free Tier (OpenCode Zen Models)
|
|
135
|
+
|
|
136
|
+
OpenCode Zen provides free models via the `opencode/` provider prefix. These are excellent starting points and require no API key:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"agents": {
|
|
141
|
+
"coder": { "model": "opencode/minimax-m2.5-free" },
|
|
142
|
+
"reviewer": { "model": "opencode/big-pickle" },
|
|
143
|
+
"test_engineer":{ "model": "opencode/gpt-5-nano" },
|
|
144
|
+
"explorer": { "model": "opencode/trinity-large-preview-free" },
|
|
145
|
+
"sme": { "model": "opencode/trinity-large-preview-free" },
|
|
146
|
+
"critic": { "model": "opencode/trinity-large-preview-free" },
|
|
147
|
+
"docs": { "model": "opencode/trinity-large-preview-free" },
|
|
148
|
+
"designer": { "model": "opencode/trinity-large-preview-free" }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
> Save this configuration to `.opencode/swarm.json` in your project root (or `~/.config/opencode/opencode-swarm.json` for global config).
|
|
154
|
+
|
|
155
|
+
> **Note:** The `architect` key is intentionally omitted — it inherits whatever model you have selected in the OpenCode UI for maximum reasoning quality.
|
|
156
|
+
|
|
157
|
+
### Paid Providers
|
|
158
|
+
|
|
159
|
+
For production use, mix providers to maximize quality across writing vs. reviewing:
|
|
160
|
+
|
|
161
|
+
| Agent | Recommended Model | Why |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| `architect` | OpenCode UI selection | Needs strongest reasoning |
|
|
164
|
+
| `coder` | `minimax-coding-plan/MiniMax-M2.5` | Fast, accurate code generation |
|
|
165
|
+
| `reviewer` | `zai-coding-plan/glm-5` | Different training data from coder |
|
|
166
|
+
| `test_engineer` | `minimax-coding-plan/MiniMax-M2.5` | Same strengths as coder |
|
|
167
|
+
| `explorer` | `google/gemini-2.5-flash` | Fast read-heavy analysis |
|
|
168
|
+
| `sme` | `kimi-for-coding/k2p5` | Strong domain expertise |
|
|
169
|
+
| `critic` | `zai-coding-plan/glm-5` | Independent plan review |
|
|
170
|
+
| `docs` | `zai-coding-plan/glm-4.7-flash` | Fast, cost-effective documentation generation |
|
|
171
|
+
| `designer` | `kimi-for-coding/k2p5` | Strong UI/UX generation capabilities |
|
|
172
|
+
|
|
173
|
+
### Provider Formats
|
|
174
|
+
|
|
175
|
+
| Provider | Format | Example |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| OpenCode Zen (free) | `opencode/<model>` | `opencode/trinity-large-preview-free` |
|
|
178
|
+
| Anthropic | `anthropic/<model>` | `anthropic/claude-opus-4-6` |
|
|
179
|
+
| Google | `google/<model>` | `google/gemini-2.5-flash` |
|
|
180
|
+
| Z.ai | `zai-coding-plan/<model>` | `zai-coding-plan/glm-5` |
|
|
181
|
+
| MiniMax | `minimax-coding-plan/<model>` | `minimax-coding-plan/MiniMax-M2.5` |
|
|
182
|
+
| Kimi | `kimi-for-coding/<model>` | `kimi-for-coding/k2p5` |
|
|
183
|
+
|
|
130
184
|
## Useful Commands
|
|
131
185
|
|
|
132
186
|
| Command | What It Does |
|
|
@@ -381,6 +435,35 @@ Config file location: `~/.config/opencode/opencode-swarm.json` (global) or `.ope
|
|
|
381
435
|
|
|
382
436
|
### Automation
|
|
383
437
|
|
|
438
|
+
## Mode Detection (v6.13)
|
|
439
|
+
|
|
440
|
+
Swarm now explicitly distinguishes five architect modes:
|
|
441
|
+
|
|
442
|
+
- **`DISCOVER`** — After the explorer finishes scanning the codebase.
|
|
443
|
+
- **`PLAN`** — When the architect writes or updates the plan.
|
|
444
|
+
- **`EXECUTE`** — During task implementation (the normal pipeline).
|
|
445
|
+
- **`PHASE-WRAP`** — After all tasks in a phase are completed, before docs are updated.
|
|
446
|
+
- **`UNKNOWN`** — Fallback when the current state does not match any known mode.
|
|
447
|
+
|
|
448
|
+
Each mode determines which injection blocks are added to the LLM prompt (e.g., plan cursor is injected in `PLAN`, tool output truncation in `EXECUTE`, etc.).
|
|
449
|
+
|
|
450
|
+
Default mode: `manual`. No background automation — all actions require explicit slash commands.
|
|
451
|
+
|
|
452
|
+
Modes:
|
|
453
|
+
|
|
454
|
+
- `manual` — No background automation. All actions via slash commands (default).
|
|
455
|
+
- `hybrid` — Background automation for safe operations, manual for sensitive ones.
|
|
456
|
+
- `auto` — Full background automation.
|
|
457
|
+
|
|
458
|
+
Capability defaults:
|
|
459
|
+
|
|
460
|
+
- `plan_sync`: `true` — Background plan synchronization using `fs.watch` with debounced writes (300ms) and 2-second polling fallback
|
|
461
|
+
- `phase_preflight`: `false` — Phase preflight checks before agent execution (opt-in)
|
|
462
|
+
- `config_doctor_on_startup`: `false` — Validate configuration on startup
|
|
463
|
+
- `config_doctor_autofix`: `false` — Auto-fix for config doctor (opt-in, security-sensitive)
|
|
464
|
+
- `evidence_auto_summaries`: `true` — Automatic summaries for evidence bundles
|
|
465
|
+
- `decision_drift_detection`: `true` — Detect drift between planned and actual decisions
|
|
466
|
+
|
|
384
467
|
## Plan Cursor (v6.13)
|
|
385
468
|
|
|
386
469
|
The `plan_cursor` config compresses the plan that is injected into the LLM context.
|
|
@@ -429,37 +512,6 @@ When truncation is active, a footer is appended:
|
|
|
429
512
|
[output truncated to {maxLines} lines – use `tool_output.per_tool.<tool>` to adjust]
|
|
430
513
|
```
|
|
431
514
|
|
|
432
|
-
## Mode Detection (v6.13)
|
|
433
|
-
|
|
434
|
-
Swarm now explicitly distinguishes five architect modes:
|
|
435
|
-
|
|
436
|
-
| Mode | When Injected |
|
|
437
|
-
|------|----------------|
|
|
438
|
-
| `DISCOVER` | After the explorer finishes scanning the codebase. |
|
|
439
|
-
| `PLAN` | When the architect writes or updates the plan. |
|
|
440
|
-
| `EXECUTE` | During task implementation (the normal pipeline). |
|
|
441
|
-
| `PHASE-WRAP` | After all tasks in a phase are completed, before docs are updated. |
|
|
442
|
-
| `UNKNOWN` | Fallback when the current state does not match any known mode. |
|
|
443
|
-
|
|
444
|
-
Each mode determines which injection blocks are added to the LLM prompt (e.g., plan cursor is injected in `PLAN`, tool output truncation in `EXECUTE`, etc.).
|
|
445
|
-
|
|
446
|
-
Default mode: `manual`. No background automation — all actions require explicit slash commands.
|
|
447
|
-
|
|
448
|
-
Modes:
|
|
449
|
-
|
|
450
|
-
- `manual` — No background automation. All actions via slash commands (default).
|
|
451
|
-
- `hybrid` — Background automation for safe operations, manual for sensitive ones.
|
|
452
|
-
- `auto` — Full background automation.
|
|
453
|
-
|
|
454
|
-
Capability defaults:
|
|
455
|
-
|
|
456
|
-
- `plan_sync`: `true` — Background plan synchronization using `fs.watch` with debounced writes (300ms) and 2-second polling fallback
|
|
457
|
-
- `phase_preflight`: `false` — Phase preflight checks before agent execution (opt-in)
|
|
458
|
-
- `config_doctor_on_startup`: `false` — Validate configuration on startup
|
|
459
|
-
- `config_doctor_autofix`: `false` — Auto-fix for config doctor (opt-in, security-sensitive)
|
|
460
|
-
- `evidence_auto_summaries`: `true` — Automatic summaries for evidence bundles
|
|
461
|
-
- `decision_drift_detection`: `true` — Detect drift between planned and actual decisions
|
|
462
|
-
|
|
463
515
|
---
|
|
464
516
|
|
|
465
517
|
### Disabling Agents
|
|
@@ -671,6 +723,7 @@ Upcoming: v6.14 focuses on further context optimization and agent coordination i
|
|
|
671
723
|
- [Design Rationale](docs/design-rationale.md)
|
|
672
724
|
- [Installation Guide](docs/installation.md)
|
|
673
725
|
- [Linux + Docker Desktop Install Guide](docs/installation-linux-docker.md)
|
|
726
|
+
- [LLM Operator Installation Guide](docs/installation-llm-operator.md)
|
|
674
727
|
- [Pre-Swarm Planning Guide](docs/planning.md)
|
|
675
728
|
- [Swarm Briefing for LLMs](docs/swarm-briefing.md)
|
|
676
729
|
|
package/dist/cli/index.js
CHANGED
|
@@ -53,11 +53,14 @@ async function install() {
|
|
|
53
53
|
if (!fs.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
54
54
|
const defaultConfig = {
|
|
55
55
|
agents: {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
coder: { model: "opencode/minimax-m2.5-free" },
|
|
57
|
+
reviewer: { model: "opencode/big-pickle" },
|
|
58
|
+
test_engineer: { model: "opencode/gpt-5-nano" },
|
|
59
|
+
explorer: { model: "opencode/trinity-large-preview-free" },
|
|
60
|
+
sme: { model: "opencode/trinity-large-preview-free" },
|
|
61
|
+
critic: { model: "opencode/trinity-large-preview-free" },
|
|
62
|
+
docs: { model: "opencode/trinity-large-preview-free" },
|
|
63
|
+
designer: { model: "opencode/trinity-large-preview-free" }
|
|
61
64
|
},
|
|
62
65
|
max_iterations: 5
|
|
63
66
|
};
|
package/dist/index.js
CHANGED
|
@@ -30200,9 +30200,10 @@ function hasCompoundTestExtension(filename) {
|
|
|
30200
30200
|
function getTestFilesFromConvention(sourceFiles) {
|
|
30201
30201
|
const testFiles = [];
|
|
30202
30202
|
for (const file3 of sourceFiles) {
|
|
30203
|
+
const normalizedPath = file3.replace(/\\/g, "/");
|
|
30203
30204
|
const basename2 = path12.basename(file3);
|
|
30204
30205
|
const dirname4 = path12.dirname(file3);
|
|
30205
|
-
if (hasCompoundTestExtension(basename2) || basename2.includes(".spec.") || basename2.includes(".test.")) {
|
|
30206
|
+
if (hasCompoundTestExtension(basename2) || basename2.includes(".spec.") || basename2.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
|
|
30206
30207
|
if (!testFiles.includes(file3)) {
|
|
30207
30208
|
testFiles.push(file3);
|
|
30208
30209
|
}
|
|
@@ -31582,16 +31583,15 @@ for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
|
|
|
31582
31583
|
}
|
|
31583
31584
|
}
|
|
31584
31585
|
var DEFAULT_MODELS = {
|
|
31585
|
-
|
|
31586
|
-
|
|
31587
|
-
|
|
31588
|
-
test_engineer: "
|
|
31589
|
-
sme: "
|
|
31590
|
-
|
|
31591
|
-
|
|
31592
|
-
|
|
31593
|
-
|
|
31594
|
-
default: "google/gemini-2.5-flash"
|
|
31586
|
+
explorer: "opencode/trinity-large-preview-free",
|
|
31587
|
+
coder: "opencode/minimax-m2.5-free",
|
|
31588
|
+
reviewer: "opencode/big-pickle",
|
|
31589
|
+
test_engineer: "opencode/gpt-5-nano",
|
|
31590
|
+
sme: "opencode/trinity-large-preview-free",
|
|
31591
|
+
critic: "opencode/trinity-large-preview-free",
|
|
31592
|
+
docs: "opencode/trinity-large-preview-free",
|
|
31593
|
+
designer: "opencode/trinity-large-preview-free",
|
|
31594
|
+
default: "opencode/trinity-large-preview-free"
|
|
31595
31595
|
};
|
|
31596
31596
|
var DEFAULT_SCORING_CONFIG = {
|
|
31597
31597
|
enabled: false,
|
|
@@ -36890,6 +36890,26 @@ function isOutsideSwarmDir(filePath) {
|
|
|
36890
36890
|
const relative2 = path15.relative(swarmDir, resolved);
|
|
36891
36891
|
return relative2.startsWith("..") || path15.isAbsolute(relative2);
|
|
36892
36892
|
}
|
|
36893
|
+
function isSourceCodePath(filePath) {
|
|
36894
|
+
if (!filePath)
|
|
36895
|
+
return false;
|
|
36896
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
36897
|
+
const nonSourcePatterns = [
|
|
36898
|
+
/^README(\..+)?$/i,
|
|
36899
|
+
/\/README(\..+)?$/i,
|
|
36900
|
+
/^CHANGELOG(\..+)?$/i,
|
|
36901
|
+
/\/CHANGELOG(\..+)?$/i,
|
|
36902
|
+
/^package\.json$/,
|
|
36903
|
+
/\/package\.json$/,
|
|
36904
|
+
/^\.github\//,
|
|
36905
|
+
/\/\.github\//,
|
|
36906
|
+
/^docs\//,
|
|
36907
|
+
/\/docs\//,
|
|
36908
|
+
/^\.swarm\//,
|
|
36909
|
+
/\/\.swarm\//
|
|
36910
|
+
];
|
|
36911
|
+
return !nonSourcePatterns.some((pattern) => pattern.test(normalized));
|
|
36912
|
+
}
|
|
36893
36913
|
function isGateTool(toolName) {
|
|
36894
36914
|
const normalized = toolName.replace(/^[^:]+[:.]/, "");
|
|
36895
36915
|
const gateTools = [
|
|
@@ -36935,7 +36955,7 @@ function createGuardrailsHooks(config3) {
|
|
|
36935
36955
|
if (isArchitect(input.sessionID) && isWriteTool(input.tool)) {
|
|
36936
36956
|
const args2 = output.args;
|
|
36937
36957
|
const targetPath = args2?.filePath ?? args2?.path ?? args2?.file ?? args2?.target;
|
|
36938
|
-
if (typeof targetPath === "string" && isOutsideSwarmDir(targetPath)) {
|
|
36958
|
+
if (typeof targetPath === "string" && isOutsideSwarmDir(targetPath) && isSourceCodePath(targetPath)) {
|
|
36939
36959
|
const session2 = swarmState.agentSessions.get(input.sessionID);
|
|
36940
36960
|
if (session2) {
|
|
36941
36961
|
session2.architectWriteCount++;
|
|
@@ -38758,7 +38778,10 @@ var ECOSYSTEMS = [
|
|
|
38758
38778
|
buildFiles: ["build.gradle", "build.gradle.kts", "gradle.properties"],
|
|
38759
38779
|
toolchainCommands: ["gradle", "gradlew"],
|
|
38760
38780
|
commands: [
|
|
38761
|
-
{
|
|
38781
|
+
{
|
|
38782
|
+
command: process.platform === "win32" ? "gradlew.bat build" : "./gradlew build",
|
|
38783
|
+
priority: 1
|
|
38784
|
+
},
|
|
38762
38785
|
{ command: "gradle build", priority: 2 }
|
|
38763
38786
|
]
|
|
38764
38787
|
},
|
|
@@ -40824,7 +40847,7 @@ function normalizeAgentsFromDelegations(delegations) {
|
|
|
40824
40847
|
function isValidRetroEntry(entry, phase) {
|
|
40825
40848
|
return entry.type === "retrospective" && "phase_number" in entry && entry.phase_number === phase && "verdict" in entry && entry.verdict === "pass";
|
|
40826
40849
|
}
|
|
40827
|
-
async function executePhaseComplete(args2) {
|
|
40850
|
+
async function executePhaseComplete(args2, workingDirectory) {
|
|
40828
40851
|
const phase = Number(args2.phase);
|
|
40829
40852
|
const summary = args2.summary;
|
|
40830
40853
|
const sessionID = args2.sessionID;
|
|
@@ -40855,8 +40878,8 @@ async function executePhaseComplete(args2) {
|
|
|
40855
40878
|
const trackedAgents = session.phaseAgentsDispatched ?? new Set;
|
|
40856
40879
|
const allAgents = new Set([...delegationAgents, ...trackedAgents]);
|
|
40857
40880
|
const agentsDispatched = Array.from(allAgents).sort();
|
|
40858
|
-
const
|
|
40859
|
-
const { config: config3 } = loadPluginConfigWithMeta(
|
|
40881
|
+
const dir = workingDirectory ?? process.cwd();
|
|
40882
|
+
const { config: config3 } = loadPluginConfigWithMeta(dir);
|
|
40860
40883
|
let phaseCompleteConfig;
|
|
40861
40884
|
try {
|
|
40862
40885
|
phaseCompleteConfig = PhaseCompleteConfigSchema.parse(config3.phase_complete ?? {});
|
|
@@ -40882,16 +40905,16 @@ async function executePhaseComplete(args2) {
|
|
|
40882
40905
|
warnings: []
|
|
40883
40906
|
}, null, 2);
|
|
40884
40907
|
}
|
|
40885
|
-
const retroBundle = await loadEvidence(
|
|
40908
|
+
const retroBundle = await loadEvidence(dir, `retro-${phase}`);
|
|
40886
40909
|
let retroFound = false;
|
|
40887
40910
|
if (retroBundle !== null) {
|
|
40888
40911
|
retroFound = retroBundle.entries?.some((entry) => isValidRetroEntry(entry, phase)) ?? false;
|
|
40889
40912
|
}
|
|
40890
40913
|
if (!retroFound) {
|
|
40891
|
-
const allTaskIds = await listEvidenceTaskIds(
|
|
40914
|
+
const allTaskIds = await listEvidenceTaskIds(dir);
|
|
40892
40915
|
const retroTaskIds = allTaskIds.filter((id) => id.startsWith("retro-"));
|
|
40893
40916
|
for (const taskId of retroTaskIds) {
|
|
40894
|
-
const bundle = await loadEvidence(
|
|
40917
|
+
const bundle = await loadEvidence(dir, taskId);
|
|
40895
40918
|
if (bundle === null)
|
|
40896
40919
|
continue;
|
|
40897
40920
|
retroFound = bundle.entries?.some((entry) => isValidRetroEntry(entry, phase)) ?? false;
|
|
@@ -40945,7 +40968,7 @@ async function executePhaseComplete(args2) {
|
|
|
40945
40968
|
summary: safeSummary ?? null
|
|
40946
40969
|
};
|
|
40947
40970
|
try {
|
|
40948
|
-
const eventsPath = validateSwarmPath(
|
|
40971
|
+
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
40949
40972
|
fs17.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
40950
40973
|
`, "utf-8");
|
|
40951
40974
|
} catch (writeError) {
|
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
* Core implementation - gathers data, enforces policy, writes event, resets state.
|
|
4
4
|
*/
|
|
5
5
|
import { type ToolDefinition } from '@opencode-ai/plugin/tool';
|
|
6
|
+
/**
|
|
7
|
+
* Arguments for the phase_complete tool
|
|
8
|
+
*/
|
|
9
|
+
export interface PhaseCompleteArgs {
|
|
10
|
+
/** The phase number being completed */
|
|
11
|
+
phase: number;
|
|
12
|
+
/** Optional summary of the phase */
|
|
13
|
+
summary?: string;
|
|
14
|
+
/** Session ID to track state (optional, defaults to current session context) */
|
|
15
|
+
sessionID?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Execute the phase_complete tool
|
|
19
|
+
* Gathers data, enforces policy, writes event, resets state
|
|
20
|
+
*/
|
|
21
|
+
export declare function executePhaseComplete(args: PhaseCompleteArgs, workingDirectory?: string): Promise<string>;
|
|
6
22
|
/**
|
|
7
23
|
* Tool definition for phase_complete
|
|
8
24
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.14.0",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -34,9 +34,8 @@
|
|
|
34
34
|
"LICENSE"
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
|
-
"clean": "
|
|
38
|
-
"
|
|
39
|
-
"build": "rm -rf dist && bun run copy-grammars && bun build src/index.ts --outdir dist --target bun --format esm && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm && bun run scripts/copy-grammars.ts --to-dist && tsc --emitDeclarationOnly",
|
|
37
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
38
|
+
"build": "bun run clean && bun run scripts/copy-grammars.ts && bun build src/index.ts --outdir dist --target bun --format esm && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm && bun run scripts/copy-grammars.ts --to-dist && tsc --emitDeclarationOnly",
|
|
40
39
|
"typecheck": "tsc --noEmit",
|
|
41
40
|
"test": "bun test",
|
|
42
41
|
"lint": "biome lint .",
|