@jmanuelcorral/openteam 0.1.0 → 0.1.1
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/AGENTS.md +41 -41
- package/LICENSE +21 -21
- package/README.md +315 -315
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
# openteam — instrucciones para opencode
|
|
2
|
-
|
|
3
|
-
openteam es un plugin de opencode en **TypeScript + Bun** con routing **local-first** y fallback **FRONTIER cheapest-capable**. La meta es ahorrar coste/tokens frontier sin perder calidad, privacidad ni capacidad en tareas difíciles.
|
|
4
|
-
|
|
5
|
-
## Comandos de verificación
|
|
6
|
-
|
|
7
|
-
- Tests: `bun test`
|
|
8
|
-
- Typecheck: `bun run typecheck`
|
|
9
|
-
- Lint+format: `biome check .`
|
|
10
|
-
- Coverage requerido: global lines >= 85% y branches >= 80%; `src/router/**` al 100%.
|
|
11
|
-
- Determinismo: ejecutar el test específico de router cuando exista (`bun test tests/router/determinism.test.ts` o selector equivalente).
|
|
12
|
-
|
|
13
|
-
## Reglas de arquitectura
|
|
14
|
-
|
|
15
|
-
- Lee `docs/architecture.md`, `docs/testing-and-quality.md` y `PLAN.md` antes de cambios grandes.
|
|
16
|
-
- `router/` es puro: sin I/O, reloj, random, env vars ni logs.
|
|
17
|
-
- `plugin/` contiene hooks opencode; cualquier uso de superficie no documentada necesita test de contrato.
|
|
18
|
-
- `local/` aísla Ollama, LM Studio y Foundry Local.
|
|
19
|
-
- `config/` valida y persiste `.opencode/openteam.json`.
|
|
20
|
-
- `telemetry/` no guarda prompts completos; usa hash y metadatos redactados.
|
|
21
|
-
|
|
22
|
-
## Config y agentes opencode
|
|
23
|
-
|
|
24
|
-
- Config runtime canónica: `.opencode/openteam.json`.
|
|
25
|
-
- Reconciliación: `.openteam/config.json` queda obsoleto frente a la decisión de Rusty.
|
|
26
|
-
- Las definiciones Markdown de agents viven en `.opencode/agent/` en este repo. La documentación pública menciona `.opencode/agents/`; la investigación local verificó que el source soporta ambos.
|
|
27
|
-
- opencode lee este `AGENTS.md` como instrucciones de proyecto (verificado en docs/rules el 2026-07-06).
|
|
28
|
-
|
|
29
|
-
## Convenciones
|
|
30
|
-
|
|
31
|
-
- Documentación y prosa: español.
|
|
32
|
-
- Código, rutas, tipos e identificadores: English.
|
|
33
|
-
- TypeScript strict, ESM only, Zod en boundaries.
|
|
34
|
-
- Biome gobierna lint/format; no introduzcas ESLint/Prettier salvo decisión nueva.
|
|
35
|
-
|
|
36
|
-
## No negociables
|
|
37
|
-
|
|
38
|
-
- No merge sin tests, coverage, typecheck, lint/format y determinismo verdes.
|
|
39
|
-
- No enviar datos `privacySensitive` a frontier con `forceLocalOnSensitive`.
|
|
40
|
-
- No hardcodear un frontier premium como baseline: usar cheapest-capable configurable.
|
|
41
|
-
- No depender de runtimes locales reales, red o secretos en CI.
|
|
1
|
+
# openteam — instrucciones para opencode
|
|
2
|
+
|
|
3
|
+
openteam es un plugin de opencode en **TypeScript + Bun** con routing **local-first** y fallback **FRONTIER cheapest-capable**. La meta es ahorrar coste/tokens frontier sin perder calidad, privacidad ni capacidad en tareas difíciles.
|
|
4
|
+
|
|
5
|
+
## Comandos de verificación
|
|
6
|
+
|
|
7
|
+
- Tests: `bun test`
|
|
8
|
+
- Typecheck: `bun run typecheck`
|
|
9
|
+
- Lint+format: `biome check .`
|
|
10
|
+
- Coverage requerido: global lines >= 85% y branches >= 80%; `src/router/**` al 100%.
|
|
11
|
+
- Determinismo: ejecutar el test específico de router cuando exista (`bun test tests/router/determinism.test.ts` o selector equivalente).
|
|
12
|
+
|
|
13
|
+
## Reglas de arquitectura
|
|
14
|
+
|
|
15
|
+
- Lee `docs/architecture.md`, `docs/testing-and-quality.md` y `PLAN.md` antes de cambios grandes.
|
|
16
|
+
- `router/` es puro: sin I/O, reloj, random, env vars ni logs.
|
|
17
|
+
- `plugin/` contiene hooks opencode; cualquier uso de superficie no documentada necesita test de contrato.
|
|
18
|
+
- `local/` aísla Ollama, LM Studio y Foundry Local.
|
|
19
|
+
- `config/` valida y persiste `.opencode/openteam.json`.
|
|
20
|
+
- `telemetry/` no guarda prompts completos; usa hash y metadatos redactados.
|
|
21
|
+
|
|
22
|
+
## Config y agentes opencode
|
|
23
|
+
|
|
24
|
+
- Config runtime canónica: `.opencode/openteam.json`.
|
|
25
|
+
- Reconciliación: `.openteam/config.json` queda obsoleto frente a la decisión de Rusty.
|
|
26
|
+
- Las definiciones Markdown de agents viven en `.opencode/agent/` en este repo. La documentación pública menciona `.opencode/agents/`; la investigación local verificó que el source soporta ambos.
|
|
27
|
+
- opencode lee este `AGENTS.md` como instrucciones de proyecto (verificado en docs/rules el 2026-07-06).
|
|
28
|
+
|
|
29
|
+
## Convenciones
|
|
30
|
+
|
|
31
|
+
- Documentación y prosa: español.
|
|
32
|
+
- Código, rutas, tipos e identificadores: English.
|
|
33
|
+
- TypeScript strict, ESM only, Zod en boundaries.
|
|
34
|
+
- Biome gobierna lint/format; no introduzcas ESLint/Prettier salvo decisión nueva.
|
|
35
|
+
|
|
36
|
+
## No negociables
|
|
37
|
+
|
|
38
|
+
- No merge sin tests, coverage, typecheck, lint/format y determinismo verdes.
|
|
39
|
+
- No enviar datos `privacySensitive` a frontier con `forceLocalOnSensitive`.
|
|
40
|
+
- No hardcodear un frontier premium como baseline: usar cheapest-capable configurable.
|
|
41
|
+
- No depender de runtimes locales reales, red o secretos en CI.
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Jose Manuel Corral (@jmanuelcorral)
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jose Manuel Corral (@jmanuelcorral)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,315 +1,315 @@
|
|
|
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
|
+
## 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).
|