@hueyexe/opencode-ensemble 0.14.0 → 0.14.2
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 +105 -63
- package/dist/index.js +1606 -1459
- package/package.json +8 -4
- package/src/dashboard.ts +92 -57
- package/src/db.ts +86 -2
- package/src/hooks.ts +72 -5
- package/src/index.ts +21 -9
- package/src/messaging.ts +1 -1
- package/src/notify.ts +1 -1
- package/src/process.ts +55 -0
- package/src/recovery.ts +30 -9
- package/src/schema.ts +1 -1
- package/src/system-prompt.ts +1 -1
- package/src/tools/merge-helper.ts +16 -24
- package/src/tools/shared.ts +7 -10
- package/src/tools/team-cleanup.ts +9 -14
- package/src/types.ts +51 -5
- package/src/watchdog.ts +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@hueyexe/opencode-ensemble)
|
|
8
8
|
[](https://www.npmjs.com/package/@hueyexe/opencode-ensemble)
|
|
9
|
-
[]()
|
|
10
10
|
[]()
|
|
11
11
|
[]()
|
|
12
12
|
[](./LICENSE)
|
|
@@ -19,7 +19,7 @@ Plugin built on the public OpenCode SDK. No internal dependencies.
|
|
|
19
19
|
|
|
20
20
|
```json
|
|
21
21
|
{
|
|
22
|
-
"plugin": ["@hueyexe/opencode-ensemble@0.14.
|
|
22
|
+
"plugin": ["@hueyexe/opencode-ensemble@0.14.2"]
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
@@ -29,79 +29,114 @@ Add to your `opencode.json`, restart OpenCode, and ask it to do something that b
|
|
|
29
29
|
|
|
30
30
|
You ask the agent to do something complex. It creates a team, spawns teammates, and they work in parallel. Each teammate runs in its own OpenCode session with a fresh context window.
|
|
31
31
|
|
|
32
|
-
A
|
|
32
|
+
A realistic development-team interaction:
|
|
33
33
|
|
|
34
34
|
```
|
|
35
|
-
You: "
|
|
35
|
+
You: "Fix checkout idempotency so duplicate Stripe webhooks cannot create
|
|
36
|
+
duplicate orders. Add regression tests and review the final diff for risk."
|
|
36
37
|
|
|
37
38
|
The lead agent:
|
|
38
|
-
1. Creates a team called "
|
|
39
|
-
2. Adds tasks
|
|
40
|
-
3.
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
|
|
39
|
+
1. Creates a team called "checkout-idempotency".
|
|
40
|
+
2. Adds independent tasks first and records the generated task IDs.
|
|
41
|
+
3. Adds dependent QA and review tasks with `depends_on` using real returned IDs.
|
|
42
|
+
4. Spawns a small team with explicit roles:
|
|
43
|
+
- scout: explore agent, worktree disabled, model openai/gpt-5.3-codex-spark
|
|
44
|
+
- api-dev: build agent, own worktree, model anthropic/claude-opus-4-7, plan_approval: true
|
|
45
|
+
- qa: build agent, own worktree, model anthropic/claude-sonnet-4-6
|
|
46
|
+
- reviewer: explore agent, worktree disabled, model openai/gpt-5.3-codex-spark
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
[
|
|
52
|
-
|
|
49
|
+
The lead uses the task board to make sequencing visible. Record the returned task IDs before creating dependent tasks:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
team_tasks_add({
|
|
53
|
+
tasks: [
|
|
54
|
+
{ content: "Map checkout webhook flow and identify idempotency risks", priority: "high" },
|
|
55
|
+
{ content: "Implement duplicate-webhook idempotency guard", priority: "high" },
|
|
56
|
+
],
|
|
57
|
+
})
|
|
58
|
+
// -> Added 2 tasks: task_abc123, task_def456
|
|
59
|
+
|
|
60
|
+
team_tasks_add({
|
|
61
|
+
tasks: [
|
|
62
|
+
{ content: "Add regression tests for duplicate webhook delivery", priority: "high", depends_on: ["task_def456"] },
|
|
63
|
+
],
|
|
64
|
+
})
|
|
65
|
+
// -> Added 1 task: task_ghi789
|
|
66
|
+
|
|
67
|
+
team_tasks_add({
|
|
68
|
+
tasks: [
|
|
69
|
+
{ content: "Review final diff for order, payment, and retry risks", priority: "medium", depends_on: ["task_def456", "task_ghi789"] },
|
|
70
|
+
],
|
|
71
|
+
})
|
|
72
|
+
// -> Added 1 task: task_jkl012
|
|
53
73
|
```
|
|
54
74
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
Then it spawns teammates one at a time:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
team_spawn({
|
|
79
|
+
name: "scout",
|
|
80
|
+
agent: "explore",
|
|
81
|
+
worktree: false,
|
|
82
|
+
model: "openai/gpt-5.3-codex-spark",
|
|
83
|
+
claim_task: "task_abc123",
|
|
84
|
+
prompt: "Trace the checkout webhook flow. Report the files, data model, existing tests, and the smallest safe implementation plan. Do not edit files.",
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
team_spawn({
|
|
88
|
+
name: "api-dev",
|
|
89
|
+
agent: "build",
|
|
90
|
+
model: "anthropic/claude-opus-4-7",
|
|
91
|
+
plan_approval: true,
|
|
92
|
+
claim_task: "task_def456",
|
|
93
|
+
prompt: "After scout reports, implement the idempotency guard. Keep the change narrow. Commit your work and send a task-result message.",
|
|
94
|
+
})
|
|
62
95
|
```
|
|
63
96
|
|
|
64
|
-
|
|
97
|
+
The same pattern assigns `qa` to regression tests and `reviewer` to final review. The reviewer stays read-only (`worktree: false`) so it can inspect merged changes without producing another branch.
|
|
65
98
|
|
|
66
|
-
|
|
99
|
+
Teammates coordinate without the lead polling:
|
|
67
100
|
|
|
68
101
|
```
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
alice [idle 2m, last msg: 1m ago] agent: build branch: ensemble-validation-alice
|
|
75
|
-
bob [idle 1m, last msg: 30s ago] agent: build branch: ensemble-validation-bob
|
|
76
|
-
carol [working 5m, last msg: 3m ago] agent: build branch: ensemble-validation-carol
|
|
77
|
-
task: Write integration tests for validated endpoints
|
|
78
|
-
Tasks: 5 total (3 completed, 1 in_progress, 1 pending)
|
|
102
|
+
scout -> lead: "Checkout flow is src/webhooks/stripe.ts -> createOrderFromPayment(). Existing tests are in test/checkout-webhook.test.ts. Risk: retries race before order insert commits."
|
|
103
|
+
api-dev -> lead: "Plan ready: add unique event_id insert before order creation, treat duplicate insert as success, add a transaction around order creation."
|
|
104
|
+
lead -> api-dev: approves plan
|
|
105
|
+
qa -> api-dev: "Which duplicate signal should tests assert: event_id conflict or existing order lookup?"
|
|
106
|
+
api-dev -> qa: "Assert duplicate event_id returns success and creates one order. See src/webhooks/stripe.ts."
|
|
79
107
|
```
|
|
80
108
|
|
|
81
|
-
|
|
109
|
+
When work is done, the lead reviews and integrates deliberately:
|
|
82
110
|
|
|
83
111
|
```
|
|
84
|
-
|
|
112
|
+
team_results({ from: "api-dev" })
|
|
113
|
+
team_shutdown({ member: "api-dev" })
|
|
114
|
+
team_merge({ member: "api-dev" })
|
|
85
115
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
116
|
+
team_results({ from: "qa" })
|
|
117
|
+
team_shutdown({ member: "qa" })
|
|
118
|
+
team_merge({ member: "qa" })
|
|
119
|
+
|
|
120
|
+
team_spawn({ name: "reviewer", agent: "explore", worktree: false, claim_task: "task_jkl012", prompt: "Review the merged diff for correctness, missed tests, and risky behavior. Do not edit files." })
|
|
89
121
|
```
|
|
90
122
|
|
|
91
|
-
|
|
123
|
+
The lead runs the repository verification commands, summarizes the result, and only then cleans up the team. All merged teammate changes remain in your working directory as unstaged changes for review with `git diff`.
|
|
92
124
|
|
|
125
|
+
## Agent Skill
|
|
126
|
+
|
|
127
|
+
Install the companion skill to teach your AI how to form useful Ensemble teams, write better teammate prompts, choose models, and avoid common coordination failures:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx skills@latest add hueyexe/opencode-ensemble --skill opencode-ensemble
|
|
93
131
|
```
|
|
94
|
-
[toast] alice shut down
|
|
95
|
-
[toast] bob shut down
|
|
96
|
-
[toast] carol shut down
|
|
97
|
-
|
|
98
|
-
Lead: "All validation and tests are complete. 5 endpoints validated,
|
|
99
|
-
12 test cases added. Team cleaned up.
|
|
100
|
-
Merged 3 branch(es) into working directory (unstaged).
|
|
101
|
-
Review changes with: git diff"
|
|
102
|
-
```
|
|
103
132
|
|
|
104
|
-
|
|
133
|
+
The skill is useful when you want the agent to decide whether parallel work is appropriate, split work into independent slices, use `depends_on` correctly, or pick a safe mix of `explore` and `build` teammates.
|
|
134
|
+
|
|
135
|
+
Good team shapes:
|
|
136
|
+
|
|
137
|
+
- **Scout, builder, reviewer**: one read-only `explore` agent maps the code, one `build` agent changes it, one read-only `explore` agent reviews the diff.
|
|
138
|
+
- **Parallel slices**: two or three `build` agents own independent files or vertical slices, then one reviewer checks the combined result.
|
|
139
|
+
- **Risky change**: use `plan_approval: true` on the implementing teammate, then approve or reject the plan through `team_message` before edits begin.
|
|
105
140
|
|
|
106
141
|
## Dashboard
|
|
107
142
|
|
|
@@ -132,6 +167,13 @@ Set to `0` to disable. The dashboard starts automatically when OpenCode loads th
|
|
|
132
167
|
|
|
133
168
|
Two steps: add the plugin, then allowlist worktree paths.
|
|
134
169
|
|
|
170
|
+
### Runtime requirements
|
|
171
|
+
|
|
172
|
+
The plugin uses SQLite via the host's runtime adapter:
|
|
173
|
+
|
|
174
|
+
- **Bun**: any version with `bun:sqlite` (Bun ≥ 1.0).
|
|
175
|
+
- **Node / Electron** (e.g. opencode Desktop): **Node ≥ 24** for stable `node:sqlite`. Older Node (20.x) lacks the module entirely; Node 22.5–23 has it behind `--experimental-sqlite`. If you load the plugin under an older Node and see `Cannot find module 'node:sqlite'` at startup, your runtime is too old.
|
|
176
|
+
|
|
135
177
|
### 1. Add the plugin
|
|
136
178
|
|
|
137
179
|
Add to your OpenCode config with a pinned version. Project-level or global.
|
|
@@ -140,7 +182,7 @@ Add to your OpenCode config with a pinned version. Project-level or global.
|
|
|
140
182
|
|
|
141
183
|
```json
|
|
142
184
|
{
|
|
143
|
-
"plugin": ["@hueyexe/opencode-ensemble@0.14.
|
|
185
|
+
"plugin": ["@hueyexe/opencode-ensemble@0.14.2"]
|
|
144
186
|
}
|
|
145
187
|
```
|
|
146
188
|
|
|
@@ -148,7 +190,7 @@ Add to your OpenCode config with a pinned version. Project-level or global.
|
|
|
148
190
|
|
|
149
191
|
```json
|
|
150
192
|
{
|
|
151
|
-
"plugin": ["@hueyexe/opencode-ensemble@0.14.
|
|
193
|
+
"plugin": ["@hueyexe/opencode-ensemble@0.14.2"]
|
|
152
194
|
}
|
|
153
195
|
```
|
|
154
196
|
|
|
@@ -245,7 +287,7 @@ Teammate messages arrive in the lead's session as `[Team message from alice]: ..
|
|
|
245
287
|
|
|
246
288
|
## Architecture
|
|
247
289
|
|
|
248
|
-
- **SQLite** (
|
|
290
|
+
- **SQLite** (WAL mode) for teams, members, tasks, and messages. Uses `bun:sqlite` in Bun and `node:sqlite` in Node/Electron through the internal database adapter.
|
|
249
291
|
- **promptAsync** for message delivery: injects a message and starts the prompt loop in one call
|
|
250
292
|
- **Git worktree isolation**: each teammate gets their own worktree by default, so multiple agents can edit files without conflicts. Opt out with `worktree: false` for read-only agents.
|
|
251
293
|
- **System prompt injection**: the lead's system prompt includes team state (member statuses, task counts) on every LLM call. Teammates get a short role reminder.
|
|
@@ -278,8 +320,8 @@ Control which AI models your agents use. By default, agents use whatever model O
|
|
|
278
320
|
```json
|
|
279
321
|
{
|
|
280
322
|
"modelsByAgent": {
|
|
281
|
-
"build": "anthropic/claude-opus-4-
|
|
282
|
-
"explore": "
|
|
323
|
+
"build": "anthropic/claude-opus-4-7",
|
|
324
|
+
"explore": "openai/gpt-5.3-codex-spark"
|
|
283
325
|
}
|
|
284
326
|
}
|
|
285
327
|
```
|
|
@@ -287,7 +329,7 @@ Control which AI models your agents use. By default, agents use whatever model O
|
|
|
287
329
|
**Rotate through a pool for diverse perspectives:**
|
|
288
330
|
```json
|
|
289
331
|
{
|
|
290
|
-
"modelPool": ["anthropic/claude-opus-4-
|
|
332
|
+
"modelPool": ["anthropic/claude-opus-4-7", "anthropic/claude-sonnet-4-6", "openai/gpt-5.4"],
|
|
291
333
|
"modelAssignment": "rotate"
|
|
292
334
|
}
|
|
293
335
|
```
|
|
@@ -296,7 +338,7 @@ Control which AI models your agents use. By default, agents use whatever model O
|
|
|
296
338
|
```json
|
|
297
339
|
{
|
|
298
340
|
"promptForModels": true,
|
|
299
|
-
"modelPool": ["anthropic/claude-opus-4-
|
|
341
|
+
"modelPool": ["anthropic/claude-opus-4-7", "opencode/big-pickle", "openai/gpt-5.3-codex-spark"]
|
|
300
342
|
}
|
|
301
343
|
```
|
|
302
344
|
|
|
@@ -311,7 +353,7 @@ When `promptForModels` is true, the lead uses the question tool to ask which mod
|
|
|
311
353
|
|
|
312
354
|
The lead can always override by passing `model` directly on `team_spawn`, regardless of config.
|
|
313
355
|
|
|
314
|
-
Model IDs use the `provider/model` format from [models.dev](https://models.dev) (e.g. `anthropic/claude-opus-4-
|
|
356
|
+
Model IDs use the `provider/model` format from [models.dev](https://models.dev) (e.g. `anthropic/claude-opus-4-7`, `openai/gpt-5.4`). For OpenCode Zen models, use the `opencode/` prefix (e.g. `opencode/big-pickle`).
|
|
315
357
|
|
|
316
358
|
## Configuration
|
|
317
359
|
|
|
@@ -331,7 +373,7 @@ Configure via JSON files, environment variables, or both. Project config overrid
|
|
|
331
373
|
"rateLimitCapacity": 10,
|
|
332
374
|
"dashboardPort": 4747,
|
|
333
375
|
"defaultModel": "anthropic/claude-sonnet-4-6",
|
|
334
|
-
"modelPool": ["anthropic/claude-opus-4-
|
|
376
|
+
"modelPool": ["anthropic/claude-opus-4-7", "anthropic/claude-sonnet-4-6", "openai/gpt-5.4"],
|
|
335
377
|
"modelsByAgent": {},
|
|
336
378
|
"modelAssignment": "default",
|
|
337
379
|
"promptForModels": false
|
|
@@ -353,7 +395,7 @@ All fields are optional. Missing fields use defaults.
|
|
|
353
395
|
| `dashboardPort` | `4747` | Dashboard server port. `0` disables. |
|
|
354
396
|
| `defaultModel` | `""` | Default model for all agents (e.g. `"anthropic/claude-sonnet-4-6"`). Empty = OpenCode's default. |
|
|
355
397
|
| `modelPool` | `[]` | List of models for rotation/random assignment. |
|
|
356
|
-
| `modelsByAgent` | `{}` | Map agent type to model (e.g. `{"build": "anthropic/claude-opus-4-
|
|
398
|
+
| `modelsByAgent` | `{}` | Map agent type to model (e.g. `{"build": "anthropic/claude-opus-4-7"}`). |
|
|
357
399
|
| `modelAssignment` | `"default"` | How to assign models: `"default"`, `"rotate"`, or `"random"`. |
|
|
358
400
|
| `promptForModels` | `false` | Lead asks user about model preferences before spawning. |
|
|
359
401
|
|
|
@@ -412,7 +454,7 @@ Same coordination model (shared tasks, peer messaging, lead coordination) with s
|
|
|
412
454
|
```bash
|
|
413
455
|
bun install
|
|
414
456
|
bun run typecheck
|
|
415
|
-
bun test #
|
|
457
|
+
bun test # 568 tests
|
|
416
458
|
bun run build
|
|
417
459
|
```
|
|
418
460
|
|