@te-river/opencode-team-mode 1.5.4 → 1.5.6

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 (158) hide show
  1. package/README.md +732 -634
  2. package/README.zh-CN.md +655 -576
  3. package/dist/agents.d.ts +6 -1
  4. package/dist/agents.d.ts.map +1 -1
  5. package/dist/agents.js +103 -522
  6. package/dist/agents.js.map +1 -1
  7. package/dist/approval-gate.d.ts +16 -0
  8. package/dist/approval-gate.d.ts.map +1 -1
  9. package/dist/approval-gate.js +8 -1
  10. package/dist/approval-gate.js.map +1 -1
  11. package/dist/blackboard.d.ts.map +1 -1
  12. package/dist/blackboard.js +3 -2
  13. package/dist/blackboard.js.map +1 -1
  14. package/dist/commands.d.ts.map +1 -1
  15. package/dist/commands.js +7 -6
  16. package/dist/commands.js.map +1 -1
  17. package/dist/envprotect/bash-classify.d.ts +42 -0
  18. package/dist/envprotect/bash-classify.d.ts.map +1 -0
  19. package/dist/envprotect/bash-classify.js +221 -0
  20. package/dist/envprotect/bash-classify.js.map +1 -0
  21. package/dist/envprotect/gate-predicates.d.ts +57 -0
  22. package/dist/envprotect/gate-predicates.d.ts.map +1 -0
  23. package/dist/envprotect/gate-predicates.js +174 -0
  24. package/dist/envprotect/gate-predicates.js.map +1 -0
  25. package/dist/envprotect/hook.d.ts +45 -0
  26. package/dist/envprotect/hook.d.ts.map +1 -0
  27. package/dist/envprotect/hook.js +158 -0
  28. package/dist/envprotect/hook.js.map +1 -0
  29. package/dist/envprotect/path-classify.d.ts +16 -0
  30. package/dist/envprotect/path-classify.d.ts.map +1 -0
  31. package/dist/envprotect/path-classify.js +72 -0
  32. package/dist/envprotect/path-classify.js.map +1 -0
  33. package/dist/envprotect/patterns.d.ts +77 -0
  34. package/dist/envprotect/patterns.d.ts.map +1 -0
  35. package/dist/envprotect/patterns.js +182 -0
  36. package/dist/envprotect/patterns.js.map +1 -0
  37. package/dist/envprotect.d.ts +19 -217
  38. package/dist/envprotect.d.ts.map +1 -1
  39. package/dist/envprotect.js +18 -803
  40. package/dist/envprotect.js.map +1 -1
  41. package/dist/fs-safe.d.ts +16 -0
  42. package/dist/fs-safe.d.ts.map +1 -0
  43. package/dist/fs-safe.js +56 -0
  44. package/dist/fs-safe.js.map +1 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +22 -6
  47. package/dist/index.js.map +1 -1
  48. package/dist/prompts/lead.d.ts +7 -0
  49. package/dist/prompts/lead.d.ts.map +1 -0
  50. package/dist/prompts/lead.js +230 -0
  51. package/dist/prompts/lead.js.map +1 -0
  52. package/dist/prompts/shared.d.ts +8 -0
  53. package/dist/prompts/shared.d.ts.map +1 -0
  54. package/dist/prompts/shared.js +118 -0
  55. package/dist/prompts/shared.js.map +1 -0
  56. package/dist/prompts/specialists.d.ts +12 -0
  57. package/dist/prompts/specialists.d.ts.map +1 -0
  58. package/dist/prompts/specialists.js +218 -0
  59. package/dist/prompts/specialists.js.map +1 -0
  60. package/dist/shell-text.d.ts +14 -0
  61. package/dist/shell-text.d.ts.map +1 -0
  62. package/dist/shell-text.js +16 -0
  63. package/dist/shell-text.js.map +1 -0
  64. package/dist/tm/args-schema.d.ts +36 -0
  65. package/dist/tm/args-schema.d.ts.map +1 -0
  66. package/dist/tm/args-schema.js +191 -0
  67. package/dist/tm/args-schema.js.map +1 -0
  68. package/dist/tm/browser.d.ts +52 -0
  69. package/dist/tm/browser.d.ts.map +1 -0
  70. package/dist/tm/browser.js +361 -0
  71. package/dist/tm/browser.js.map +1 -0
  72. package/dist/tm/client-unwrap.d.ts +38 -0
  73. package/dist/tm/client-unwrap.d.ts.map +1 -0
  74. package/dist/tm/client-unwrap.js +113 -0
  75. package/dist/tm/client-unwrap.js.map +1 -0
  76. package/dist/tm/config.d.ts +46 -18
  77. package/dist/tm/config.d.ts.map +1 -1
  78. package/dist/tm/config.js +60 -17
  79. package/dist/tm/config.js.map +1 -1
  80. package/dist/tm/guard.d.ts.map +1 -1
  81. package/dist/tm/guard.js +4 -7
  82. package/dist/tm/guard.js.map +1 -1
  83. package/dist/tm/index.d.ts +15 -5
  84. package/dist/tm/index.d.ts.map +1 -1
  85. package/dist/tm/index.js +95 -19
  86. package/dist/tm/index.js.map +1 -1
  87. package/dist/tm/memory.d.ts +82 -0
  88. package/dist/tm/memory.d.ts.map +1 -0
  89. package/dist/tm/memory.js +350 -0
  90. package/dist/tm/memory.js.map +1 -0
  91. package/dist/tm/pipelines.d.ts +58 -0
  92. package/dist/tm/pipelines.d.ts.map +1 -0
  93. package/dist/tm/pipelines.js +301 -0
  94. package/dist/tm/pipelines.js.map +1 -0
  95. package/dist/tm/preview.d.ts +6 -1
  96. package/dist/tm/preview.d.ts.map +1 -1
  97. package/dist/tm/preview.js +31 -8
  98. package/dist/tm/preview.js.map +1 -1
  99. package/dist/tm/ptc/budgets.d.ts +38 -0
  100. package/dist/tm/ptc/budgets.d.ts.map +1 -0
  101. package/dist/tm/ptc/budgets.js +59 -0
  102. package/dist/tm/ptc/budgets.js.map +1 -0
  103. package/dist/tm/ptc/contract.d.ts +131 -0
  104. package/dist/tm/ptc/contract.d.ts.map +1 -0
  105. package/dist/tm/ptc/contract.js +47 -0
  106. package/dist/tm/ptc/contract.js.map +1 -0
  107. package/dist/tm/ptc/driver.d.ts +37 -0
  108. package/dist/tm/ptc/driver.d.ts.map +1 -0
  109. package/dist/tm/ptc/driver.js +181 -0
  110. package/dist/tm/ptc/driver.js.map +1 -0
  111. package/dist/tm/ptc/engines.d.ts +32 -0
  112. package/dist/tm/ptc/engines.d.ts.map +1 -0
  113. package/dist/tm/ptc/engines.js +201 -0
  114. package/dist/tm/ptc/engines.js.map +1 -0
  115. package/dist/tm/ptc/gate.d.ts +28 -0
  116. package/dist/tm/ptc/gate.d.ts.map +1 -0
  117. package/dist/tm/ptc/gate.js +127 -0
  118. package/dist/tm/ptc/gate.js.map +1 -0
  119. package/dist/tm/ptc/index.d.ts +19 -0
  120. package/dist/tm/ptc/index.d.ts.map +1 -0
  121. package/dist/tm/ptc/index.js +15 -0
  122. package/dist/tm/ptc/index.js.map +1 -0
  123. package/dist/tm/ptc/pscan.d.ts +11 -0
  124. package/dist/tm/ptc/pscan.d.ts.map +1 -0
  125. package/dist/tm/ptc/pscan.js +27 -0
  126. package/dist/tm/ptc/pscan.js.map +1 -0
  127. package/dist/tm/ptc/summary.d.ts +17 -0
  128. package/dist/tm/ptc/summary.d.ts.map +1 -0
  129. package/dist/tm/ptc/summary.js +107 -0
  130. package/dist/tm/ptc/summary.js.map +1 -0
  131. package/dist/tm/ptc/tool.d.ts +35 -0
  132. package/dist/tm/ptc/tool.d.ts.map +1 -0
  133. package/dist/tm/ptc/tool.js +135 -0
  134. package/dist/tm/ptc/tool.js.map +1 -0
  135. package/dist/tm/ptc.d.ts +45 -26
  136. package/dist/tm/ptc.d.ts.map +1 -1
  137. package/dist/tm/ptc.js +71 -45
  138. package/dist/tm/ptc.js.map +1 -1
  139. package/dist/tm/result.d.ts +34 -0
  140. package/dist/tm/result.d.ts.map +1 -0
  141. package/dist/tm/result.js +87 -0
  142. package/dist/tm/result.js.map +1 -0
  143. package/dist/tm/shell-bridge.d.ts +22 -0
  144. package/dist/tm/shell-bridge.d.ts.map +1 -0
  145. package/dist/tm/shell-bridge.js +70 -0
  146. package/dist/tm/shell-bridge.js.map +1 -0
  147. package/dist/tm/store.d.ts.map +1 -1
  148. package/dist/tm/store.js +2 -1
  149. package/dist/tm/store.js.map +1 -1
  150. package/dist/tm/tools.d.ts +13 -71
  151. package/dist/tm/tools.d.ts.map +1 -1
  152. package/dist/tm/tools.js +23 -656
  153. package/dist/tm/tools.js.map +1 -1
  154. package/dist/tm/webfetch.d.ts +94 -0
  155. package/dist/tm/webfetch.d.ts.map +1 -0
  156. package/dist/tm/webfetch.js +225 -0
  157. package/dist/tm/webfetch.js.map +1 -0
  158. package/package.json +2 -2
package/README.md CHANGED
@@ -1,634 +1,732 @@
1
- # OpenCode TeamMode
2
-
3
- **[English](./README.md)** | **[中文](./README.zh-CN.md)**
4
-
5
- [![npm version](https://img.shields.io/npm/v/@te-river/opencode-team-mode.svg)](https://www.npmjs.com/package/@te-river/opencode-team-mode)
6
- [![npm downloads](https://img.shields.io/npm/dm/@te-river/opencode-team-mode.svg)](https://www.npmjs.com/package/@te-river/opencode-team-mode)
7
- [![license](https://img.shields.io/npm/l/@te-river/opencode-team-mode.svg)](./LICENSE)
8
-
9
- > 🤝 **Multi-agent team collaboration plugin for [OpenCode Desktop](https://opencode.ai)**
10
- >
11
- > Adds a complete team of specialized AI agents — Architect, Implementer, Reviewer, Tester, Researcher — orchestrated by a Team Lead, all accessible via simple slash commands.
12
-
13
- ---
14
-
15
- ## ✨ What is TeamMode?
16
-
17
- TeamMode transforms OpenCode Desktop from a single-agent coding assistant into a **full development team**. Each agent has a distinct role, expertise, and personality — just like a real engineering team.
18
-
19
- Instead of one agent trying to do everything, you get:
20
-
21
- | Agent | Role | When to use |
22
- |---|---|---|
23
- | 🎯 **Team Lead** | Orchestrator | Complex tasks that need planning + multi-step execution |
24
- | 🏗️ **Architect** | System designer | Design docs, module structure, API contracts |
25
- | 💻 **Implementer** | Code writer | Building features, writing production code |
26
- | 🔍 **Reviewer** | Dimension-focused auditor | Single-dimension review (completeness / correctness / impact) — the lead runs 3 in parallel |
27
- | 🧪 **Tester** | Test engineer | Unit tests, integration tests, edge-case coverage, static verification (build / typecheck / lint / API tests) |
28
- | 🔎 **Researcher** | Knowledge finder | Library evaluation, API docs, best practices |
29
-
30
- ---
31
-
32
- ## 🚀 Quick Start
33
-
34
- ### Prerequisites
35
-
36
- 1. **Install OpenCode Desktop** (if you haven't already):
37
-
38
- | Platform | Install command |
39
- |---|---|
40
- | macOS (Apple Silicon) | `brew install --cask opencode-desktop` |
41
- | macOS (Intel) | `brew install --cask opencode-desktop` |
42
- | Windows | `scoop bucket add extras && scoop install extras/opencode-desktop` |
43
- | Linux | Download from [opencode.ai/download](https://opencode.ai/download) |
44
-
45
- Or install the **CLI/TUI** version:
46
- ```bash
47
- # one-line script (all platforms)
48
- curl -fsSL https://opencode.ai/install | bash
49
-
50
- # or via npm
51
- npm install -g opencode-ai
52
- ```
53
-
54
- 2. **Node.js ≥ 18** (for npm)
55
-
56
- ### Install TeamMode
57
-
58
- **Option A — One-line installer:**
59
-
60
- macOS / Linux (bash):
61
- ```bash
62
- curl -fsSL https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.sh | bash
63
- ```
64
-
65
- Windows (PowerShell):
66
- ```powershell
67
- irm https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1 | iex
68
- ```
69
-
70
- **Option B — Manual config:**
71
-
72
- Add the plugin to your `opencode.jsonc`:
73
-
74
- ```jsonc
75
- {
76
- "$schema": "https://opencode.ai/config.json",
77
- "plugin": [
78
- "@te-river/opencode-team-mode@latest"
79
- ]
80
- }
81
- ```
82
-
83
- OpenCode will automatically install the plugin on startup.
84
-
85
- > **Tip:** After modifying `opencode.json`, **restart OpenCode Desktop** for changes to take effect.
86
-
87
- ---
88
-
89
- ## ⚙️ Configuration
90
-
91
- The plugin automatically injects all team agents and commands when OpenCode starts. **No need to manually copy agent files or command definitions.**
92
-
93
- > ⚠️ **Model choice matters.** Every judgment in the workflow — triage,
94
- > decomposition, dispatch briefs, synthesis, review-loop verdicts — flows
95
- > through the **Team Lead**. A weak model in that seat degrades the whole
96
- > pipeline no matter how strong the specialists are. Pin your best
97
- > reasoning model to the `team` agent (recipe in
98
- > [Customization](#customization) below).
99
-
100
- ### Global install (all projects)
101
-
102
- To enable TeamMode in every project, add the plugin to your global config:
103
-
104
- ```jsonc
105
- // ~/.config/opencode/opencode.jsonc
106
- {
107
- "$schema": "https://opencode.ai/config.json",
108
- "plugin": [
109
- "@te-river/opencode-team-mode@latest"
110
- ]
111
- }
112
- ```
113
-
114
- ---
115
-
116
- ## 📖 Usage
117
-
118
- ### Slash Commands
119
-
120
- TeamMode adds six slash commands to OpenCode. Type them in the chat input:
121
-
122
- | Command | Agent | Description |
123
- |---|---|---|
124
- | `/team-plan <task>` | Architect | Create a detailed implementation plan with architecture, file manifest, and task breakdown |
125
- | `/team-implement <task>` | Implementer | Write production code for a feature or task |
126
- | `/team-review [scope]` | Reviewer | Audit code for bugs, security issues, and quality problems |
127
- | `/team-test [scope]` | Tester | Generate comprehensive tests with edge-case coverage |
128
- | `/team-research <topic>` | Researcher | Investigate libraries, APIs, or best practices |
129
- | `/team-run <task>` | Team Lead | **Full workflow** — orchestrates all agents end-to-end |
130
-
131
- #### Example workflow
132
-
133
- ```
134
- # 1. Plan the feature
135
- /team-plan Add user authentication with OAuth2 and JWT tokens
136
-
137
- # 2. Review the plan, then implement
138
- /team-implement Implement the auth module as planned
139
-
140
- # 3. Review the code
141
- /team-review src/auth/
142
-
143
- # 4. Write tests
144
- /team-test src/auth/
145
-
146
- # Or let the team lead handle everything:
147
- /team-run Add user authentication with OAuth2 and JWT tokens
148
- ```
149
-
150
- ### Agent Picker
151
-
152
- You can also invoke agents directly using the `@` mention in OpenCode Desktop:
153
-
154
- - `@team` — Orchestrate a complex task
155
- - `@architect` — Design a system or module
156
- - `@implementer` — Write code
157
- - `@reviewer` — Review code quality
158
- - `@tester` — Write tests
159
- - `@researcher` — Research a topic
160
-
161
- ### Demo
162
-
163
- A session transcript, recreated from how the flow actually looks. Team is the
164
- default agent out of the box (see Configuration to opt out), so the user just
165
- types into a fresh chat:
166
-
167
- > **User:** Add token-bucket rate limiting to our Express API — 100 requests
168
- > per minute per user, return 429 when exceeded. Don't touch anything under
169
- > `src/legacy/`.
170
-
171
- ```text
172
- team Route: product behavior change → implementer → tester → reviewer
173
- (3 dispatches → approval gate applies)
174
-
175
- Research: read README, src/app.ts, src/middleware/*
176
- Blocking questions: none — 1 assumption listed below
177
-
178
- PLAN
179
- Goal: token-bucket limiter, 100 req/min/user, 429 + Retry-After
180
- Scope: src/middleware/rateLimit.ts (new), src/app.ts (+3 lines)
181
- Pipeline: implementer → tester → reviewer (correctness)
182
- Assumption: in-memory bucket, not Redis — say the word to change
183
- Boundary: src/legacy/** untouched
184
- Approve to proceed?
185
-
186
- user approved, go
187
-
188
- team ▸ @implementer — STATUS: done
189
- CHANGES: src/middleware/rateLimit.ts (new) · src/app.ts (+3)
190
- HANDOFF: bucket {tokens, lastRefill}; refill() is a single atomic pass
191
- EVIDENCE: tsc clean (output above)
192
-
193
- ▸ @tester — STATUS: done · VERDICT: pass (14/14)
194
- FINDINGS: burst edge, window expiry, concurrent refill covered;
195
- src/legacy/** byte-identical
196
- EVIDENCE: vitest 14 passed
197
-
198
- ▸ @reviewer — STATUS: done · VERDICT: approve (correctness)
199
- FINDINGS: no Critical/Major; 1 Minor (log line noise) noted
200
-
201
- team Done.
202
- rate limiter shipped: rateLimit.ts (new) · app.ts (+3) · 14 tests green
203
- review: approve · assumption: in-memory only · src/legacy/ untouched
204
- ```
205
-
206
- The only message the user typed was the task and "approved, go". The
207
- pipeline was a routing-table lookup, execution waited for plan approval,
208
- and every handoff traveled as a structured skeleton — no file ceremony.
209
-
210
- ### Desktop-specific features
211
-
212
- In **OpenCode Desktop**, you get additional UX benefits:
213
-
214
- - 🎨 **Color-coded agents** — Each agent has a distinct color in the chat UI for easy identification.
215
- - 📋 **Agent picker** — Click the agent dropdown to switch between team agents visually.
216
- - 🔀 **Parallel sub-tasks** — The Team Lead can dispatch multiple sub-agents simultaneously, with results shown in parallel panels.
217
- - 📊 **Session history** — All team interactions are saved and searchable in the Desktop session sidebar.
218
-
219
- ---
220
-
221
- ## 🧯 Context governance (tm_* + R6 + R2) — new in v1.5.1
222
-
223
- > ⚠️ Requires `@te-river/opencode-team-mode@1.5.1` or later (released
224
- > 2026-09-08). If your config pins `@latest`, OpenCode upgrades on next start.
225
-
226
- **JIT layer-2 tools (`tm_read` / `tm_grep` / `tm_bash` / `tm_fetch`).**
227
- Large tool outputs are context cost's main driver: every step re-sends the
228
- whole window. The tm_* tools run the built-in capability under governance
229
- first: results above `TM_OFFLOAD_THRESHOLD` tokens never enter the window —
230
- they are written to a local run store and replaced by a handle with a
231
- content-aware preview (JSON keys / CSV header+shape / log ERROR×N stats /
232
- code signatures / binary metadata, hard-capped at 80 tokens). When the agent
233
- actually needs the payload it pages through it with `tm_fetch`, using an
234
- HMAC-signed, run-scoped, expiring handle. `tm_bash` only allows read-only
235
- commands (allowlist), and failures come back as structured errors instead of
236
- raw dumps.
237
-
238
- **R6 environment protection (now an approval gate).** With TeamMode active,
239
- the model cannot read environment variables silently. Env-var reads
240
- (`printenv`, `env`, `Get-ChildItem env:`, …) and env files (`.env`, shell rc
241
- files) route through OpenCode's **official confirmation dialog**: you get a
242
- native prompt to approve or deny, and an unanswered prompt is **auto-rejected
243
- after `TM_ASK_TIMEOUT_MIN` (default 10 min)** — the plugin only ever rejects
244
- on timeout, never approves on the model's behalf. Env reads that no wildcard
245
- can express (embedded `$VAR` / `${VAR}` / `$env:` inside another command,
246
- command substitution, subshell/escaped forms) and the `tm_*` wrapper channel
247
- stay a **hard block** (no dialog to slip through). tm_* wrappers route through
248
- the same checks (no backdoor via the wrappers). Audit lines record only tool
249
- name + pattern category + the verdict (`ask` / `allowed-once` /
250
- `allowed-always` / `rejected` / `timeout-rejected` / `degraded`) — never
251
- command text, paths, variable names or values.
252
-
253
- **R2 dangerous operations (same dialog).** Delete (`rm`/`del`/`Remove-Item`/
254
- `rmdir`), git publishing (`git push`/`git commit`), network fetch (`curl`/
255
- `wget`/`Invoke-WebRequest`/`Invoke-RestMethod`), package installs/publishes
256
- (`npm install`/`npm publish`/`pip install`/`winget`/`choco`), process/system
257
- (`taskkill`/`Stop-Process`/`kill`/`shutdown`/`format`) and privilege changes
258
- (`chmod`/`takeown`/`icacls`) — none are silently allowed. They pop the same
259
- official dialog and are auto-rejected if you don't answer within the timeout.
260
- The normal verification stack (`npm test`, `tsc`, `git status`/`diff`) is NOT
261
- gated, so day-to-day team work runs without interruption.
262
-
263
- > ⚠️ **When you approve a dialog, pick "once" — not "always".** Verified on
264
- > the live host, "always" records a far broader rule than the command you
265
- > saw: approving `Get-ChildItem env:PATH` with "always" stores `Get-ChildItem
266
- > *`, so every later `Get-ChildItem` runs with no dialog at all. Only the
267
- > once-verdict keeps each gated operation individually human-checked.
268
-
269
- > Deferral is per-session: env reads only route to the dialog in sessions
270
- > running TeamMode's injected agents (or after such a session has shown one
271
- > of these dialogs). In any other session (e.g. a stock `build`/`plan` chat)
272
- > TeamMode's guard keeps hard-blocking env reads, since no dialog would back
273
- > them there. Compound commands (`a; b`) are evaluated per segment by the
274
- > host and approved through one dialog; the guard blocks them outright
275
- > whenever any segment is an env read.
276
-
277
- > The permission protocol was verified against a live `opencode serve` host
278
- > (1.18.29) via SSE event capture; the Desktop dialog rendering itself is the
279
- > one leg that still needs eyeballing in a real Desktop session. Headless
280
- > `opencode run` auto-rejects an unanswered `ask` immediately (there is no
281
- > human to prompt).
282
-
283
- | Env var | Default | Purpose |
284
- |---|---|---|
285
- | `TM_ENV_PROTECT` | `strict` | R6 mode: `strict` / `standard` / `off` (off also disarms the approval timer) |
286
- | `TM_ASK_TIMEOUT_MIN` | `10` | minutes before an unanswered R6/R2 confirmation dialog is auto-rejected; minimum 3 minutes (the host's `permission.replied` reaches the plugin ~120 s late on the event bus — shorter values would auto-reject a just-approved request) |
287
- | `TM_ENV_PROTECT_EXTRA_DENY` | — | extra block patterns (regex list; always a hard block, never dialog-governed) |
288
- | `TM_OFFLOAD_THRESHOLD` | `2000` | offload threshold (tokens, chars/4 estimate) |
289
- | `TM_PREVIEW_MAX_TOKENS` | `80` | preview hard cap |
290
- | `TM_FETCH_MAX_LINES` | `2000` | tm_fetch page cap |
291
- | `TM_BLACKBOARD_DIR` | `.blackboard/` | offloaded payload store |
292
- | `TM_TRAJECTORY_DIR` | `.trajectory/` | append-only tool-call ledger |
293
- | `TM_BLACKBOARD_TTL` | `7` | store retention (days) |
294
- | `TM_BASH_READONLY_ALLOWED` | built-in table | tm_bash allowlist |
295
- | `TM_PTC_MAX_PROGRAM_CHARS` | `4000` | PTC program source length cap (chars) |
296
- | `TM_PTC_MAX_CALLS` | `20` | PTC per-run bridge-call budget (1–200) |
297
- | `TM_PTC_MAX_ERRORS` | `3` | PTC per-run error budget (1–50) |
298
- | `TM_PTC_TIMEOUT_MS` | `60000` | PTC per-run wall-clock timeout (5s–10min) |
299
- | `TM_PTC_ENGINE` | `auto` | PTC engine: `auto` (worker→inline degrade) / `worker` / `inline` |
300
-
301
- ---
302
-
303
- ## ⚡ Batch orchestration (`tm_ptc_run`) — new in v1.5.2
304
-
305
- > Shipped in **v1.5.2** (2026-09-10). Requires `@te-river/opencode-team-mode@1.5.2`
306
- > or later.
307
-
308
- `tm_ptc_run` lets a specialist agent write **one async program** that makes N
309
- governed `tm_*` calls in a single turn — zero LLM round-trips during the run,
310
- only an aggregation summary returns to context. It is designed for batch
311
- read-only tasks: multi-file reconnaissance, bulk grep + read aggregation,
312
- cross-referencing search results.
313
-
314
- ### How it works
315
-
316
- The agent writes a program body using `tm.read(args)`, `tm.grep(args)`,
317
- `tm.bash(args)`, `tm.fetch(args)` — same args as the four governed tools.
318
- Each call returns `{ok:true, data}` (governed: inline text or an offload
319
- handle) or `{ok:false, error:{tool,phase,line?,message}}`. The program
320
- `return`s a value; it is JSON-serialized into the aggregation summary.
321
-
322
- Programs containing `require`, `import`, `process`, `globalThis`, `Deno`,
323
- `Bun`, `fs`, `net`, or `child_process` are rejected before execution (static
324
- pre-scan, auxiliary guard).
325
-
326
- ### Budgets (tighten-only)
327
-
328
- The caller may tighten `max_calls`, `max_errors`, and `timeout_ms` — values
329
- above the `TM_PTC_*` ceilings are clamped down; values below the floor are
330
- clamped up. Hitting any budget stops the whole run; produced output is NOT
331
- lost.
332
-
333
- ### Engine (`TM_PTC_ENGINE`)
334
-
335
- | Mode | Behavior |
336
- |---|---|
337
- | `auto` (default) | Tries `worker_threads` first; on failure degrades to `node:vm` with a `degraded-engine` mark in the summary |
338
- | `worker` | Forces the worker engine (engine-error on failure) |
339
- | `inline` | Forces the `node:vm` engine (30s compile timeout for sync busy-loops; await-gap residual documented) |
340
-
341
- The worker engine runs the program in a dedicated thread with `env:{}`
342
- (process.env emptied), `resourceLimits`, and hard wall-clock `terminate()`.
343
- All governance (P2 path scope, P3 allowlist, R6, threshold offload, TTL)
344
- applies to every bridged call — PTC is not a bypass layer.
345
-
346
- ### Access
347
-
348
- Five specialist agents (`implementer`, `tester`, `architect`, `reviewer`,
349
- `researcher`) have `tm_ptc_run` in their whitelist. The `team` lead does
350
- not — it orchestrates, it does not run batch programs itself.
351
-
352
- ---
353
-
354
- ## 🏗️ Architecture
355
-
356
- ```
357
- opencode-team-mode/
358
- ├── package.json ← npm package definition
359
- ├── tsconfig.json ← TypeScript config
360
- ├── src/
361
- │ ├── index.ts ← Plugin entry (server(): config + R6 tool.execute.before + approval-gate event + tool segment)
362
- │ ├── agents.ts ← Agent definitions (prompts, modes, colors)
363
- │ ├── commands.ts ← Command definitions (templates, agent bindings)
364
- │ ├── blackboard.ts ← Shared blackboard + TTL auto-cleanup sweeper
365
- │ ├── envprotect.ts ← R6 env-var read protection + R2 ask-pattern sets (dialog vs hard-block)
366
- │ ├── approval-gate.ts ← Unified approval gate: host-dialog timeout auto-reject (never self-allows)
367
- │ ├── tm/ ← JIT layer-2 tools (tm_read / tm_grep / tm_bash / tm_fetch / tm_ptc_run)
368
- │ └── types.ts ← Loader-contract type definitions (1.18.x)
369
- ├── scripts/
370
- │ ├── install.sh ← One-click installer (bash)
371
- │ └── install.ps1 ← One-click installer (PowerShell)
372
- ├── pt07/ ← PT-07 baseline suite (seeded A/B token measurement)
373
- ├── LICENSE ← Apache 2.0
374
- ├── README.md ← English documentation
375
- └── README.zh-CN.md ← Chinese documentation
376
- ```
377
-
378
- ### How it works
379
-
380
- 1. OpenCode Desktop starts and loads `opencode.json(c)`.
381
- 2. It sees `"@te-river/opencode-team-mode@latest"` in the `plugin` array and loads the npm package.
382
- 3. The loader calls the plugin's `server(input, options)`, which registers a `config` hook; the hook injects 6 agents and 6 commands into the merged config. The same call installs the R6 `tool.execute.before` guard, arms the unified R6/R2 approval gate (official dialog + `TM_ASK_TIMEOUT_MIN` auto-reject, wired through an `event` hook), and registers the governed `tm_*` tools (see [Context governance](#-context-governance-tm--r6--r2--new-in-v151) below).
383
- 4. The plugin's `id: "team-mode"` is displayed as the plugin name in the Desktop UI.
384
- 5. Agents and commands are immediately available in the Desktop UI — no file copying needed. User-defined agents with the same name always win (the plugin never clobbers them).
385
-
386
- ---
387
-
388
- ## 🗂️ Coordination: structured handoffs first, files second (hybrid)
389
-
390
- Sub-agents cannot message each other live (platform limitation), so TeamMode
391
- coordinates them through a **structured reply skeleton**, with a file
392
- blackboard reserved for oversized output:
393
-
394
- - **Reply skeleton (primary channel):** every specialist's final reply starts
395
- with `STATUS: / CHANGES: / FINDINGS: / EVIDENCE: / HANDOFF:` and stays ≤50
396
- lines. Deliverables at that size travel inline — zero file I/O, nothing to
397
- fall out of sync. The lead relays `HANDOFF` verbatim into the next
398
- dispatch and machine-checks the skeleton (missing → one retry with it
399
- inline, then downgrade and note the violation).
400
- - **Board files (exception only):** when a full deliverable exceeds ~50 lines
401
- (e.g. a complete architecture doc), the dispatch names ONE file:
402
- `<repo>/.git/opencode-team/<session-key>/<task-slug>/NN-<role>-<topic>.md`
403
- — inside `.git/`, so your working tree and commits are **never polluted**
404
- (non-git workspaces fall back to the OS temp dir). Writes are frozen: a
405
- revision is a new round-suffixed file (`…-r2.md`); session folders keep a
406
- fresh conversation from touching a not-yet-swept board.
407
- - **No MANIFEST.md:** the lead's state memory is its todo list.
408
- - **Feedback loop:** Critical/Major findings and product bugs automatically
409
- become tracked fix tasks until the deliverable converges (max 2 loops,
410
- then escalate to you).
411
-
412
- ### Deterministic routing, approval gate & adaptive review (v1.4.7)
413
-
414
- - **Routing table:** the lead picks a fixed pipeline row by task shape —
415
- question → direct answer; docs-only → implementer; product behavior
416
- change → implementer → tester → reviewer; multi-module feature →
417
- architect → implementer → tester → reviewer(s); unknown external tech →
418
- researcher first. Pipelines have fixed minimums: a product change routed
419
- below 3 dispatches is a routing bug, and splitting one request into
420
- sub-2-dispatch pieces to dodge the gate is a protocol violation.
421
- - **Approval gate (count-based):** ≥2 planned dispatches → the lead
422
- researches (reading the repo itself; a researcher dispatch only for
423
- unknown external tech), presents a ≤30-line plan, and **waits for your
424
- approval** before executing anything. 0-1 dispatches run with a 1-2 line
425
- notice. A task that grows a second dispatch mid-run pauses for approval.
426
- Blocking uncertainties are batched and asked immediately — never guessed,
427
- never drip-fed.
428
- - **Adaptive review:** default is ONE reviewer dispatch (correctness);
429
- three parallel dimensions (completeness / correctness / impact) only for
430
- high-risk profiles — auth/security surface, cross-module data contracts,
431
- public APIs across ≥3 files.
432
- - **Static verification:** testers verify via build, typecheck, static
433
- analysis, and API/unit tests. Improvised browser automation (headless
434
- screenshots, DOM stubs) is banned; user-visible frontend changes end with
435
- `UI NOT VERIFIED: <what needs manual checking>` unless the project
436
- already ships real browser-test tooling.
437
- - **No-ceremony fast path:** a root cause the lead has already verified
438
- (file:line evidence) goes straight to the implementer as a fix spec —
439
- investigation dispatches serve unknowns, not ritual.
440
- - **Brevity discipline:** route selection is a table lookup; user-visible
441
- planning text stays ≤5 lines.
442
- - **Evidence standard (kept):** "done / fixed / passed" claims need
443
- verifiable evidence — command output, logs, diffs. Narratives are
444
- progress notes, not proof.
445
- - **Verbatim contracts (kept):** parallel implementers that must
446
- interoperate get the exact data contract (endpoints, field names, types)
447
- pasted verbatim into every affected dispatch.
448
- - **Docs sync (CHANGELOG + AGENTS.md):** delivered changes append a
449
- CHANGELOG.md entry when one exists, and update AGENTS.md when the change
450
- alters what it records (build/test commands, conventions, structure,
451
- agent instructions); either file is offered for creation when missing.
452
- Reading is deduplicated: the lead reads the README itself (the host does
453
- not inject it), uses the host-injected AGENTS.md/CLAUDE.md copy already
454
- in context and opens those files only when genuinely absent — and
455
- specialists never re-open these docs, since conventions arrive
456
- distilled inside their dispatches.
457
-
458
- ### Triage — questions don't become code edits
459
-
460
- The Team Lead classifies every incoming message before acting: a question or
461
- consult gets an answer (zero file changes, fixes merely proposed and awaiting
462
- your go-ahead); only explicit action requests enter the workflow. And whenever
463
- you spell out what may or may not be touched, **those boundaries outrank
464
- everything else** — the lead restates them in every single dispatch.
465
-
466
- ### Cleanup — the TTL sweeper is the only path
467
-
468
- | Who | When |
469
- |---|---|
470
- | Plugin code (in-process sweeper) | At startup + every hour: removes task directories idle **beyond the TTL** |
471
-
472
- The Team Lead never deletes task directories — finished boards stay
473
- readable so you can audit how a run went, and reclamation is pure code
474
- that never relies on the model remembering to do anything (crashes and
475
- force-kills leave nothing behind either). The sweeper prunes stale task
476
- dirs individually under a still-live session, and reclaims an entirely
477
- idle session folder in one pass. Set `ttlDays` to taste.
478
-
479
- ### Configure the TTL
480
-
481
- Default is **5 days**. To choose your own, use the tuple plugin form in
482
- `opencode.jsonc`:
483
-
484
- ```jsonc
485
- {
486
- "$schema": "https://opencode.ai/config.json",
487
- "plugin": [
488
- ["@te-river/opencode-team-mode@latest", { "ttlDays": 7 }]
489
- ]
490
- }
491
- ```
492
-
493
- `ttlDays` accepts any number of days in `(0, 365]`; invalid values silently
494
- fall back to 5.
495
-
496
- ### Default agent
497
-
498
- By default TeamMode **makes Team your default agent** — new chats open
499
- directly in the team orchestrator. One side effect comes with the default
500
- slot: the switcher pins the default agent to the **first position** and
501
- sorts everything else alphabetically, so the picker order is
502
- **team, build, plan**. (Want Team below Plan instead? That requires
503
- giving up the default slot — see the opt-out below; the two are
504
- mutually exclusive by the server's sort.)
505
-
506
- To opt out (`build` stays the default, picker order **build, plan,
507
- team**):
508
-
509
- ```jsonc
510
- {
511
- "plugin": [
512
- ["@te-river/opencode-team-mode@latest", { "defaultAgent": false }]
513
- ]
514
- }
515
- ```
516
-
517
- An explicitly configured non-`build` `default_agent` in your own config is
518
- always respected untouched — the plugin never clobbers it.
519
-
520
- **Upgrade note:** v1.4.4 briefly made this promotion opt-in; v1.4.5 restores
521
- Team-as-default as the shipped behavior. If you pinned `{ "defaultAgent":
522
- true }` during v1.4.4, you can drop that option (or switch it to `false` to
523
- opt out).
524
-
525
- ---
526
-
527
- ## 🔧 Customization
528
-
529
- ### The Team Lead's model matters most
530
-
531
- The Lead is the orchestrating brain: it classifies every message, cuts the
532
- work into packages, writes each dispatch manifest, judges reviewer/tester
533
- findings, and synthesizes the final deliverable. Quality failures there
534
- **multiply down the pipeline** — a mediocre Lead mis-decomposes, briefs the
535
- experts vaguely, and waves weak work through; no specialist can rescue an
536
- assignment it was never correctly given.
537
-
538
- So run the strongest model you can afford **in the Lead seat**. The other
539
- roles tolerate cheaper models — they work from tight briefs with scoped
540
- reading. Pin models per agent:
541
-
542
- ```jsonc
543
- {
544
- "agent": {
545
- // Team Lead — orchestration earns your best model
546
- "team": { "model": "anthropic/claude-opus-4-5" },
547
- // specialists — cheaper models are usually fine
548
- "implementer": { "model": "anthropic/claude-sonnet-4-6" }
549
- }
550
- }
551
- ```
552
-
553
- (Model IDs above are placeholders — use whatever your provider exposes.
554
- Your own `agent.team` definition always takes precedence over the plugin's.)
555
-
556
- ### Override an agent
557
-
558
- Add an agent with the same name in your `opencode.json` — your definition takes precedence:
559
-
560
- ```jsonc
561
- {
562
- "agent": {
563
- "reviewer": {
564
- "model": "anthropic/claude-sonnet-4-6",
565
- "prompt": "You are an extremely strict reviewer. Reject anything with a lint warning."
566
- }
567
- }
568
- }
569
- ```
570
-
571
- ### Add your own agents
572
-
573
- TeamMode does not prevent you from adding more agents. Define them alongside the team:
574
-
575
- ```jsonc
576
- {
577
- "agent": {
578
- "devops": {
579
- "mode": "subagent",
580
- "description": "Handles CI/CD, Docker, and deployment tasks.",
581
- "prompt": "You are the DevOps engineer..."
582
- }
583
- }
584
- }
585
- ```
586
-
587
- ### Disable an agent
588
-
589
- ```jsonc
590
- {
591
- "agent": {
592
- "researcher": { "disable": true }
593
- }
594
- }
595
- ```
596
-
597
- ---
598
-
599
- ## 📦 Publishing to npm
600
-
601
- If you want to publish your own fork:
602
-
603
- ```bash
604
- npm run build # compile TypeScript → dist/
605
- npm version patch # bump version
606
- npm publish # publish to npm registry
607
- ```
608
-
609
- ---
610
-
611
- ## 🤝 Contributing
612
-
613
- Contributions are welcome! Areas where we need help:
614
-
615
- - 🌐 **Localization** — Translate agent prompts to other languages
616
- - 🎨 **More agent roles** — DevOps, DBA, Security Specialist, UX Designer
617
- - 🔧 **Additional commands** — `/team-deploy`, `/team-docs`, `/team-refactor`
618
- - 📝 **Better prompts** — Improve agent behavior through prompt engineering
619
-
620
- ---
621
-
622
- ## 📄 License
623
-
624
- [Apache License 2.0](./LICENSE)
625
-
626
- ---
627
-
628
- ## 🔗 Links
629
-
630
- - [npm Package](https://www.npmjs.com/package/@te-river/opencode-team-mode) — `@te-river/opencode-team-mode` on npm
631
- - [OpenCode Desktop](https://opencode.ai) — Official website & download
632
- - [OpenCode Docs](https://opencode.ai/docs) — Configuration & plugin documentation
633
- - [OpenCode Plugin API](https://opencode.ai/docs/plugins) — Build your own plugins
634
- - [OpenCode GitHub](https://github.com/anomalyco/opencode) — Source code for OpenCode itself
1
+ # OpenCode TeamMode
2
+
3
+ **[English](./README.md)** | **[中文](./README.zh-CN.md)**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@te-river/opencode-team-mode.svg)](https://www.npmjs.com/package/@te-river/opencode-team-mode)
6
+ [![npm downloads](https://img.shields.io/npm/dm/@te-river/opencode-team-mode.svg)](https://www.npmjs.com/package/@te-river/opencode-team-mode)
7
+ [![license](https://img.shields.io/npm/l/@te-river/opencode-team-mode.svg)](./LICENSE)
8
+
9
+ > 🤝 **Multi-agent team collaboration plugin for [OpenCode Desktop](https://opencode.ai)**
10
+ >
11
+ > Adds a complete team of specialized AI agents — Architect, Implementer, Reviewer, Tester, Researcher — orchestrated by a Team Lead, all accessible via simple slash commands.
12
+
13
+ ---
14
+
15
+ ## ✨ What is TeamMode?
16
+
17
+ TeamMode transforms OpenCode Desktop from a single-agent coding assistant into a **full development team**. Each agent has a distinct role, expertise, and personality — just like a real engineering team.
18
+
19
+ Instead of one agent trying to do everything, you get:
20
+
21
+ | Agent | Role | When to use |
22
+ |---|---|---|
23
+ | 🎯 **Team Lead** | Orchestrator | Complex tasks that need planning + multi-step execution |
24
+ | 🏗️ **Architect** | System designer | Design docs, module structure, API contracts |
25
+ | 💻 **Implementer** | Code writer | Building features, writing production code |
26
+ | 🔍 **Reviewer** | Dimension-focused auditor | Single-dimension review (completeness / correctness / impact) — ONE reviewer by default; 3 in parallel only for high-risk changes |
27
+ | 🧪 **Tester** | Test engineer | Unit tests, integration tests, edge-case coverage, static verification (build / typecheck / lint / API tests) |
28
+ | 🔎 **Researcher** | Knowledge finder | Local-repo investigation first (code, configs, installed packages, shipped docs); web lookups via user MCP tools or the governed `tm_webfetch` — one of the two network roles (with the Team Lead) |
29
+
30
+ ---
31
+
32
+ ## 🚀 Quick Start
33
+
34
+ ### Prerequisites
35
+
36
+ 1. **Install OpenCode Desktop** (if you haven't already):
37
+
38
+ | Platform | Install command |
39
+ |---|---|
40
+ | macOS (Apple Silicon) | `brew install --cask opencode-desktop` |
41
+ | macOS (Intel) | `brew install --cask opencode-desktop` |
42
+ | Windows | `scoop bucket add extras && scoop install extras/opencode-desktop` |
43
+ | Linux | Download from [opencode.ai/download](https://opencode.ai/download) |
44
+
45
+ Or install the **CLI/TUI** version:
46
+ ```bash
47
+ # one-line script (all platforms)
48
+ curl -fsSL https://opencode.ai/install | bash
49
+
50
+ # or via npm
51
+ npm install -g opencode-ai
52
+ ```
53
+
54
+ 2. **Node.js ≥ 18** (for npm)
55
+
56
+ ### Install TeamMode
57
+
58
+ **Option A — One-line installer:**
59
+
60
+ macOS / Linux (bash):
61
+ ```bash
62
+ curl -fsSL https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.sh | bash
63
+ ```
64
+
65
+ Windows (PowerShell):
66
+ ```powershell
67
+ irm https://ghproxy.net/https://raw.githubusercontent.com/Te-River/Opencode-TeamMode/main/scripts/install.ps1 | iex
68
+ ```
69
+
70
+ **Option B — Manual config:**
71
+
72
+ Add the plugin to your `opencode.jsonc`:
73
+
74
+ ```jsonc
75
+ {
76
+ "$schema": "https://opencode.ai/config.json",
77
+ "plugin": [
78
+ "@te-river/opencode-team-mode@latest"
79
+ ]
80
+ }
81
+ ```
82
+
83
+ OpenCode will automatically install the plugin on startup.
84
+
85
+ > **Tip:** After modifying `opencode.json`, **restart OpenCode Desktop** for changes to take effect.
86
+
87
+ ---
88
+
89
+ ## ⚙️ Configuration
90
+
91
+ The plugin automatically injects all team agents and commands when OpenCode starts. **No need to manually copy agent files or command definitions.**
92
+
93
+ > ⚠️ **Model choice matters.** Every judgment in the workflow — triage,
94
+ > decomposition, dispatch briefs, synthesis, review-loop verdicts — flows
95
+ > through the **Team Lead**. A weak model in that seat degrades the whole
96
+ > pipeline no matter how strong the specialists are. Pin your best
97
+ > reasoning model to the `team` agent (recipe in
98
+ > [Customization](#customization) below).
99
+
100
+ ### Global install (all projects)
101
+
102
+ To enable TeamMode in every project, add the plugin to your global config:
103
+
104
+ ```jsonc
105
+ // ~/.config/opencode/opencode.jsonc
106
+ {
107
+ "$schema": "https://opencode.ai/config.json",
108
+ "plugin": [
109
+ "@te-river/opencode-team-mode@latest"
110
+ ]
111
+ }
112
+ ```
113
+
114
+ ---
115
+
116
+ ## 📖 Usage
117
+
118
+ ### Slash Commands
119
+
120
+ TeamMode adds six slash commands to OpenCode. Type them in the chat input:
121
+
122
+ | Command | Agent | Description |
123
+ |---|---|---|
124
+ | `/team-plan <task>` | Architect | Create a detailed implementation plan with architecture, file manifest, and task breakdown |
125
+ | `/team-implement <task>` | Implementer | Write production code for a feature or task |
126
+ | `/team-review [scope]` | Reviewer | Audit code for bugs, security issues, and quality problems |
127
+ | `/team-test [scope]` | Tester | Generate comprehensive tests with edge-case coverage |
128
+ | `/team-research <topic>` | Researcher | Investigate the local repository first; web lookups via the governed `tm_browser` / `tm_webfetch`, then user MCP tools |
129
+ | `/team-run <task>` | Team Lead | **Full workflow** — orchestrates all agents end-to-end |
130
+
131
+ #### Example workflow
132
+
133
+ ```
134
+ # 1. Plan the feature
135
+ /team-plan Add user authentication with OAuth2 and JWT tokens
136
+
137
+ # 2. Review the plan, then implement
138
+ /team-implement Implement the auth module as planned
139
+
140
+ # 3. Review the code
141
+ /team-review src/auth/
142
+
143
+ # 4. Write tests
144
+ /team-test src/auth/
145
+
146
+ # Or let the team lead handle everything:
147
+ /team-run Add user authentication with OAuth2 and JWT tokens
148
+ ```
149
+
150
+ ### Agent Picker
151
+
152
+ You can also invoke agents directly using the `@` mention in OpenCode Desktop:
153
+
154
+ - `@team` — Orchestrate a complex task
155
+ - `@architect` — Design a system or module
156
+ - `@implementer` — Write code
157
+ - `@reviewer` — Review code quality
158
+ - `@tester` — Write tests
159
+ - `@researcher` — Research a topic
160
+
161
+ ### Demo
162
+
163
+ A session transcript, recreated from how the flow actually looks. Team is the
164
+ default agent out of the box (see Configuration to opt out), so the user just
165
+ types into a fresh chat:
166
+
167
+ > **User:** Add token-bucket rate limiting to our Express API — 100 requests
168
+ > per minute per user, return 429 when exceeded. Don't touch anything under
169
+ > `src/legacy/`.
170
+
171
+ ```text
172
+ team Route: product behavior change → implementer → tester → reviewer
173
+ (3 dispatches → approval gate applies)
174
+
175
+ Research: read README, src/app.ts, src/middleware/*
176
+ Blocking questions: none — 1 assumption listed below
177
+
178
+ PLAN
179
+ Goal: token-bucket limiter, 100 req/min/user, 429 + Retry-After
180
+ Scope: src/middleware/rateLimit.ts (new), src/app.ts (+3 lines)
181
+ Pipeline: implementer → tester → reviewer (correctness)
182
+ Assumption: in-memory bucket, not Redis — say the word to change
183
+ Boundary: src/legacy/** untouched
184
+ Approve to proceed?
185
+
186
+ user approved, go
187
+
188
+ team ▸ @implementer — STATUS: done
189
+ CHANGES: src/middleware/rateLimit.ts (new) · src/app.ts (+3)
190
+ HANDOFF: bucket {tokens, lastRefill}; refill() is a single atomic pass
191
+ EVIDENCE: tsc clean (output above)
192
+
193
+ ▸ @tester — STATUS: done · VERDICT: pass (14/14)
194
+ FINDINGS: burst edge, window expiry, concurrent refill covered;
195
+ src/legacy/** byte-identical
196
+ EVIDENCE: vitest 14 passed
197
+
198
+ ▸ @reviewer — STATUS: done · VERDICT: approve (correctness)
199
+ FINDINGS: no Critical/Major; 1 Minor (log line noise) noted
200
+
201
+ team Done.
202
+ rate limiter shipped: rateLimit.ts (new) · app.ts (+3) · 14 tests green
203
+ review: approve · assumption: in-memory only · src/legacy/ untouched
204
+ ```
205
+
206
+ The only message the user typed was the task and "approved, go". The
207
+ pipeline was a routing-table lookup, execution waited for plan approval,
208
+ and every handoff traveled as a structured skeleton — no file ceremony.
209
+
210
+ ### Desktop-specific features
211
+
212
+ In **OpenCode Desktop**, you get additional UX benefits:
213
+
214
+ - 🎨 **Color-coded agents** — Each agent has a distinct color in the chat UI for easy identification.
215
+ - 📋 **Agent picker** — Click the agent dropdown to switch between team agents visually.
216
+ - 🔀 **Parallel sub-tasks** — The Team Lead can dispatch multiple sub-agents simultaneously, with results shown in parallel panels.
217
+ - 📊 **Session history** — All team interactions are saved and searchable in the Desktop session sidebar.
218
+
219
+ ---
220
+
221
+ ## 🧰 Governed tools & security
222
+
223
+ Every tool TeamMode adds runs under ONE governance pipeline: outputs above
224
+ `TM_OFFLOAD_THRESHOLD` tokens never enter the context window — they are
225
+ offloaded to a run store and replaced by a content-aware preview plus an
226
+ HMAC-signed handle that the agent pages through with `tm_fetch` when it
227
+ genuinely needs the payload. Security, memory and web access shipped
228
+ across v1.5.1–v1.5.6; see [CHANGELOG.md](./CHANGELOG.md) for the history.
229
+
230
+ | Tool | What it does | Roles |
231
+ |---|---|---|
232
+ | `tm_read` / `tm_grep` / `tm_bash` / `tm_fetch` | Governed file read / regex search (host index) / read-only shell (allowlist) / paged handle retrieval | all six agents |
233
+ | `tm_memory` | Project memory store (Markdown + frontmatter): add / search / list / forget | all six agents |
234
+ | `tm_webfetch` | Single governed GET of an allowlisted web page | Lead + Researcher |
235
+ | `tm_browser` | Interactive browser session (headful CDP): open / navigate / read / screenshot / close | Lead + Researcher |
236
+ | `tm_ptc_run` | Batch orchestration: one program, N governed calls, zero LLM round-trips | all six agents |
237
+
238
+ > **Fixed tool priority ladder (every task): ① TeamMode governed tools
239
+ > (`tm_*`) → ② user MCP/plugin tools → ③ the model's own reasoning
240
+ > (a missing capability is reported as a gap, never fabricated).** The
241
+ > ladder is also a fallback chain: when a governed tool errors (no browser
242
+ > on this host, blocked host), the agent says so and drops to the next
243
+ > rung instead of giving up.
244
+
245
+ Agents are prompted to route every lookup through these tools — scan the
246
+ tool surface, plan the concrete call, expand colloquial or abbreviated
247
+ terms to canonical forms and search both spellings — instead of answering
248
+ from memory or simulating removed tools.
249
+
250
+ ### Context governance: offload, handles, previews
251
+
252
+ **JIT layer-2 tools (`tm_read` / `tm_grep` / `tm_bash` / `tm_fetch`).**
253
+ Large tool outputs are context cost's main driver: every step re-sends the
254
+ whole window. The tm_* tools run the built-in capability under governance
255
+ first: results above `TM_OFFLOAD_THRESHOLD` tokens never enter the window —
256
+ they are written to a local run store and replaced by a handle with a
257
+ content-aware preview (JSON keys / CSV header+shape / log ERROR×N stats /
258
+ code signatures / binary metadata, hard-capped at 80 tokens). When the agent
259
+ actually needs the payload it pages through it with `tm_fetch`, using an
260
+ HMAC-signed, run-scoped, expiring handle. `tm_bash` only allows read-only
261
+ commands (allowlist), and failures come back as structured errors instead of
262
+ raw dumps. Agents are prompted to route every lookup through these tools —
263
+ scan the tool surface, plan the concrete call, expand colloquial or
264
+ abbreviated terms to canonical forms and search both spellings — instead of
265
+ answering from memory or simulating removed tools.
266
+
267
+ ### Project memory (tm_memory)
268
+
269
+ **Project memory (`tm_memory`) — all agents.** Durable project facts
270
+ (build commands, environment quirks, architecture decisions, user
271
+ conventions that outlive one conversation) live as Markdown files with
272
+ frontmatter under the same git-aware store
273
+ (`<repo>/.git/opencode-team/memories/<project-slug>/<category>/`) —
274
+ human-editable, never in your working tree. `add` / `search`
275
+ (deterministic keyword scoring, top 5) / `list` / `forget`; content is
276
+ capped at 4000 chars per memory — task state belongs to the todo list,
277
+ oversized docs to board files. Agents are prompted to search before
278
+ assuming project conventions and to save hard-won facts for the next
279
+ conversation.
280
+
281
+ ### Web access (tm_browser + tm_webfetch) — network roles only
282
+
283
+ 1. **Governed web tools.** `tm_browser` — an interactive browser session
284
+ driving **your own Chromium-family browser** (Edge probed first on
285
+ Windows) headful via the CDP pipe protocol: open → navigate → read
286
+ (page text, threshold-governed like tm_read) → screenshot (PNG saved
287
+ to the run store, only the path enters context) → close. Isolated
288
+ temp profile (never your real one); the **domain allowlist is enforced
289
+ at the network layer** per request (CDP `Fetch.requestPaused` —
290
+ non-allowlisted hosts get `BlockedByClient`). Display-less Linux
291
+ hosts run headless automatically; `TM_BROWSER_HEADLESS` forces either
292
+ way, `TM_BROWSER_PATH` points at a specific executable. `tm_webfetch`
293
+ — a single governed GET of an allowlisted page. Both ride the same
294
+ governance as every tm_* tool (threshold offload + content-aware
295
+ preview + `tm_fetch` handle), so a web page can never flood the
296
+ context.
297
+ 2. **User MCP/plugin tools.** Browser automation, search or fetch tools
298
+ from user-configured MCP servers are the fallback for what the
299
+ governed tools cannot do — the whitelist never touches them.
300
+ 3. The other four agents (architect / implementer / reviewer / tester)
301
+ have NO network grant — web questions are reported as a gap, never
302
+ simulated. The built-in webfetch/websearch tools stay removed; remote
303
+ `.env`-style URLs are refused (R6 red line).
304
+
305
+ Seeded allowlist hosts (both web tools): `mobile.moegirl.org.cn` (wiki
306
+ term), `search.bilibili.com`, `cn.bing.com`, `www.baidu.com` (search URL
307
+ templates); extend via `TM_WEBFETCH_ALLOWED_DOMAINS` (`"*"` opens every
308
+ host).
309
+
310
+ Seeded allowlist hosts (both web tools): `mobile.moegirl.org.cn` (wiki
311
+ term), `search.bilibili.com`, `cn.bing.com`, `www.baidu.com` (search URL
312
+ templates); extend via `TM_WEBFETCH_ALLOWED_DOMAINS` (`"*"` opens every
313
+ host).
314
+
315
+ ### Security: R6 + R2 approval gate
316
+
317
+ **R6 environment protection (now an approval gate).** With TeamMode active,
318
+ the model cannot read environment variables silently. Env-var reads
319
+ (`printenv`, `env`, `Get-ChildItem env:`, …) and env files (`.env`, shell rc
320
+ files) route through OpenCode's **official confirmation dialog**: you get a
321
+ native prompt to approve or deny, and an unanswered prompt is **auto-rejected
322
+ after `TM_ASK_TIMEOUT_MIN` (default 10 min)** — the plugin only ever rejects
323
+ on timeout, never approves on the model's behalf. Env reads that no wildcard
324
+ can express (embedded `$VAR` / `${VAR}` / `$env:` inside another command,
325
+ command substitution, subshell/escaped forms) and the `tm_*` wrapper channel
326
+ stay a **hard block** (no dialog to slip through). tm_* wrappers route through
327
+ the same checks (no backdoor via the wrappers). Audit lines record only tool
328
+ name + pattern category + the verdict (`ask` / `allowed-once` /
329
+ `allowed-always` / `rejected` / `timeout-rejected` / `degraded`) — never
330
+ command text, paths, variable names or values.
331
+
332
+ **R2 dangerous operations (same dialog).** Delete (`rm`/`del`/`Remove-Item`/
333
+ `rmdir`), git publishing (`git push`/`git commit`), network fetch (`curl`/
334
+ `wget`/`Invoke-WebRequest`/`Invoke-RestMethod`), package installs/publishes
335
+ (`npm install`/`npm publish`/`pip install`/`winget`/`choco`), process/system
336
+ (`taskkill`/`Stop-Process`/`kill`/`shutdown`/`format`) and privilege changes
337
+ (`chmod`/`takeown`/`icacls`) — none are silently allowed. They pop the same
338
+ official dialog and are auto-rejected if you don't answer within the timeout.
339
+ The normal verification stack (`npm test`, `tsc`, `git status`/`diff`) is NOT
340
+ gated, so day-to-day team work runs without interruption.
341
+
342
+ > ⚠️ **When you approve a dialog, pick "once" — not "always".** Verified on
343
+ > the live host, "always" records a far broader rule than the command you
344
+ > saw: approving `Get-ChildItem env:PATH` with "always" stores `Get-ChildItem
345
+ > *`, so every later `Get-ChildItem` runs with no dialog at all. Only the
346
+ > once-verdict keeps each gated operation individually human-checked.
347
+ > (If you do pick "always" on an env dialog, TeamMode scopes it to the
348
+ > current session — and env-FILE reads such as `cat .env` stay hard-blocked
349
+ > regardless: no dialog ever backs them, so no "always" can consent to them.)
350
+
351
+ > Deferral is per-session: env reads only route to the dialog in sessions
352
+ > running TeamMode's injected agents (or after such a session has shown one
353
+ > of these dialogs). In any other session (e.g. a stock `build`/`plan` chat)
354
+ > TeamMode's guard keeps hard-blocking env reads, since no dialog would back
355
+ > them there. Within one session, a user prompt routed to a non-injected
356
+ > agent REVOKES that eligibility (the per-turn agent signal rides
357
+ > `message.updated`; the verified host passes NO agent to
358
+ > `tool.execute.before`). Compound commands (`a; b`) are evaluated per segment by the
359
+ > host and approved through one dialog; the guard blocks them outright
360
+ > whenever any segment is an env read.
361
+
362
+ > The permission protocol was verified against a live `opencode serve` host
363
+ > (1.18.29) via SSE event capture; the Desktop dialog rendering itself is the
364
+ > one leg that still needs eyeballing in a real Desktop session. Headless
365
+ > `opencode run` auto-rejects an unanswered `ask` immediately (there is no
366
+ > human to prompt).
367
+
368
+ ### Repo hygiene & path semantics
369
+
370
+ > **Repo hygiene.** The offload/trajectory stores live under
371
+ > `<repo>/.git/opencode-team/` (or the OS temp dir outside a git repo) —
372
+ > never your working tree. Every agent is instructed to delete scratch /
373
+ > temporary files it created before reporting done, and to keep throwaway
374
+ > work in the OS temp dir so nothing lands in the repo at all. `tm_read` /
375
+ > `tm_grep` paths are relative to the **project root** (not the agent's
376
+ > working directory).
377
+
378
+ ### Environment variables
379
+
380
+ | Env var | Default | Purpose |
381
+ |---|---|---|
382
+ | `TM_ENV_PROTECT` | `strict` | R6 mode: `strict` / `standard` / `off` (off also disarms the approval timer) |
383
+ | `TM_ASK_TIMEOUT_MIN` | `10` | minutes before an unanswered R6/R2 confirmation dialog is auto-rejected; minimum 3 minutes (the host's `permission.replied` reaches the plugin ~120 s late on the event bus — shorter values would auto-reject a just-approved request) |
384
+ | `TM_ENV_PROTECT_EXTRA_DENY` | — | extra block patterns (regex list; always a hard block, never dialog-governed) |
385
+ | `TM_OFFLOAD_THRESHOLD` | `2000` | offload threshold (tokens, CJK-aware estimate) |
386
+ | `TM_PREVIEW_MAX_TOKENS` | `80` | preview hard cap |
387
+ | `TM_FETCH_MAX_LINES` | `2000` | tm_fetch page cap |
388
+ | `TM_BLACKBOARD_DIR` | `<repo>/.git/opencode-team/blackboard/` | offloaded payload store (tmpdir fallback outside a git repo; explicit value = absolute or project-relative) |
389
+ | `TM_TRAJECTORY_DIR` | `<repo>/.git/opencode-team/trajectory/` | append-only tool-call ledger (tmpdir fallback outside a git repo) |
390
+ | `TM_BLACKBOARD_TTL` | `7` | store retention (days) |
391
+ | `TM_BASH_READONLY_ALLOWED` | built-in table | tm_bash allowlist |
392
+ | `TM_WEBFETCH_ALLOWED_DOMAINS` | `mobile.moegirl.org.cn, search.bilibili.com, cn.bing.com, www.baidu.com` | tm_webfetch/tm_browser allowlist (`"*"` opens every host; explicit empty = deny all) |
393
+ | `TM_BROWSER_PATH` | auto-detect | tm_browser executable override (Edge/Chrome/Chromium probed per OS) |
394
+ | `TM_BROWSER_HEADLESS` | `auto` | tm_browser: `1` headless (servers/CI) / `0` headful / `auto` (headless only on display-less Linux) |
395
+ | `TM_PTC_MAX_PROGRAM_CHARS` | `4000` | PTC program source length cap (chars) |
396
+ | `TM_PTC_MAX_CALLS` | `20` | PTC per-run bridge-call budget (1–200) |
397
+ | `TM_PTC_MAX_ERRORS` | `3` | PTC per-run error budget (1–50) |
398
+ | `TM_PTC_TIMEOUT_MS` | `60000` | PTC per-run wall-clock timeout (5s–10min) |
399
+ | `TM_PTC_ENGINE` | `auto` | PTC engine: `auto` (worker→inline degrade) / `worker` / `inline` |
400
+
401
+ ### Batch orchestration (tm_ptc_run)
402
+
403
+ `tm_ptc_run` lets a specialist agent write **one async program** that makes N
404
+ governed `tm_*` calls in a single turn — zero LLM round-trips during the run,
405
+ only an aggregation summary returns to context. It is designed for batch
406
+ read-only tasks: multi-file reconnaissance, bulk grep + read aggregation,
407
+ cross-referencing search results.
408
+
409
+ #### How it works
410
+
411
+ The agent writes a program body using `tm.read(args)`, `tm.grep(args)`,
412
+ `tm.bash(args)`, `tm.fetch(args)` — same args as the four governed tools.
413
+ Each call returns `{ok:true, data}` (governed: inline text or an offload
414
+ handle) or `{ok:false, error:{tool,phase,line?,message}}`. The program
415
+ `return`s a value; it is JSON-serialized into the aggregation summary.
416
+
417
+ Programs containing `require`, `import`, `process`, `globalThis`, `Deno`,
418
+ `Bun`, `fs`, `net`, or `child_process` are rejected before execution (static
419
+ pre-scan, auxiliary guard).
420
+
421
+ #### Budgets (tighten-only)
422
+
423
+ The caller may tighten `max_calls`, `max_errors`, and `timeout_ms` — values
424
+ above the `TM_PTC_*` ceilings are clamped down; values below the floor are
425
+ clamped up. Hitting any budget stops the whole run; produced output is NOT
426
+ lost.
427
+
428
+ #### Engine (`TM_PTC_ENGINE`)
429
+
430
+ | Mode | Behavior |
431
+ |---|---|
432
+ | `auto` (default) | Tries `worker_threads` first; on engine failure it re-runs the WHOLE program on `node:vm` with a `degraded-engine` mark in the summary (bridged calls are read-only, so a re-run is safe; the fallback starts with fresh budgets under the same wall-clock deadline) |
433
+ | `worker` | Forces the worker engine (engine-error on failure) |
434
+ | `inline` | Forces the `node:vm` engine (script timeout kills pre-await synchronous busy-loops; a busy loop after the first `await` blocks the host event loop irrecoverably — prefer worker/auto) |
435
+
436
+ The worker engine runs the program in a dedicated thread with `env:{}`
437
+ (process.env emptied), `resourceLimits`, and hard wall-clock `terminate()`.
438
+ All governance (P2 path scope, P3 allowlist, R6, threshold offload, TTL)
439
+ applies to every bridged call — PTC is not a bypass layer.
440
+
441
+ #### Access
442
+
443
+ `tm_ptc_run` is in the whitelist of **all six** agents (the `team` lead
444
+ included — v1.5.4 revised the original deny ruling). Every bridged call
445
+ still runs the full governed tm_* pipeline (P2 path scope, P3 allowlist, R6,
446
+ threshold offload + handles, TTL), so batch orchestration is a convenience
447
+ gain, not a governance gap.
448
+
449
+ ---
450
+
451
+ ## 🏗️ Architecture
452
+
453
+ ```
454
+ opencode-team-mode/
455
+ ├── package.json ← npm package definition
456
+ ├── tsconfig.json ← TypeScript config
457
+ ├── src/
458
+ │ ├── index.ts ← Plugin entry (server(): config + R6 tool.execute.before + approval-gate event + tool segment)
459
+ │ ├── agents.ts ← Agent structure (modes, colors, temperatures, whitelist matrix)
460
+ │ ├── prompts/ ← The agent prompt strings (lead / specialists / shared) — pinned by tests
461
+ │ ├── commands.ts ← Command definitions (templates, agent bindings)
462
+ │ ├── blackboard.ts ← Shared blackboard + TTL auto-cleanup sweeper
463
+ │ ├── envprotect.ts ← R6 facade → envprotect/ (patterns / bash-classify / path-classify / gate-predicates / hook)
464
+ │ ├── approval-gate.ts ← Unified approval gate: host-dialog timeout auto-reject (never self-allows)
465
+ │ ├── tm/ ← JIT layer-2 tools: pipelines / result / client-unwrap / shell-bridge / args-schema / tools / guard / preview / store / refs / config / webfetch / memory / browser / ptc/ (9 modules)
466
+ │ └── types.ts ← Loader-contract type definitions (1.18.x)
467
+ ├── scripts/
468
+ │ ├── install.sh ← One-click installer (bash)
469
+ │ └── install.ps1 ← One-click installer (PowerShell)
470
+ ├── pt07/ ← PT-07 baseline suite (seeded A/B token measurement)
471
+ ├── LICENSE ← Apache 2.0
472
+ ├── README.md ← English documentation
473
+ └── README.zh-CN.md ← Chinese documentation
474
+ ```
475
+
476
+ ### How it works
477
+
478
+ 1. OpenCode Desktop starts and loads `opencode.json(c)`.
479
+ 2. It sees `"@te-river/opencode-team-mode@latest"` in the `plugin` array and loads the npm package.
480
+ 3. The loader calls the plugin's `server(input, options)`, which registers a `config` hook; the hook injects 6 agents and 6 commands into the merged config. The same call installs the R6 `tool.execute.before` guard, arms the unified R6/R2 approval gate (official dialog + `TM_ASK_TIMEOUT_MIN` auto-reject, wired through an `event` hook), and registers the governed `tm_*` tools (see [Governed tools & security](#-governed-tools--security) below).
481
+ 4. The plugin's `id: "team-mode"` is displayed as the plugin name in the Desktop UI.
482
+ 5. Agents and commands are immediately available in the Desktop UI — no file copying needed. User-defined agents with the same name always win (the plugin never clobbers them).
483
+
484
+ ---
485
+
486
+ ## 🤖 How the team works
487
+
488
+ Sub-agents cannot message each other live (platform limitation), so TeamMode
489
+ coordinates them through a **structured reply skeleton**, with a file
490
+ blackboard reserved for oversized output:
491
+
492
+ - **Reply skeleton (primary channel):** every specialist's final reply starts
493
+ with `STATUS: / CHANGES: / FINDINGS: / EVIDENCE: / HANDOFF:` and stays ≤50
494
+ lines. Deliverables at that size travel inline — zero file I/O, nothing to
495
+ fall out of sync. The lead relays `HANDOFF` verbatim into the next
496
+ dispatch and machine-checks the skeleton (missing → one retry with it
497
+ inline, then downgrade and note the violation).
498
+ - **Board files (exception only):** when a full deliverable exceeds ~50 lines
499
+ (e.g. a complete architecture doc), the dispatch names ONE file:
500
+ `<repo>/.git/opencode-team/<session-key>/<task-slug>/NN-<role>-<topic>.md`
501
+ — inside `.git/`, so your working tree and commits are **never polluted**
502
+ (non-git workspaces fall back to the OS temp dir). Writes are frozen: a
503
+ revision is a new round-suffixed file (`…-r2.md`); session folders keep a
504
+ fresh conversation from touching a not-yet-swept board.
505
+ - **No MANIFEST.md:** the lead's state memory is its todo list.
506
+ - **Feedback loop:** Critical/Major findings and product bugs automatically
507
+ become tracked fix tasks until the deliverable converges (max 2 loops,
508
+ then escalate to you).
509
+
510
+ ### Deterministic routing, approval gate & adaptive review
511
+
512
+ - **Routing table:** the lead picks a fixed pipeline row by task shape —
513
+ question → direct answer; docs-only → implementer; product behavior
514
+ change → implementer → tester → reviewer; multi-module feature →
515
+ architect → implementer → tester → reviewer(s); unknown external tech →
516
+ researcher first. Pipelines have fixed minimums: a product change routed
517
+ below 3 dispatches is a routing bug, and splitting one request into
518
+ sub-2-dispatch pieces to dodge the gate is a protocol violation.
519
+ - **Approval gate (count-based):** ≥2 planned dispatches → the lead
520
+ researches (reading the repo itself; a researcher dispatch only for
521
+ unknown external tech), presents a ≤30-line plan, and **waits for your
522
+ approval** before executing anything. 0-1 dispatches run with a 1-2 line
523
+ notice. A task that grows a second dispatch mid-run pauses for approval.
524
+ Blocking uncertainties are batched and asked immediately — never guessed,
525
+ never drip-fed.
526
+ - **Adaptive review:** default is ONE reviewer dispatch (correctness);
527
+ three parallel dimensions (completeness / correctness / impact) only for
528
+ high-risk profiles — auth/security surface, cross-module data contracts,
529
+ public APIs across ≥3 files.
530
+ - **Static verification:** testers verify via build, typecheck, static
531
+ analysis, and API/unit tests. Improvised browser automation (headless
532
+ screenshots, DOM stubs) is banned; user-visible frontend changes end with
533
+ `UI NOT VERIFIED: <what needs manual checking>` unless the project
534
+ already ships real browser-test tooling.
535
+ - **No-ceremony fast path:** a root cause the lead has already verified
536
+ (file:line evidence) goes straight to the implementer as a fix spec —
537
+ investigation dispatches serve unknowns, not ritual.
538
+ - **Brevity discipline:** route selection is a table lookup; user-visible
539
+ planning text stays ≤5 lines.
540
+ - **Evidence standard (kept):** "done / fixed / passed" claims need
541
+ verifiable evidence — command output, logs, diffs. Narratives are
542
+ progress notes, not proof.
543
+ - **Verbatim contracts (kept):** parallel implementers that must
544
+ interoperate get the exact data contract (endpoints, field names, types)
545
+ pasted verbatim into every affected dispatch.
546
+ - **Docs sync (CHANGELOG + AGENTS.md):** delivered changes append a
547
+ CHANGELOG.md entry when one exists, and update AGENTS.md when the change
548
+ alters what it records (build/test commands, conventions, structure,
549
+ agent instructions); either file is offered for creation when missing.
550
+ Reading is deduplicated: the lead reads the README itself (the host does
551
+ not inject it), uses the host-injected AGENTS.md/CLAUDE.md copy already
552
+ in context and opens those files only when genuinely absent — and
553
+ specialists never re-open these docs, since conventions arrive
554
+ distilled inside their dispatches.
555
+
556
+ ### Triage — questions don't become code edits
557
+
558
+ The Team Lead classifies every incoming message before acting: a question or
559
+ consult gets an answer (zero file changes, fixes merely proposed and awaiting
560
+ your go-ahead); only explicit action requests enter the workflow. And whenever
561
+ you spell out what may or may not be touched, **those boundaries outrank
562
+ everything else** — the lead restates them in every single dispatch.
563
+
564
+ ### Cleanup — the TTL sweeper is the only path
565
+
566
+ | Who | When |
567
+ |---|---|
568
+ | Plugin code (in-process sweeper) | At startup + every hour: removes task directories idle **beyond the TTL** |
569
+
570
+ The Team Lead never deletes task directories — finished boards stay
571
+ readable so you can audit how a run went, and reclamation is pure code
572
+ that never relies on the model remembering to do anything (crashes and
573
+ force-kills leave nothing behind either). The sweeper prunes stale task
574
+ dirs individually under a still-live session, and reclaims an entirely
575
+ idle session folder in one pass. Set `ttlDays` to taste.
576
+
577
+ ### Configure the TTL
578
+
579
+ Default is **5 days**. To choose your own, use the tuple plugin form in
580
+ `opencode.jsonc`:
581
+
582
+ ```jsonc
583
+ {
584
+ "$schema": "https://opencode.ai/config.json",
585
+ "plugin": [
586
+ ["@te-river/opencode-team-mode@latest", { "ttlDays": 7 }]
587
+ ]
588
+ }
589
+ ```
590
+
591
+ `ttlDays` accepts any number of days in `(0, 365]`; invalid values silently
592
+ fall back to 5.
593
+
594
+ ### Default agent
595
+
596
+ By default TeamMode **makes Team your default agent** — new chats open
597
+ directly in the team orchestrator. One side effect comes with the default
598
+ slot: the switcher pins the default agent to the **first position** and
599
+ sorts everything else alphabetically, so the picker order is
600
+ **team, build, plan**. (Want Team below Plan instead? That requires
601
+ giving up the default slot — see the opt-out below; the two are
602
+ mutually exclusive by the server's sort.)
603
+
604
+ To opt out (`build` stays the default, picker order **build, plan,
605
+ team**):
606
+
607
+ ```jsonc
608
+ {
609
+ "plugin": [
610
+ ["@te-river/opencode-team-mode@latest", { "defaultAgent": false }]
611
+ ]
612
+ }
613
+ ```
614
+
615
+ An explicitly configured non-`build` `default_agent` in your own config is
616
+ always respected untouched — the plugin never clobbers it.
617
+
618
+ **Upgrade note:** v1.4.4 briefly made this promotion opt-in; v1.4.5 restores
619
+ Team-as-default as the shipped behavior. If you pinned `{ "defaultAgent":
620
+ true }` during v1.4.4, you can drop that option (or switch it to `false` to
621
+ opt out).
622
+
623
+ ---
624
+
625
+ ## 🔧 Customization
626
+
627
+ ### The Team Lead's model matters most
628
+
629
+ The Lead is the orchestrating brain: it classifies every message, cuts the
630
+ work into packages, writes each dispatch manifest, judges reviewer/tester
631
+ findings, and synthesizes the final deliverable. Quality failures there
632
+ **multiply down the pipeline** — a mediocre Lead mis-decomposes, briefs the
633
+ experts vaguely, and waves weak work through; no specialist can rescue an
634
+ assignment it was never correctly given.
635
+
636
+ So run the strongest model you can afford **in the Lead seat**. The other
637
+ roles tolerate cheaper models — they work from tight briefs with scoped
638
+ reading. Pin models per agent:
639
+
640
+ ```jsonc
641
+ {
642
+ "agent": {
643
+ // Team Lead — orchestration earns your best model
644
+ "team": { "model": "anthropic/claude-opus-4-5" },
645
+ // specialists — cheaper models are usually fine
646
+ "implementer": { "model": "anthropic/claude-sonnet-4-6" }
647
+ }
648
+ }
649
+ ```
650
+
651
+ (Model IDs above are placeholders — use whatever your provider exposes.
652
+ Your own `agent.team` definition always takes precedence over the plugin's.)
653
+
654
+ ### Override an agent
655
+
656
+ Add an agent with the same name in your `opencode.json` — your definition takes precedence:
657
+
658
+ ```jsonc
659
+ {
660
+ "agent": {
661
+ "reviewer": {
662
+ "model": "anthropic/claude-sonnet-4-6",
663
+ "prompt": "You are an extremely strict reviewer. Reject anything with a lint warning."
664
+ }
665
+ }
666
+ }
667
+ ```
668
+
669
+ ### Add your own agents
670
+
671
+ TeamMode does not prevent you from adding more agents. Define them alongside the team:
672
+
673
+ ```jsonc
674
+ {
675
+ "agent": {
676
+ "devops": {
677
+ "mode": "subagent",
678
+ "description": "Handles CI/CD, Docker, and deployment tasks.",
679
+ "prompt": "You are the DevOps engineer..."
680
+ }
681
+ }
682
+ }
683
+ ```
684
+
685
+ ### Disable an agent
686
+
687
+ ```jsonc
688
+ {
689
+ "agent": {
690
+ "researcher": { "disable": true }
691
+ }
692
+ }
693
+ ```
694
+
695
+ ---
696
+
697
+ ## 📦 Publishing to npm
698
+
699
+ If you want to publish your own fork:
700
+
701
+ ```bash
702
+ npm run build # compile TypeScript → dist/
703
+ npm version patch # bump version
704
+ npm publish # publish to npm registry
705
+ ```
706
+
707
+ ---
708
+
709
+ ## 🤝 Contributing
710
+
711
+ Contributions are welcome! Areas where we need help:
712
+
713
+ - 🌐 **Localization** — Translate agent prompts to other languages
714
+ - 🎨 **More agent roles** — DevOps, DBA, Security Specialist, UX Designer
715
+ - 🔧 **Additional commands** — `/team-deploy`, `/team-docs`, `/team-refactor`
716
+ - 📝 **Better prompts** — Improve agent behavior through prompt engineering
717
+
718
+ ---
719
+
720
+ ## 📄 License
721
+
722
+ [Apache License 2.0](./LICENSE)
723
+
724
+ ---
725
+
726
+ ## 🔗 Links
727
+
728
+ - [npm Package](https://www.npmjs.com/package/@te-river/opencode-team-mode) — `@te-river/opencode-team-mode` on npm
729
+ - [OpenCode Desktop](https://opencode.ai) — Official website & download
730
+ - [OpenCode Docs](https://opencode.ai/docs) — Configuration & plugin documentation
731
+ - [OpenCode Plugin API](https://opencode.ai/docs/plugins) — Build your own plugins
732
+ - [OpenCode GitHub](https://github.com/anomalyco/opencode) — Source code for OpenCode itself