opencode-swarm 7.52.2 → 7.52.3

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 CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  ---
18
18
 
19
- OpenCode Swarm is a plugin for [OpenCode](https://opencode.ai) that turns a single AI coding session into an **architect-led team of specialized core, optional, and conditional agents** see `/swarm agents` for the live roster. One agent writes the code. A different agent reviews it. Another writes and runs tests. Another checks security. **Nothing ships until every required gate passes.**
19
+ OpenCode Swarm is a plugin for [OpenCode](https://opencode.ai) that turns a single AI coding session into an **architect-led team of specialized core, optional, and conditional agents**. Run `/swarm agents` for the live roster; it is generated from the current plugin configuration. One agent writes the code. A different agent reviews it. Another writes and runs tests. Another checks security. **Nothing ships until every required gate passes.**
20
20
 
21
21
  ```bash
22
22
  bunx opencode-swarm install
@@ -24,7 +24,7 @@ bunx opencode-swarm install
24
24
 
25
25
  > This single command installs the package, registers it as an OpenCode plugin, disables conflicting default agents, and creates a ready-to-edit config at `~/.config/opencode/opencode-swarm.json`. Requires [Bun](https://bun.sh) (`bun --version` to check). If you must use npm: `npm install -g opencode-swarm && opencode-swarm install`.
26
26
 
27
- > ⚠️ **On first run, Swarm auto-selects the architect and shows a welcome message.** The default OpenCode `Build` and `Plan` modes **bypass this plugin entirely** none of the gates, reviewers, or test agents below run. If you ever need to switch architect manually, open the OpenCode mode/agent picker and choose the Swarm architect; it then coordinates every other agent automatically. If you ever see Swarm "do nothing," this is almost always the cause.
27
+ > **First-run note:** the installer registers the plugin, writes the global plugin config, creates a project override when missing, and disables the native `explore` and `general` agents in `opencode.json`. If you are not using a Swarm architect, the Swarm gates, reviewers, and test agents are bypassed. Open the OpenCode agent or mode picker and choose the Swarm architect when needed.
28
28
 
29
29
  ### Why Swarm?
30
30
 
@@ -44,7 +44,7 @@ Most AI coding tools let one model write code and ask that same model whether th
44
44
  - 🆓 **Free tier** — works with OpenCode Zen's free model roster
45
45
  - ⚙️ **Fully configurable** — override any agent's model, disable agents, tune guardrails
46
46
 
47
- > **The Swarm architect is auto-selected on first run and coordinates all other agents automatically.** You never manually switch between internal roles. If you use the default OpenCode `Build` / `Plan` modes, the plugin is bypassed entirely (see the install warning above).
47
+ > **The Swarm architect coordinates all internal agents automatically.** You never manually switch between internal roles. If the active OpenCode agent is not a Swarm architect, the plugin workflow is bypassed.
48
48
 
49
49
  ---
50
50
 
@@ -157,10 +157,10 @@ The 15-minute guide covers:
157
157
  - Running your first task
158
158
  - Troubleshooting common issues
159
159
 
160
- On first run, Swarm automatically:
161
- - Creates project config at `.opencode/opencode-swarm.json` with all agents enabled
162
- - Selects the Swarm architect as the default
163
- - Shows a welcome message with next steps
160
+ The installer automatically:
161
+ - Creates a project config at `.opencode/opencode-swarm.json` when missing so project-level overrides have a place to live
162
+ - Adds `opencode-swarm` to the OpenCode plugin list
163
+ - Disables the native `explore` and `general` agents to reduce routing conflicts
164
164
 
165
165
  ---
166
166
 
@@ -174,8 +174,7 @@ No animated GIF is shipped in the repo — instead, here is the exact terminal s
174
174
  # 1. Install the plugin (5s)
175
175
  bunx opencode-swarm install
176
176
 
177
- # 2. Open opencode Swarm auto-selects architect on first run
178
- # (the architect is auto-selected; manual selection is only needed to override)
177
+ # 2. Open opencode and select a Swarm architect if it is not already active
179
178
  opencode
180
179
 
181
180
  # 3. Inside the OpenCode session, verify Swarm is live (5s)
@@ -225,12 +224,18 @@ Each row corresponds to a real gate documented further down this README — none
225
224
  **OpenCode caches plugins indefinitely.** A normal OpenCode restart does **not**
226
225
  pull newer versions from npm — once a plugin is cached, OpenCode keeps using
227
226
  that exact copy on every subsequent launch (issue #675). The cache lives in
228
- one of two places depending on your platform:
227
+ several places depending on your platform and OpenCode version:
229
228
 
230
- - Linux / devcontainers / GitHub Codespaces:
229
+ - Current OpenCode cache layout:
230
+ `~/.cache/opencode/node_modules/opencode-swarm/`
231
+ - Legacy Linux / devcontainers / GitHub Codespaces:
231
232
  `~/.config/opencode/node_modules/opencode-swarm/`
232
- - Some macOS / Windows installs:
233
+ - Package cache layout:
233
234
  `~/.cache/opencode/packages/opencode-swarm@latest/`
235
+ - Platform-specific macOS / Windows cache roots:
236
+ `~/Library/Caches/opencode/...`, `%LOCALAPPDATA%\opencode\...`, or `%APPDATA%\opencode\...`
237
+
238
+ The updater also clears known OpenCode lock files (`bun.lock`, `bun.lockb`, and `package-lock.json`) so the next start resolves the latest package.
234
239
 
235
240
  To upgrade to the latest published version (clears both layouts automatically):
236
241
 
@@ -250,7 +255,7 @@ in your `opencode-swarm.json`.
250
255
 
251
256
  ## Commands
252
257
 
253
- All 43 subcommands at a glance:
258
+ Common subcommands at a glance:
254
259
 
255
260
  ```bash
256
261
  /swarm help [command] # List all commands or get detailed help for a specific command
@@ -266,7 +271,7 @@ Use `/swarm help` to see all available commands categorized by function. Use `/s
266
271
 
267
272
  Nine commands display a ⚠️ warning in help output because they share names with Claude Code built-in slash commands (e.g., `/plan`, `/reset`, `/status`). The warning reminds you to always use `/swarm <command>` — the bare CC command does something different and sometimes destructive. See [docs/commands.md#claude-code-command-conflicts](docs/commands.md#claude-code-command-conflicts) for the full conflict registry.
268
273
 
269
- See [docs/commands.md](docs/commands.md) for the full reference (43 commands).
274
+ See [docs/commands.md](docs/commands.md) for the full reference. The live source of truth is `src/commands/registry.ts`, which includes canonical commands, compound commands, and deprecated aliases.
270
275
 
271
276
  ## Command Aliases
272
277
 
@@ -529,13 +534,13 @@ Override via `authority.rules` in config.
529
534
 
530
535
  Built-in tools verify every task before it ships:
531
536
 
532
- - **syntax_check** — Tree-sitter validation (12 languages)
537
+ - **syntax_check** — Tree-sitter validation across the configured language grammar map
533
538
  - **placeholder_scan** — Catches TODOs, stubs, incomplete code
534
539
  - **sast_scan** — 63+ security rules, 9 languages (offline)
535
540
  - **sbom_generate** — Dependency tracking (CycloneDX)
536
541
  - **quality_budget** — Complexity, duplication, test ratio limits
537
542
 
538
- All tools run locally. No Docker, no network calls.
543
+ These quality gates run locally. No Docker is required. Config-gated features such as General Council web search can make external API calls only when you enable them and provide a Tavily or Brave Search key.
539
544
 
540
545
  ### Context Budget Guard
541
546
 
@@ -719,16 +724,16 @@ Swarm provides tools for managing generated skill lifecycles:
719
724
  <details>
720
725
  <summary><strong>Quality Gates (Technical Detail)</strong></summary>
721
726
 
722
- ### Built-in Tools
727
+ ### Built-in Tools and Hooks
723
728
 
724
- | Tool | What It Does |
729
+ | Surface | What It Does |
725
730
  |------|-------------|
726
- | syntax_check | Tree-sitter validation across 12 languages |
731
+ | syntax_check | Tree-sitter validation across the configured language grammar map |
727
732
  | placeholder_scan | Catches TODOs, FIXMEs, stubs, placeholder text |
728
733
  | sast_scan | Offline security analysis, 63+ rules, 9 languages |
729
734
  | sbom_generate | CycloneDX dependency tracking, 8 ecosystems |
730
735
  | build_check | Runs your project's native build/typecheck |
731
- | incremental_verify | Post-coder typecheck for TS/JS, Go, Rust, C# (v6.29.2) |
736
+ | incremental_verify | Post-coder hook for TS/JS, Go, Rust, Python, and C#; configured by `incremental_verify.*`, not invoked as a registered tool |
732
737
  | quality_budget | Enforces complexity, duplication, and test ratio limits |
733
738
  | pre_check_batch | Runs lint, secretscan, SAST, and quality budget in parallel (~15s vs ~60s sequential) |
734
739
  | phase_complete | Enforces phase completion, verifies required agents, requires a valid retrospective evidence bundle, logs events, and resets state; appends to `events.jsonl` with file locking |
@@ -742,7 +747,7 @@ Swarm provides tools for managing generated skill lifecycles:
742
747
  | symbols | Extract exported symbols from source files; supports `workspace` (boolean) and `name` (string) parameters for multi-file symbol search |
743
748
 
744
749
 
745
- All tools run locally. No Docker, no network calls, no external APIs.
750
+ Quality-gate surfaces run locally and require no Docker. Optional search-backed council features use external APIs only when explicitly enabled and configured.
746
751
 
747
752
  Optional enhancement: Semgrep (if on PATH).
748
753
 
@@ -873,19 +878,21 @@ Config file location: `~/.config/opencode/opencode-swarm.json` (global) or `.ope
873
878
  "knowledge": {
874
879
  "enabled": true,
875
880
  "swarm_max_entries": 100,
876
- "hive_max_entries": 1000,
877
- "auto_promote_days": 30,
881
+ "hive_max_entries": 200,
882
+ "auto_promote_days": 90,
878
883
  "max_inject_count": 5,
884
+ "inject_char_budget": 2000,
885
+ "max_lesson_display_chars": 120,
879
886
  "dedup_threshold": 0.6,
880
887
  "scope_filter": ["global"],
881
888
  "hive_enabled": true,
882
- "rejected_max_entries": 200,
889
+ "rejected_max_entries": 20,
883
890
  "validation_enabled": true,
884
- "evergreen_confidence": 0.8,
885
- "evergreen_utility": 0.5,
886
- "low_utility_threshold": 0.2,
891
+ "evergreen_confidence": 0.9,
892
+ "evergreen_utility": 0.8,
893
+ "low_utility_threshold": 0.3,
887
894
  "min_retrievals_for_utility": 3,
888
- "schema_version": "v6.17"
895
+ "schema_version": 1
889
896
  }
890
897
  }
891
898
  ```
@@ -1024,7 +1031,7 @@ Control how tool outputs are summarized for LLM context.
1024
1031
  | `/swarm preflight` | Run phase preflight checks |
1025
1032
  | `/swarm config doctor [--fix]` | Config validation with optional auto-fix |
1026
1033
  | `/swarm doctor tools` | Tool registration coherence and binary readiness check |
1027
- | `/swarm sync-plan` | Force plan.md regeneration from plan.json |
1034
+ | `/swarm sync-plan` | Force `plan.md` regeneration from the canonical plan ledger |
1028
1035
  | `/swarm specify [description]` | Generate or import a feature specification |
1029
1036
  | `/swarm clarify [topic]` | Clarify and refine an existing feature specification |
1030
1037
  | `/swarm analyze` | Analyze spec.md vs plan.md for requirement coverage gaps |
@@ -1040,9 +1047,15 @@ Control how tool outputs are summarized for LLM context.
1040
1047
  | `/swarm knowledge quarantine [id]` | Move a knowledge entry to quarantine |
1041
1048
  | `/swarm knowledge restore [id]` | Restore a quarantined knowledge entry |
1042
1049
  | `/swarm memory status` | Show memory provider and JSONL migration status |
1050
+ | `/swarm memory pending` | Show pending memory proposals and recent rejection reasons |
1051
+ | `/swarm memory recall-log` | Summarize memory recall usage |
1052
+ | `/swarm memory stale` | List expired, superseded, deleted, and low-utility memory records |
1053
+ | `/swarm memory compact` | Dry-run memory cleanup; pass `--confirm` to apply |
1043
1054
  | `/swarm memory export` | Export memory records and proposals to JSONL |
1055
+ | `/swarm memory evaluate` | Run memory recall evaluation fixtures |
1044
1056
  | `/swarm memory import` | Import legacy JSONL memory into SQLite |
1045
1057
  | `/swarm memory migrate` | Run the one-time JSONL to SQLite migration |
1058
+ | `/swarm concurrency <set|status|reset>` | Manage session-scoped runtime concurrency override |
1046
1059
  | `/swarm turbo` | Enable turbo mode for the current session (bypasses QA gates) |
1047
1060
  | `/swarm full-auto` | Toggle Full-Auto Mode for the current session [on|off] |
1048
1061
  | `/swarm checkpoint` | Save a git checkpoint for the current state |
@@ -1053,8 +1066,8 @@ Control how tool outputs are summarized for LLM context.
1053
1066
 
1054
1067
  ## Supported Languages
1055
1068
 
1056
- Full Tier-1 support: TypeScript, JavaScript, Python, Go, Rust
1057
- Tier-2 support: Java, Kotlin, C#, C/C++, Swift
1069
+ Full Tier-1 support: TypeScript, JavaScript, Python, Go, Rust
1070
+ Tier-2 support: Java, Kotlin, C#, C/C++, Swift
1058
1071
  Tier-3 support: Dart, Ruby, PHP/Laravel
1059
1072
 
1060
1073
  All binaries optional. Missing tools produce soft warnings, never hard-fail.
package/dist/cli/index.js CHANGED
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "opencode-swarm",
55
- version: "7.52.2",
55
+ version: "7.52.3",
56
56
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
57
57
  main: "dist/index.js",
58
58
  types: "dist/index.d.ts",
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ var package_default;
69
69
  var init_package = __esm(() => {
70
70
  package_default = {
71
71
  name: "opencode-swarm",
72
- version: "7.52.2",
72
+ version: "7.52.3",
73
73
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
74
74
  main: "dist/index.js",
75
75
  types: "dist/index.d.ts",
@@ -41528,6 +41528,7 @@ __export(exports_state, {
41528
41528
  endAgentSession: () => endAgentSession,
41529
41529
  defaultRunContext: () => defaultRunContext,
41530
41530
  clearCriticalShownIds: () => clearCriticalShownIds,
41531
+ canAdvanceTaskState: () => canAdvanceTaskState,
41531
41532
  buildRehydrationCache: () => buildRehydrationCache,
41532
41533
  beginInvocation: () => beginInvocation,
41533
41534
  applyRehydrationCache: () => applyRehydrationCache,
@@ -41906,14 +41907,6 @@ function advanceTaskState(session, taskId, newState, options, councilConfig) {
41906
41907
  if (!session || !(session.taskWorkflowStates instanceof Map)) {
41907
41908
  throw new Error("INVALID_SESSION: session.taskWorkflowStates must be a Map instance");
41908
41909
  }
41909
- const STATE_ORDER = [
41910
- "idle",
41911
- "coder_delegated",
41912
- "pre_check_passed",
41913
- "reviewer_run",
41914
- "tests_run",
41915
- "complete"
41916
- ];
41917
41910
  const current = session.taskWorkflowStates.get(taskId) ?? "idle";
41918
41911
  const currentIndex = STATE_ORDER.indexOf(current);
41919
41912
  const newIndex = STATE_ORDER.indexOf(newState);
@@ -41930,10 +41923,33 @@ function advanceTaskState(session, taskId, newState, options, councilConfig) {
41930
41923
  }
41931
41924
  }
41932
41925
  session.taskWorkflowStates.set(taskId, newState);
41926
+ if (newState === "complete") {
41927
+ session.stageBCompletion?.delete(taskId);
41928
+ }
41933
41929
  if (options?.emitTelemetry !== false) {
41934
41930
  telemetry.taskStateChanged(options?.telemetrySessionId ?? session.agentName, taskId, newState, current);
41935
41931
  }
41936
41932
  }
41933
+ function canAdvanceTaskState(session, taskId, newState, councilConfig) {
41934
+ if (!isValidTaskId2(taskId))
41935
+ return false;
41936
+ if (!session || !(session.taskWorkflowStates instanceof Map))
41937
+ return false;
41938
+ const current = session.taskWorkflowStates.get(taskId) ?? "idle";
41939
+ const currentIndex = STATE_ORDER.indexOf(current);
41940
+ const newIndex = STATE_ORDER.indexOf(newState);
41941
+ if (newIndex <= currentIndex)
41942
+ return false;
41943
+ if (newState === "complete" && current !== "tests_run") {
41944
+ const councilEntry = session.taskCouncilApproved?.get(taskId);
41945
+ const effectiveMinimum = councilConfig?.requireAllMembers ? 5 : councilConfig?.minimumMembers ?? 3;
41946
+ const councilApproved = councilEntry?.verdict === "APPROVE" && (councilEntry.quorumSize ?? 0) >= effectiveMinimum;
41947
+ const pastPreCheck = currentIndex >= STATE_ORDER.indexOf("pre_check_passed");
41948
+ if (!councilApproved || !pastPreCheck)
41949
+ return false;
41950
+ }
41951
+ return true;
41952
+ }
41937
41953
  async function advanceTaskStateAndPersist(session, taskId, newState, directory, options, councilConfig) {
41938
41954
  advanceTaskState(session, taskId, newState, options, councilConfig);
41939
41955
  if (newState !== "coder_delegated" && newState !== "complete") {
@@ -42104,14 +42120,6 @@ function applyRehydrationCache(session) {
42104
42120
  session.taskCouncilApproved = new Map;
42105
42121
  }
42106
42122
  const { planTaskStates, evidenceMap } = _rehydrationCache;
42107
- const STATE_ORDER = [
42108
- "idle",
42109
- "coder_delegated",
42110
- "pre_check_passed",
42111
- "reviewer_run",
42112
- "tests_run",
42113
- "complete"
42114
- ];
42115
42123
  for (const [taskId, planState] of planTaskStates) {
42116
42124
  const existingState = session.taskWorkflowStates.get(taskId);
42117
42125
  const evidence = evidenceMap.get(taskId);
@@ -42247,7 +42255,7 @@ function addKnowledgeAckDedup(key) {
42247
42255
  set2.delete(oldest);
42248
42256
  }
42249
42257
  }
42250
- var _rehydrationCache = null, _councilDisagreementWarned, _toolAggregates, defaultRunContext, _runContexts, swarmState, MAX_TRACKED_CRITICAL_SHOWN = 500, MAX_TRACKED_KNOWLEDGE_ACKS = 5000, _internals16;
42258
+ var _rehydrationCache = null, _councilDisagreementWarned, STATE_ORDER, _toolAggregates, defaultRunContext, _runContexts, swarmState, MAX_TRACKED_CRITICAL_SHOWN = 500, MAX_TRACKED_KNOWLEDGE_ACKS = 5000, _internals16;
42251
42259
  var init_state = __esm(() => {
42252
42260
  init_constants();
42253
42261
  init_plan_schema();
@@ -42258,6 +42266,14 @@ var init_state = __esm(() => {
42258
42266
  init_telemetry();
42259
42267
  init_logger();
42260
42268
  _councilDisagreementWarned = new Set;
42269
+ STATE_ORDER = [
42270
+ "idle",
42271
+ "coder_delegated",
42272
+ "pre_check_passed",
42273
+ "reviewer_run",
42274
+ "tests_run",
42275
+ "complete"
42276
+ ];
42261
42277
  _toolAggregates = new Map;
42262
42278
  defaultRunContext = new AgentRunContext("default", _toolAggregates);
42263
42279
  _runContexts = new Map;
@@ -128573,6 +128589,12 @@ function recoverTaskStateFromDelegations(taskId, directory) {
128573
128589
  advanceTaskState(session, taskId, "coder_delegated");
128574
128590
  } catch {}
128575
128591
  }
128592
+ if (hasReviewer) {
128593
+ recordStageBCompletion(session, taskId, "reviewer");
128594
+ }
128595
+ if (hasTestEngineer) {
128596
+ recordStageBCompletion(session, taskId, "test_engineer");
128597
+ }
128576
128598
  if (hasReviewer) {
128577
128599
  const stateNow = getTaskState(session, taskId);
128578
128600
  if (stateNow === "coder_delegated" || stateNow === "pre_check_passed") {
package/dist/state.d.ts CHANGED
@@ -425,6 +425,22 @@ export declare function advanceTaskState(session: AgentSessionState, taskId: str
425
425
  minimumMembers?: number;
426
426
  requireAllMembers?: boolean;
427
427
  }): void;
428
+ /**
429
+ * Returns true iff calling `advanceTaskState(session, taskId, newState)` would
430
+ * succeed without throwing. Use this predicate to guard call sites that cannot
431
+ * catch `INVALID_TASK_STATE_TRANSITION` as a control-flow mechanism.
432
+ *
433
+ * Does NOT perform side effects or emit telemetry.
434
+ *
435
+ * @param session - The agent session state
436
+ * @param taskId - The task identifier
437
+ * @param newState - The requested new state
438
+ * @param councilConfig - Optional council quorum config (required when newState='complete')
439
+ */
440
+ export declare function canAdvanceTaskState(session: AgentSessionState, taskId: string, newState: TaskWorkflowState, councilConfig?: {
441
+ minimumMembers?: number;
442
+ requireAllMembers?: boolean;
443
+ }): boolean;
428
444
  /**
429
445
  * Advance the per-task workflow state machine AND persist the corresponding
430
446
  * plan.json status at meaningful workflow boundaries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.52.2",
3
+ "version": "7.52.3",
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",