@jmanuelcorral/openteam 0.1.0 → 0.1.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 CHANGED
@@ -1,315 +1,358 @@
1
- # openteam
2
-
3
- **openteam — plugin de opencode con routing coste-consciente local-first, fallback FRONTIER cheapest-capable y orquestación multiagente tipo Squad.**
4
-
5
- ## Tabla de contenidos
6
-
7
- - [Qué es y por qué existe](#qué-es-y-por-qué-existe)
8
- - [Características](#características)
9
- - [Requisitos](#requisitos)
10
- - [Instalación](#instalación)
11
- - [Configuración](#configuración)
12
- - [Uso](#uso)
13
- - [Ejemplos en Windows](#ejemplos-en-windows)
14
- - [Privacidad](#privacidad)
15
- - [Calidad](#calidad)
16
- - [Compatibilidad](#compatibilidad)
17
- - [Roadmap](#roadmap)
18
- - [Licencia](#licencia)
19
-
20
- ## Qué es y por qué existe
21
-
22
- openteam añade a opencode una capa de routing y orquestación para ahorrar tokens y coste frontier sin perder calidad ni privacidad. La estrategia por defecto es **local-first**: tareas triviales, resúmenes, documentación sencilla y diffs pequeños intentan usar runtimes locales; tareas de arquitectura, seguridad, refactors multiarchivo, tool calling crítico o debugging ambiguo escalan a **FRONTIER cheapest-capable**.
23
-
24
- El router mantiene una garantía de privacidad: con `privacyMode: "forceLocalOnSensitive"`, una tarea marcada como `privacySensitive` no escala a frontier.
25
-
26
- ## Características
27
-
28
- - Routing por turno desde el hook `chat.message`, mutando `output.message.model` antes de que opencode persista el mensaje.
29
- - Registro de runtimes locales OpenAI-compatible: Ollama, LM Studio y Foundry Local.
30
- - Clasificador local JSON con fallback heurístico determinista.
31
- - Perfiles de capacidad desde Models.dev, con cache y fallback curado cuando el catálogo no está disponible.
32
- - Selección frontier **cheapest-capable** por coste blended `0.75 * inputUSD + 0.25 * outputUSD`.
33
- - Presupuestos por sesión, mes y tokens frontier por sesión.
34
- - Telemetría `CostRecord` JSONL hash-only: guarda `promptHash`, métricas de coste y decisión, nunca prompts crudos.
35
- - Orquestación Squad con `runRoleTask` / `runRoleTasks`, subsesiones SDK y modelo explícito en `client.session.prompt({ body: { model } })`.
36
- - Refresh de disponibilidad local al arrancar y en eventos `session.created` / `session.idle`.
37
-
38
- ## Requisitos
39
-
40
- - opencode compatible con `@opencode-ai/plugin` `1.17.13`.
41
- - Bun `>=1.3` para desarrollo y tests.
42
- - Runtimes locales opcionales:
43
- - Ollama en `http://localhost:11434/v1`.
44
- - LM Studio en `http://localhost:1234/v1`.
45
- - Foundry Local con puerto dinámico descubierto por CLI en Windows.
46
-
47
- ## Instalación
48
-
49
- ### Opción A: paquete npm
50
-
51
- El paquete se publica como `@jmanuelcorral/openteam`. opencode instala los plugins declarados en el array `plugin` de `opencode.json`; basta con referenciar el nombre del paquete:
52
-
53
- ```jsonc
54
- {
55
- "$schema": "https://opencode.ai/config.json",
56
- "model": "anthropic/claude-sonnet-4-5",
57
- "small_model": "ollama/qwen3:8b",
58
- "plugin": [
59
- [
60
- "@jmanuelcorral/openteam",
61
- {
62
- "baseline": {
63
- "mode": "auto",
64
- "pinnedModel": null,
65
- "hardDefault": {
66
- "providerID": "anthropic",
67
- "modelID": "claude-sonnet-4-5"
68
- }
69
- },
70
- "router": {
71
- "mode": "balanced",
72
- "localDefault": {
73
- "providerID": "ollama",
74
- "modelID": "qwen3:8b"
75
- },
76
- "trivialPromptMaxChars": 280,
77
- "frontierPromptMinChars": 2000
78
- },
79
- "local": {
80
- "runtimes": [
81
- {
82
- "id": "ollama",
83
- "enabled": true,
84
- "baseURL": "http://localhost:11434/v1",
85
- "defaultModel": {
86
- "providerID": "ollama",
87
- "modelID": "qwen3:8b"
88
- }
89
- },
90
- {
91
- "id": "lmstudio",
92
- "enabled": true,
93
- "baseURL": "http://localhost:1234/v1",
94
- "defaultModel": {
95
- "providerID": "lmstudio",
96
- "modelID": "qwen2.5-coder-local"
97
- }
98
- }
99
- ]
100
- },
101
- "budgets": {
102
- "sessionUSD": 2,
103
- "monthlyUSD": 30,
104
- "frontierTokensPerSession": 250000,
105
- "hardStopOnBudgetExhaustion": false
106
- },
107
- "privacyMode": "forceLocalOnSensitive",
108
- "telemetry": {
109
- "enabled": true,
110
- "path": ".opencode/openteam-telemetry.jsonl"
111
- }
112
- }
113
- ]
114
- ],
115
- "provider": {
116
- "ollama": {
117
- "npm": "@ai-sdk/openai-compatible",
118
- "name": "Ollama (local)",
119
- "options": {
120
- "baseURL": "http://localhost:11434/v1",
121
- "apiKey": "ollama",
122
- "chunkTimeout": 60000
123
- },
124
- "models": {
125
- "qwen3:8b": {
126
- "name": "Qwen3 8B (Ollama)",
127
- "tool_call": true,
128
- "limit": { "context": 32768, "output": 8192 }
129
- }
130
- }
131
- },
132
- "lmstudio": {
133
- "npm": "@ai-sdk/openai-compatible",
134
- "name": "LM Studio (local)",
135
- "options": {
136
- "baseURL": "http://localhost:1234/v1",
137
- "apiKey": "lm-studio"
138
- },
139
- "models": {
140
- "qwen2.5-coder-local": {
141
- "name": "Qwen2.5 Coder Local",
142
- "tool_call": true,
143
- "limit": { "context": 32768, "output": 8192 }
144
- }
145
- }
146
- }
147
- }
148
- }
149
- ```
150
-
151
- ### Opción B: ruta de desarrollo
152
-
153
- Durante desarrollo puedes cargar un plugin local desde `.opencode/plugins/openteam.ts`:
154
-
155
- ```jsonc
156
- {
157
- "$schema": "https://opencode.ai/config.json",
158
- "plugin": [
159
- [
160
- "./.opencode/plugins/openteam.ts",
161
- {
162
- "router": {
163
- "mode": "balanced",
164
- "localDefault": {
165
- "providerID": "ollama",
166
- "modelID": "qwen3:8b"
167
- }
168
- },
169
- "telemetry": {
170
- "path": ".opencode/openteam-telemetry.jsonl"
171
- }
172
- }
173
- ]
174
- ]
175
- }
176
- ```
177
-
178
- ## Configuración
179
-
180
- La configuración runtime canónica vive en `.opencode/openteam.json`; este repositorio incluye `.opencode/openteam.example.json` como ejemplo completo. La forma validada por Zod es la de `src/config/schema.ts`. `telemetry` es una opción del plugin leída por `src/index.ts`, no parte del objeto `OpenTeamConfig` persistido.
181
-
182
- | Key | Tipo | Default | Descripción |
183
- | --- | --- | --- | --- |
184
- | `baseline.mode` | `"auto" \| "pinned"` | `"auto"` | En `auto`, usa perfiles frontier cheapest-capable cuando se pasan al router; en `pinned`, usa `baseline.pinnedModel` si existe. |
185
- | `baseline.pinnedModel` | `ModelRef \| null` | `null` | Modelo frontier fijado explícitamente. `ModelRef` usa `{ "providerID": string, "modelID": string }`. |
186
- | `baseline.hardDefault` | `ModelRef` | `{ "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }` | Fallback frontier si no hay perfiles cheapest-capable o pin válido. |
187
- | `router.mode` | `"economy" \| "balanced" \| "quality"` | `"balanced"` | Modo de routing validado y reservado para política. |
188
- | `router.localDefault` | `ModelRef` | `{ "providerID": "ollama", "modelID": "qwen3:8b" }` | Modelo local principal. |
189
- | `router.trivialPromptMaxChars` | `number` entero positivo | `280` | Prompts sin código hasta este tamaño prefieren local. |
190
- | `router.frontierPromptMinChars` | `number` entero positivo | `2000` | Prompts desde este tamaño se tratan como candidatos a frontier si no aplican guards. |
191
- | `local.runtimes` | `LocalRuntime[]` | Ollama enabled en `http://localhost:11434/v1` con `qwen3:8b` | Lista mínima de un runtime local. |
192
- | `local.runtimes[].id` | `"ollama" \| "lmstudio" \| "foundry-local"` | requerido | Runtime local. |
193
- | `local.runtimes[].enabled` | `boolean` | `true` | Habilita o deshabilita ese runtime. |
194
- | `local.runtimes[].baseURL` | URL opcional | según runtime/config | Endpoint OpenAI-compatible `/v1`; Foundry Local puede omitirlo si usa discovery. |
195
- | `local.runtimes[].discovery` | `"cli" \| "sdk" \| "manual"` opcional | sin default por item | Discovery de Foundry Local; el registry usa CLI si está configurado y no es `manual`. |
196
- | `local.runtimes[].defaultModel` | `ModelRef` | requerido | Modelo por defecto de ese runtime. |
197
- | `budgets.sessionUSD` | `number` positivo opcional | sin límite | Presupuesto frontier por sesión. |
198
- | `budgets.monthlyUSD` | `number` positivo opcional | sin límite | Presupuesto frontier mensual. |
199
- | `budgets.frontierTokensPerSession` | `number` entero positivo opcional | sin límite | Límite de tokens frontier por sesión. |
200
- | `budgets.hardStopOnBudgetExhaustion` | `boolean` | `false` | Si es `true`, agotar presupuesto devuelve `blockFrontier`; si es `false`, fuerza local. |
201
- | `privacyMode` | `"forceLocalOnSensitive" \| "consentBeforeFrontier" \| "off"` | `"forceLocalOnSensitive"` | Política de privacidad para tareas sensibles. |
202
- | `telemetry.enabled` | `boolean` plugin option | `true` | Activa/desactiva escritura JSONL. |
203
- | `telemetry.path` | `string` plugin option | `.opencode/openteam-telemetry.jsonl` | Ruta del log `CostRecord` JSONL. |
204
-
205
- ## Uso
206
-
207
- En cada turno, openteam deriva señales del prompt (`promptChars`, `hasCode`, `privacySensitive`, `requiresTools` y override de modelo si existe), ejecuta `chooseModel` y asigna `output.message.model`.
208
-
209
- La orquestación Squad usa roles estáticos y subsesiones opencode:
210
-
211
- | Rol | Agent opencode | Tier base | Política |
212
- | --- | --- | --- | --- |
213
- | `rusty` | `architect` | `hard` | Arquitectura y decisiones de alto riesgo; frontier auto. |
214
- | `livingston` | `integration` | `moderate` | Integración TS/opencode; tool calling por defecto. |
215
- | `yen` | `local-runtime` | `moderate` | Runtimes locales; local-first con fallback frontier. |
216
- | `basher` | `routing-cost` | `moderate` | Router, coste y presupuesto; local-first. |
217
- | `scribe` | `scribe` | `trivial` | Documentación y resúmenes; local-first. |
218
- | `linus` | `tester` | `simple` | Tests y contratos; local-first con tools. |
219
-
220
- `runRoleTask` ejecuta una subsesión; `runRoleTasks` ejecuta varias con `batchID`. Los roles con `destructive` o `multiFileEdit` elevan el tier antes de elegir modelo.
221
-
222
- Para ver ahorro y decisiones, revisa el JSONL de telemetría. Campos clave: `promptHash`, `promptChars`, `tier`, `routeKind`, `selected`, `rationale`, `estimatedCostUSD`, `baselineCostUSD`, `estimatedSavingsUSD`, `budgetAction`, `tokensIn` y `tokensOut`.
223
-
224
- ## Ejemplos en Windows
225
-
226
- ### Ollama
227
-
228
- ```powershell
229
- ollama serve
230
- ollama pull qwen3:8b
231
- Invoke-RestMethod -Uri "http://localhost:11434/v1/models" -Method Get
232
- ```
233
-
234
- ### LM Studio
235
-
236
- 1. Abre LM Studio.
237
- 2. Carga un modelo compatible.
238
- 3. Activa el servidor local OpenAI-compatible en el puerto `1234`.
239
-
240
- ```powershell
241
- Invoke-RestMethod -Uri "http://localhost:1234/v1/models" -Method Get
242
- ```
243
-
244
- ### Foundry Local
245
-
246
- ```powershell
247
- foundry service status
248
- ```
249
-
250
- openteam extrae el puerto de la salida del CLI y normaliza el endpoint a `http://localhost:<PORT>/v1`.
251
-
252
- ### Telemetría
253
-
254
- ```powershell
255
- $telemetryPath = "C:\gitrepos\openteam\.opencode\openteam-telemetry.jsonl"
256
- Get-Content -Path $telemetryPath -Tail 5
257
- ```
258
-
259
- ### Verificación local
260
-
261
- ```powershell
262
- Set-Location -Path "C:\gitrepos\openteam"
263
- bun test
264
- bun run typecheck
265
- bun run lint
266
- bun run format:check
267
- # Cuando el empaquetado de Fase 4 exponga el script:
268
- bun run build
269
- ```
270
-
271
- ## Privacidad
272
-
273
- Con `privacyMode: "forceLocalOnSensitive"`, si `TaskSignals.privacySensitive` es `true`, `chooseModel` usa local y no permite fallback frontier. Si no hay local utilizable, la decisión conserva la ruta local y registra la razón en `rationale`.
274
-
275
- La telemetría usa `hashPrompt`, actualmente `fnv1a32:<hash>`, y no serializa el prompt completo.
276
-
277
- ## Calidad
278
-
279
- Gates no negociables:
280
-
281
- - `bun test`
282
- - Coverage global: líneas `>= 85%`, branches `>= 80%`.
283
- - Coverage de `src/router/**`: `100%` lines, branches, statements y functions.
284
- - `bun run typecheck`
285
- - `biome check .` o `bun run lint` + `bun run format:check`
286
- - Test de determinismo del router.
287
- - Tests de contrato si cambian hooks opencode, agents, comandos, providers o SDK.
288
-
289
- Estado actual de Fases 0-3: **202 tests verdes**.
290
-
291
- ## Compatibilidad
292
-
293
- Consulta [docs/compatibility.md](docs/compatibility.md). Resumen verificado el `2026-07-06`:
294
-
295
- | Superficie | Versión / contrato |
296
- | --- | --- |
297
- | openteam | `0.1.0` para Fase 4 npm + docs |
298
- | `@opencode-ai/plugin` | `1.17.13` |
299
- | `@opencode-ai/sdk` | `1.17.13` |
300
- | Hook de routing | `chat.message`; no `chat.params` para cambiar modelo |
301
- | Subsesiones | `client.session.create` + `client.session.prompt({ body: { model } })` |
302
-
303
- ## Roadmap
304
-
305
- | Fase | Estado | Entregables |
306
- | --- | --- | --- |
307
- | 0. Scaffold/PoC | Hecha | TS/Bun, plugin mínimo, hook `chat.message`. |
308
- | 1. Local registry + router heurístico | Hecha | Ollama/LM Studio/Foundry, probes y `chooseModel` determinista. |
309
- | 2. Clasificador + perfiles + presupuesto + telemetría | Hecha | Clasificador local, `ModelCapabilityProfile`, budgets y `CostRecord`. |
310
- | 3. Orquestación multiagente | Hecha | Coordinator, roles, child sessions y permisos. |
311
- | 4. Empaquetado npm + docs | En curso | Package exportable, README, ejemplos Windows y matriz de compatibilidad. |
312
-
313
- ## Licencia
314
-
315
- MIT. Consulta [LICENSE](LICENSE).
1
+ # openteam
2
+
3
+ **openteam — plugin de opencode con routing coste-consciente local-first, fallback FRONTIER cheapest-capable y orquestación multiagente tipo Squad.**
4
+
5
+ ## Tabla de contenidos
6
+
7
+ - [Qué es y por qué existe](#qué-es-y-por-qué-existe)
8
+ - [Características](#características)
9
+ - [Requisitos](#requisitos)
10
+ - [Instalación](#instalación)
11
+ - [Configuración](#configuración)
12
+ - [Uso](#uso)
13
+ - [Ejemplos en Windows](#ejemplos-en-windows)
14
+ - [Privacidad](#privacidad)
15
+ - [Calidad](#calidad)
16
+ - [Compatibilidad](#compatibilidad)
17
+ - [Roadmap](#roadmap)
18
+ - [Licencia](#licencia)
19
+
20
+ ## Qué es y por qué existe
21
+
22
+ openteam añade a opencode una capa de routing y orquestación para ahorrar tokens y coste frontier sin perder calidad ni privacidad. La estrategia por defecto es **local-first**: tareas triviales, resúmenes, documentación sencilla y diffs pequeños intentan usar runtimes locales; tareas de arquitectura, seguridad, refactors multiarchivo, tool calling crítico o debugging ambiguo escalan a **FRONTIER cheapest-capable**.
23
+
24
+ El router mantiene una garantía de privacidad: con `privacyMode: "forceLocalOnSensitive"`, una tarea marcada como `privacySensitive` no escala a frontier.
25
+
26
+ ## Características
27
+
28
+ - Routing por turno desde el hook `chat.message`, mutando `output.message.model` antes de que opencode persista el mensaje.
29
+ - Registro de runtimes locales OpenAI-compatible: Ollama, LM Studio y Foundry Local.
30
+ - Clasificador local JSON con fallback heurístico determinista.
31
+ - Perfiles de capacidad desde Models.dev, con cache y fallback curado cuando el catálogo no está disponible.
32
+ - Selección frontier **cheapest-capable** por coste blended `0.75 * inputUSD + 0.25 * outputUSD`.
33
+ - Presupuestos por sesión, mes y tokens frontier por sesión.
34
+ - Telemetría `CostRecord` JSONL hash-only: guarda `promptHash`, métricas de coste y decisión, nunca prompts crudos.
35
+ - Orquestación Squad con `runRoleTask` / `runRoleTasks`, subsesiones SDK y modelo explícito en `client.session.prompt({ body: { model } })`.
36
+ - Refresh de disponibilidad local al arrancar y en eventos `session.created` / `session.idle`.
37
+
38
+ ## Requisitos
39
+
40
+ - opencode compatible con `@opencode-ai/plugin` `1.17.13`.
41
+ - Bun `>=1.3` para desarrollo y tests.
42
+ - Runtimes locales opcionales:
43
+ - Ollama en `http://localhost:11434/v1`.
44
+ - LM Studio en `http://localhost:1234/v1`.
45
+ - Foundry Local con puerto dinámico descubierto por CLI en Windows.
46
+
47
+ ## Instalación
48
+
49
+ ### Opción A: paquete npm
50
+
51
+ El paquete se publica como `@jmanuelcorral/openteam`. opencode instala los plugins declarados en el array `plugin` de `opencode.json`; basta con referenciar el nombre del paquete:
52
+
53
+ ```jsonc
54
+ {
55
+ "$schema": "https://opencode.ai/config.json",
56
+ "model": "anthropic/claude-sonnet-4-5",
57
+ "small_model": "ollama/qwen3:8b",
58
+ "plugin": [
59
+ [
60
+ "@jmanuelcorral/openteam",
61
+ {
62
+ "baseline": {
63
+ "mode": "auto",
64
+ "pinnedModel": null,
65
+ "hardDefault": {
66
+ "providerID": "anthropic",
67
+ "modelID": "claude-sonnet-4-5"
68
+ }
69
+ },
70
+ "router": {
71
+ "mode": "balanced",
72
+ "localDefault": {
73
+ "providerID": "ollama",
74
+ "modelID": "qwen3:8b"
75
+ },
76
+ "trivialPromptMaxChars": 280,
77
+ "frontierPromptMinChars": 2000
78
+ },
79
+ "local": {
80
+ "runtimes": [
81
+ {
82
+ "id": "ollama",
83
+ "enabled": true,
84
+ "baseURL": "http://localhost:11434/v1",
85
+ "defaultModel": {
86
+ "providerID": "ollama",
87
+ "modelID": "qwen3:8b"
88
+ }
89
+ },
90
+ {
91
+ "id": "lmstudio",
92
+ "enabled": true,
93
+ "baseURL": "http://localhost:1234/v1",
94
+ "defaultModel": {
95
+ "providerID": "lmstudio",
96
+ "modelID": "qwen2.5-coder-local"
97
+ }
98
+ }
99
+ ]
100
+ },
101
+ "budgets": {
102
+ "sessionUSD": 2,
103
+ "monthlyUSD": 30,
104
+ "frontierTokensPerSession": 250000,
105
+ "hardStopOnBudgetExhaustion": false
106
+ },
107
+ "privacyMode": "forceLocalOnSensitive",
108
+ "telemetry": {
109
+ "enabled": true,
110
+ "path": ".opencode/openteam-telemetry.jsonl"
111
+ }
112
+ }
113
+ ]
114
+ ],
115
+ "provider": {
116
+ "ollama": {
117
+ "npm": "@ai-sdk/openai-compatible",
118
+ "name": "Ollama (local)",
119
+ "options": {
120
+ "baseURL": "http://localhost:11434/v1",
121
+ "apiKey": "ollama",
122
+ "chunkTimeout": 60000
123
+ },
124
+ "models": {
125
+ "qwen3:8b": {
126
+ "name": "Qwen3 8B (Ollama)",
127
+ "tool_call": true,
128
+ "limit": { "context": 32768, "output": 8192 }
129
+ }
130
+ }
131
+ },
132
+ "lmstudio": {
133
+ "npm": "@ai-sdk/openai-compatible",
134
+ "name": "LM Studio (local)",
135
+ "options": {
136
+ "baseURL": "http://localhost:1234/v1",
137
+ "apiKey": "lm-studio"
138
+ },
139
+ "models": {
140
+ "qwen2.5-coder-local": {
141
+ "name": "Qwen2.5 Coder Local",
142
+ "tool_call": true,
143
+ "limit": { "context": 32768, "output": 8192 }
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ ### Opción B: ruta de desarrollo
152
+
153
+ Durante desarrollo puedes cargar un plugin local desde `.opencode/plugins/openteam.ts`:
154
+
155
+ ```jsonc
156
+ {
157
+ "$schema": "https://opencode.ai/config.json",
158
+ "plugin": [
159
+ [
160
+ "./.opencode/plugins/openteam.ts",
161
+ {
162
+ "router": {
163
+ "mode": "balanced",
164
+ "localDefault": {
165
+ "providerID": "ollama",
166
+ "modelID": "qwen3:8b"
167
+ }
168
+ },
169
+ "telemetry": {
170
+ "path": ".opencode/openteam-telemetry.jsonl"
171
+ }
172
+ }
173
+ ]
174
+ ]
175
+ }
176
+ ```
177
+
178
+ ## Configuración
179
+
180
+ La configuración runtime canónica vive en `.opencode/openteam.json`; este repositorio incluye `.opencode/openteam.example.json` como ejemplo completo. La forma validada por Zod es la de `src/config/schema.ts`. `telemetry` es una opción del plugin leída por `src/index.ts`, no parte del objeto `OpenTeamConfig` persistido.
181
+
182
+ | Key | Tipo | Default | Descripción |
183
+ | --- | --- | --- | --- |
184
+ | `baseline.mode` | `"auto" \| "pinned"` | `"auto"` | En `auto`, usa perfiles frontier cheapest-capable cuando se pasan al router; en `pinned`, usa `baseline.pinnedModel` si existe. |
185
+ | `baseline.pinnedModel` | `ModelRef \| null` | `null` | Modelo frontier fijado explícitamente. `ModelRef` usa `{ "providerID": string, "modelID": string }`. |
186
+ | `baseline.hardDefault` | `ModelRef` | `{ "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }` | Fallback frontier si no hay perfiles cheapest-capable o pin válido. |
187
+ | `router.mode` | `"economy" \| "balanced" \| "quality"` | `"balanced"` | Modo de routing validado y reservado para política. |
188
+ | `router.localDefault` | `ModelRef` | `{ "providerID": "ollama", "modelID": "qwen3:8b" }` | Modelo local principal. |
189
+ | `router.trivialPromptMaxChars` | `number` entero positivo | `280` | Prompts sin código hasta este tamaño prefieren local. |
190
+ | `router.frontierPromptMinChars` | `number` entero positivo | `2000` | Prompts desde este tamaño se tratan como candidatos a frontier si no aplican guards. |
191
+ | `local.runtimes` | `LocalRuntime[]` | Ollama enabled en `http://localhost:11434/v1` con `qwen3:8b` | Lista mínima de un runtime local. |
192
+ | `local.runtimes[].id` | `"ollama" \| "lmstudio" \| "foundry-local"` | requerido | Runtime local. |
193
+ | `local.runtimes[].enabled` | `boolean` | `true` | Habilita o deshabilita ese runtime. |
194
+ | `local.runtimes[].baseURL` | URL opcional | según runtime/config | Endpoint OpenAI-compatible `/v1`; Foundry Local puede omitirlo si usa discovery. |
195
+ | `local.runtimes[].discovery` | `"cli" \| "sdk" \| "manual"` opcional | sin default por item | Discovery de Foundry Local; el registry usa CLI si está configurado y no es `manual`. |
196
+ | `local.runtimes[].defaultModel` | `ModelRef` | requerido | Modelo por defecto de ese runtime. |
197
+ | `budgets.sessionUSD` | `number` positivo opcional | sin límite | Presupuesto frontier por sesión. |
198
+ | `budgets.monthlyUSD` | `number` positivo opcional | sin límite | Presupuesto frontier mensual. |
199
+ | `budgets.frontierTokensPerSession` | `number` entero positivo opcional | sin límite | Límite de tokens frontier por sesión. |
200
+ | `budgets.hardStopOnBudgetExhaustion` | `boolean` | `false` | Si es `true`, agotar presupuesto devuelve `blockFrontier`; si es `false`, fuerza local. |
201
+ | `privacyMode` | `"forceLocalOnSensitive" \| "consentBeforeFrontier" \| "off"` | `"forceLocalOnSensitive"` | Política de privacidad para tareas sensibles. |
202
+ | `telemetry.enabled` | `boolean` plugin option | `true` | Activa/desactiva escritura JSONL. |
203
+ | `telemetry.path` | `string` plugin option | `.opencode/openteam-telemetry.jsonl` | Ruta del log `CostRecord` JSONL. |
204
+
205
+ ## Uso
206
+
207
+ En cada turno, openteam deriva señales del prompt (`promptChars`, `hasCode`, `privacySensitive`, `requiresTools` y override de modelo si existe), ejecuta `chooseModel` y asigna `output.message.model`.
208
+
209
+ La orquestación Squad usa roles estáticos y subsesiones opencode:
210
+
211
+ | Rol | Agent opencode | Tier base | Política |
212
+ | --- | --- | --- | --- |
213
+ | `rusty` | `architect` | `hard` | Arquitectura y decisiones de alto riesgo; frontier auto. |
214
+ | `livingston` | `integration` | `moderate` | Integración TS/opencode; tool calling por defecto. |
215
+ | `yen` | `local-runtime` | `moderate` | Runtimes locales; local-first con fallback frontier. |
216
+ | `basher` | `routing-cost` | `moderate` | Router, coste y presupuesto; local-first. |
217
+ | `scribe` | `scribe` | `trivial` | Documentación y resúmenes; local-first. |
218
+ | `linus` | `tester` | `simple` | Tests y contratos; local-first con tools. |
219
+
220
+ `runRoleTask` ejecuta una subsesión; `runRoleTasks` ejecuta varias con `batchID`. Los roles con `destructive` o `multiFileEdit` elevan el tier antes de elegir modelo.
221
+
222
+ Para ver ahorro y decisiones, revisa el JSONL de telemetría. Campos clave: `promptHash`, `promptChars`, `tier`, `routeKind`, `selected`, `rationale`, `estimatedCostUSD`, `baselineCostUSD`, `estimatedSavingsUSD`, `budgetAction`, `tokensIn` y `tokensOut`.
223
+
224
+ ## Comandos runtime
225
+
226
+ openteam expone comandos para inspeccionar y cambiar el routing sin editar JSON a mano. Hay tres superficies equivalentes:
227
+
228
+ ### 1. Tool en la conversación
229
+
230
+ El plugin registra la herramienta `openteam`. Pídele al agente que la use, o instala el comando `/openteam` (ver más abajo). Acciones:
231
+
232
+ - `show` — muestra el baseline efectivo.
233
+ - `set` (con `model` en formato `provider/model`) — fija el baseline (modo `pinned`).
234
+ - `auto` — vuelve a cheapest-capable (modo `auto`).
235
+ - `doctor` — diagnóstico de runtimes locales, privacidad y telemetría.
236
+ - `report` resumen de coste y ahorro desde la telemetría.
237
+
238
+ Los cambios de `set`/`auto` se persisten en `.opencode/openteam.json` y aplican en el siguiente arranque del plugin.
239
+
240
+ ### 2. Slash command `/openteam`
241
+
242
+ Copia [`.opencode/command/openteam.md`](.opencode/command/openteam.md) a tu proyecto (o a `~/.config/opencode/command/`). Después:
243
+
244
+ ```text
245
+ /openteam baseline show
246
+ /openteam baseline set anthropic/claude-sonnet-4-5
247
+ /openteam baseline auto
248
+ /openteam doctor
249
+ /openteam report
250
+ ```
251
+
252
+ ### 3. CLI (`bin`)
253
+
254
+ El paquete expone el binario `openteam`. Con instalación global:
255
+
256
+ ```powershell
257
+ npm i -g @jmanuelcorral/openteam
258
+ openteam baseline show
259
+ openteam baseline set openai/gpt-5-mini
260
+ openteam doctor --config .opencode/openteam.json
261
+ openteam report --telemetry .opencode/openteam-telemetry.jsonl
262
+ ```
263
+
264
+ Flags: `--config <path>` y `--telemetry <path>` sobrescriben las rutas por defecto.
265
+
266
+ ## Ejemplos en Windows
267
+
268
+ ### Ollama
269
+
270
+ ```powershell
271
+ ollama serve
272
+ ollama pull qwen3:8b
273
+ Invoke-RestMethod -Uri "http://localhost:11434/v1/models" -Method Get
274
+ ```
275
+
276
+ ### LM Studio
277
+
278
+ 1. Abre LM Studio.
279
+ 2. Carga un modelo compatible.
280
+ 3. Activa el servidor local OpenAI-compatible en el puerto `1234`.
281
+
282
+ ```powershell
283
+ Invoke-RestMethod -Uri "http://localhost:1234/v1/models" -Method Get
284
+ ```
285
+
286
+ ### Foundry Local
287
+
288
+ ```powershell
289
+ foundry service status
290
+ ```
291
+
292
+ openteam extrae el puerto de la salida del CLI y normaliza el endpoint a `http://localhost:<PORT>/v1`.
293
+
294
+ ### Telemetría
295
+
296
+ ```powershell
297
+ $telemetryPath = "C:\gitrepos\openteam\.opencode\openteam-telemetry.jsonl"
298
+ Get-Content -Path $telemetryPath -Tail 5
299
+ ```
300
+
301
+ ### Verificación local
302
+
303
+ ```powershell
304
+ Set-Location -Path "C:\gitrepos\openteam"
305
+ bun test
306
+ bun run typecheck
307
+ bun run lint
308
+ bun run format:check
309
+ # Cuando el empaquetado de Fase 4 exponga el script:
310
+ bun run build
311
+ ```
312
+
313
+ ## Privacidad
314
+
315
+ Con `privacyMode: "forceLocalOnSensitive"`, si `TaskSignals.privacySensitive` es `true`, `chooseModel` usa local y no permite fallback frontier. Si no hay local utilizable, la decisión conserva la ruta local y registra la razón en `rationale`.
316
+
317
+ La telemetría usa `hashPrompt`, actualmente `fnv1a32:<hash>`, y no serializa el prompt completo.
318
+
319
+ ## Calidad
320
+
321
+ Gates no negociables:
322
+
323
+ - `bun test`
324
+ - Coverage global: líneas `>= 85%`, branches `>= 80%`.
325
+ - Coverage de `src/router/**`: `100%` lines, branches, statements y functions.
326
+ - `bun run typecheck`
327
+ - `biome check .` o `bun run lint` + `bun run format:check`
328
+ - Test de determinismo del router.
329
+ - Tests de contrato si cambian hooks opencode, agents, comandos, providers o SDK.
330
+
331
+ Estado actual de Fases 0-3: **202 tests verdes**.
332
+
333
+ ## Compatibilidad
334
+
335
+ Consulta [docs/compatibility.md](docs/compatibility.md). Resumen verificado el `2026-07-06`:
336
+
337
+ | Superficie | Versión / contrato |
338
+ | --- | --- |
339
+ | openteam | `0.1.0` para Fase 4 npm + docs |
340
+ | `@opencode-ai/plugin` | `1.17.13` |
341
+ | `@opencode-ai/sdk` | `1.17.13` |
342
+ | Hook de routing | `chat.message`; no `chat.params` para cambiar modelo |
343
+ | Subsesiones | `client.session.create` + `client.session.prompt({ body: { model } })` |
344
+
345
+ ## Roadmap
346
+
347
+ | Fase | Estado | Entregables |
348
+ | --- | --- | --- |
349
+ | 0. Scaffold/PoC | Hecha | TS/Bun, plugin mínimo, hook `chat.message`. |
350
+ | 1. Local registry + router heurístico | Hecha | Ollama/LM Studio/Foundry, probes y `chooseModel` determinista. |
351
+ | 2. Clasificador + perfiles + presupuesto + telemetría | Hecha | Clasificador local, `ModelCapabilityProfile`, budgets y `CostRecord`. |
352
+ | 3. Orquestación multiagente | Hecha | Coordinator, roles, child sessions y permisos. |
353
+ | 4. Empaquetado npm + docs | Hecha | Package exportable, README, ejemplos Windows y matriz de compatibilidad. |
354
+ | 5. Comandos runtime | Hecha | `baseline show/set/auto`, `doctor` y `report` vía tool, `/openteam` y CLI `bin`. |
355
+
356
+ ## Licencia
357
+
358
+ MIT. Consulta [LICENSE](LICENSE).