@jmanuelcorral/openteam 0.18.0 → 0.19.0

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 (113) hide show
  1. package/.opencode/openteam.example.json +23 -14
  2. package/AGENTS.md +16 -2
  3. package/README.es.md +291 -208
  4. package/README.md +292 -138
  5. package/dist/capabilities/classify.d.ts.map +1 -1
  6. package/dist/capabilities/normalize.d.ts.map +1 -1
  7. package/dist/certificates/graph-release-certificate.json +2 -2
  8. package/dist/certificates/graph-shadow-certificate.json +2 -2
  9. package/dist/cli.js +1354 -594
  10. package/dist/commands/agents.d.ts +16 -4
  11. package/dist/commands/agents.d.ts.map +1 -1
  12. package/dist/commands/dispatch.d.ts.map +1 -1
  13. package/dist/commands/doctor.d.ts.map +1 -1
  14. package/dist/commands/local.d.ts +4 -5
  15. package/dist/commands/local.d.ts.map +1 -1
  16. package/dist/commands/report.d.ts +6 -6
  17. package/dist/commands/report.d.ts.map +1 -1
  18. package/dist/commands/rolesInit.d.ts +10 -12
  19. package/dist/commands/rolesInit.d.ts.map +1 -1
  20. package/dist/commands/setup.d.ts +5 -13
  21. package/dist/commands/setup.d.ts.map +1 -1
  22. package/dist/commands/yolo.d.ts +2 -4
  23. package/dist/commands/yolo.d.ts.map +1 -1
  24. package/dist/config/errors.d.ts.map +1 -1
  25. package/dist/config/executionPolicyDomains.d.ts +18 -0
  26. package/dist/config/executionPolicyDomains.d.ts.map +1 -0
  27. package/dist/config/migrations.d.ts +9 -2
  28. package/dist/config/migrations.d.ts.map +1 -1
  29. package/dist/config/persist.d.ts.map +1 -1
  30. package/dist/config/runtime.d.ts +2 -0
  31. package/dist/config/runtime.d.ts.map +1 -1
  32. package/dist/config/schema.d.ts +97 -12
  33. package/dist/config/schema.d.ts.map +1 -1
  34. package/dist/console/configView.d.ts +2 -7
  35. package/dist/console/configView.d.ts.map +1 -1
  36. package/dist/console/render.d.ts.map +1 -1
  37. package/dist/console/types.d.ts +2 -2
  38. package/dist/console/types.d.ts.map +1 -1
  39. package/dist/context/schema.d.ts +13 -7
  40. package/dist/context/schema.d.ts.map +1 -1
  41. package/dist/graph/certificate.d.ts.map +1 -1
  42. package/dist/graph/langgraph/adapter.d.ts +7 -8
  43. package/dist/graph/langgraph/adapter.d.ts.map +1 -1
  44. package/dist/graph/langgraph/certification.d.ts +5 -0
  45. package/dist/graph/langgraph/certification.d.ts.map +1 -1
  46. package/dist/graph/langgraph/checkpointReplay.d.ts.map +1 -1
  47. package/dist/graph/langgraph/engine.d.ts +2 -2
  48. package/dist/graph/langgraph/engine.d.ts.map +1 -1
  49. package/dist/graph/langgraph/types.d.ts +11 -6
  50. package/dist/graph/langgraph/types.d.ts.map +1 -1
  51. package/dist/graph/privacyPolicy.d.ts +6 -30
  52. package/dist/graph/privacyPolicy.d.ts.map +1 -1
  53. package/dist/index.d.ts +1 -9
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +3164 -1102
  56. package/dist/mcp/teamMemory.d.ts +2 -2
  57. package/dist/mcp/teamMemory.d.ts.map +1 -1
  58. package/dist/messages/commands.d.ts +22 -35
  59. package/dist/messages/commands.d.ts.map +1 -1
  60. package/dist/messages/executionSetup.d.ts +116 -0
  61. package/dist/messages/executionSetup.d.ts.map +1 -0
  62. package/dist/messages/index.d.ts +1 -0
  63. package/dist/messages/index.d.ts.map +1 -1
  64. package/dist/messages/memoryTool.d.ts +17 -0
  65. package/dist/messages/memoryTool.d.ts.map +1 -0
  66. package/dist/messages/orchestration.d.ts +16 -0
  67. package/dist/messages/orchestration.d.ts.map +1 -0
  68. package/dist/messages/routing.d.ts +9 -0
  69. package/dist/messages/routing.d.ts.map +1 -0
  70. package/dist/opencodeArtifacts/orchestratorAgent.d.ts +3 -5
  71. package/dist/opencodeArtifacts/orchestratorAgent.d.ts.map +1 -1
  72. package/dist/orchestrator/coordinator.d.ts +28 -9
  73. package/dist/orchestrator/coordinator.d.ts.map +1 -1
  74. package/dist/orchestrator/graphEffects.d.ts +10 -11
  75. package/dist/orchestrator/graphEffects.d.ts.map +1 -1
  76. package/dist/orchestrator/outputContract.d.ts +25 -0
  77. package/dist/orchestrator/outputContract.d.ts.map +1 -1
  78. package/dist/orchestrator/roles.d.ts +25 -2
  79. package/dist/orchestrator/roles.d.ts.map +1 -1
  80. package/dist/orchestrator/runtimeSelection.d.ts.map +1 -1
  81. package/dist/orchestrator/subsessions.d.ts +49 -1
  82. package/dist/orchestrator/subsessions.d.ts.map +1 -1
  83. package/dist/plugin/availability.d.ts +15 -2
  84. package/dist/plugin/availability.d.ts.map +1 -1
  85. package/dist/plugin/diagnostics.d.ts +1 -0
  86. package/dist/plugin/diagnostics.d.ts.map +1 -1
  87. package/dist/plugin/hooks.d.ts +21 -2
  88. package/dist/plugin/hooks.d.ts.map +1 -1
  89. package/dist/plugin/memoryTool.d.ts +3 -3
  90. package/dist/plugin/memoryTool.d.ts.map +1 -1
  91. package/dist/plugin/modelOwnership.d.ts +15 -0
  92. package/dist/plugin/modelOwnership.d.ts.map +1 -0
  93. package/dist/plugin/orchestrateTool.d.ts +68 -3
  94. package/dist/plugin/orchestrateTool.d.ts.map +1 -1
  95. package/dist/router/chooseModel.d.ts.map +1 -1
  96. package/dist/router/cost.d.ts +1 -1
  97. package/dist/router/cost.d.ts.map +1 -1
  98. package/dist/router/executionPolicy.d.ts +44 -0
  99. package/dist/router/executionPolicy.d.ts.map +1 -0
  100. package/dist/router/frontierBaseline.d.ts.map +1 -1
  101. package/dist/router/types.d.ts +10 -4
  102. package/dist/router/types.d.ts.map +1 -1
  103. package/dist/telemetry/aggregate.d.ts +4 -4
  104. package/dist/telemetry/aggregate.d.ts.map +1 -1
  105. package/dist/telemetry/diagnostics.d.ts +1 -1
  106. package/dist/telemetry/diagnostics.d.ts.map +1 -1
  107. package/dist/telemetry/events.d.ts +20 -6
  108. package/dist/telemetry/events.d.ts.map +1 -1
  109. package/dist/telemetry/otel.d.ts.map +1 -1
  110. package/dist/telemetry/types.d.ts +3 -3
  111. package/dist/web/configApi.d.ts +3 -1
  112. package/dist/web/configApi.d.ts.map +1 -1
  113. package/package.json +1 -1
package/README.es.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 🌐 **Language / Idioma:** [English](README.md) · **Español** (este documento)
4
4
 
5
- **openteam — plugin de opencode con routing coste-consciente local-first, fallback FRONTIER cheapest-capable y orquestación multiagente a demanda.**
5
+ **openteam — ejecución de modelos local, frontier y mixed controlada por el operador para opencode, con selección automática cheapest-capable y orquestación multiagente a demanda.**
6
6
 
7
7
  > 📖 **Sitio de documentación:** <https://jmanuelcorral.github.io/openteam/es/> (también en [English](https://jmanuelcorral.github.io/openteam/))
8
8
 
@@ -13,6 +13,7 @@
13
13
  - [Requisitos](#requisitos)
14
14
  - [Instalación](#instalación)
15
15
  - [Quickstart: `openteam setup`](#quickstart-openteam-setup)
16
+ - [El agente `openteam`](#el-agente-openteam)
16
17
  - [Probar en otra máquina](#probar-en-otra-máquina)
17
18
  - [Actualizar openteam](#actualizar-openteam)
18
19
  - [Configuración](#configuración)
@@ -28,20 +29,25 @@
28
29
 
29
30
  ## Qué es y por qué existe
30
31
 
31
- 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**.
32
+ openteam añade a opencode una capa de routing y orquestación. El operador elige
33
+ un dominio global **local**, **frontier** o **mixed**; las políticas del
34
+ coordinador y de los workers pueden fijar un modelo exacto o usar selección
35
+ `"auto"` cheapest-capable dentro de ese dominio.
32
36
 
33
- El router mantiene una garantía de privacidad: con `privacyMode: "forceLocalOnSensitive"`, una tarea marcada como `privacySensitive` no escala a frontier.
37
+ openteam **no** inspecciona el contenido del prompt para inferir sensibilidad
38
+ antes de una llamada frontier. Para prohibir frontier, usa `local` globalmente o
39
+ estrecha un agente a `local` bajo el modo global `mixed`.
34
40
 
35
41
  ## Características
36
42
 
37
43
  - Routing por turno desde el hook `chat.message`, mutando `output.message.model` antes de que opencode persista el mensaje.
38
44
  - Registro de runtimes locales OpenAI-compatible: Ollama, LM Studio, Lemonade Server y Foundry Local.
39
- - Clasificador local JSON con fallback heurístico determinista.
40
45
  - Perfiles de capacidad desde Models.dev, con cache y fallback curado cuando el catálogo no está disponible.
41
- - Selección frontier **cheapest-capable** por coste blended `0.75 * inputUSD + 0.25 * outputUSD`.
46
+ - Selección automática **cheapest-capable** por coste, disponibilidad, soporte de tools y contexto dentro del dominio permitido.
42
47
  - Presupuestos por sesión, mes y tokens frontier por sesión.
43
48
  - Telemetría `CostRecord` JSONL hash-only: guarda `promptHash`, métricas de coste y decisión, nunca prompts crudos.
44
- - Orquestación multiagente con `runRoleTask` / `runRoleTasks`, subsesiones SDK y modelo explícito en `client.session.prompt({ body: { model } })`.
49
+ - Pines exactos o `"auto"` por agente, fallbacks ordenados opcionales y relevo acotado de modelo para nodos incompletos.
50
+ - Orquestación multiagente con subsesiones SDK y modelo explícito en `client.session.prompt({ body: { model } })`.
45
51
  - Refresh de disponibilidad local al arrancar y en eventos `session.created` / `session.idle`.
46
52
 
47
53
  ## Requisitos
@@ -78,99 +84,16 @@ Para la carga directa desde opencode, basta con referenciar el paquete:
78
84
  "$schema": "https://opencode.ai/config.json",
79
85
  "model": "anthropic/claude-sonnet-4-5",
80
86
  "small_model": "ollama/qwen3:8b",
81
- "plugin": [
82
- [
83
- "@jmanuelcorral/openteam",
84
- {
85
- "baseline": {
86
- "mode": "auto",
87
- "pinnedModel": null,
88
- "hardDefault": {
89
- "providerID": "anthropic",
90
- "modelID": "claude-sonnet-4-5"
91
- }
92
- },
93
- "router": {
94
- "mode": "balanced",
95
- "localDefault": {
96
- "providerID": "ollama",
97
- "modelID": "qwen3:8b"
98
- },
99
- "trivialPromptMaxChars": 280,
100
- "frontierPromptMinChars": 2000
101
- },
102
- "local": {
103
- "runtimes": [
104
- {
105
- "id": "ollama",
106
- "enabled": true,
107
- "baseURL": "http://localhost:11434/v1",
108
- "defaultModel": {
109
- "providerID": "ollama",
110
- "modelID": "qwen3:8b"
111
- }
112
- },
113
- {
114
- "id": "lmstudio",
115
- "enabled": true,
116
- "baseURL": "http://localhost:1234/v1",
117
- "defaultModel": {
118
- "providerID": "lmstudio",
119
- "modelID": "qwen2.5-coder-local"
120
- }
121
- }
122
- ]
123
- },
124
- "budgets": {
125
- "sessionUSD": 2,
126
- "monthlyUSD": 30,
127
- "frontierTokensPerSession": 250000,
128
- "hardStopOnBudgetExhaustion": false
129
- },
130
- "privacyMode": "forceLocalOnSensitive",
131
- "telemetry": {
132
- "enabled": true,
133
- "path": ".opencode/openteam-local/telemetry.jsonl"
134
- }
135
- }
136
- ]
137
- ],
138
- "provider": {
139
- "ollama": {
140
- "npm": "@ai-sdk/openai-compatible",
141
- "name": "Ollama (local)",
142
- "options": {
143
- "baseURL": "http://localhost:11434/v1",
144
- "apiKey": "ollama",
145
- "chunkTimeout": 60000
146
- },
147
- "models": {
148
- "qwen3:8b": {
149
- "name": "Qwen3 8B (Ollama)",
150
- "tool_call": true,
151
- "limit": { "context": 32768, "output": 8192 }
152
- }
153
- }
154
- },
155
- "lmstudio": {
156
- "npm": "@ai-sdk/openai-compatible",
157
- "name": "LM Studio (local)",
158
- "options": {
159
- "baseURL": "http://localhost:1234/v1",
160
- "apiKey": "lm-studio"
161
- },
162
- "models": {
163
- "qwen2.5-coder-local": {
164
- "name": "Qwen2.5 Coder Local",
165
- "tool_call": true,
166
- "limit": { "context": 32768, "output": 8192 }
167
- }
168
- }
169
- }
170
- }
87
+ "plugin": ["@jmanuelcorral/openteam"]
171
88
  }
172
89
  ```
173
90
 
91
+ Esos modelos deben existir en tus providers configurados en opencode;
92
+ sustitúyelos por equivalentes disponibles cuando sea necesario.
93
+
94
+ Mantén la política del operador en `.opencode/openteam.json`, no dentro de la
95
+ declaración del plugin. `openteam setup` crea ambos archivos.
96
+
174
97
  ### Opción B: ruta de desarrollo
175
98
 
176
99
  Durante desarrollo puedes cargar un plugin local desde `.opencode/plugins/openteam.ts`:
@@ -178,33 +101,29 @@ Durante desarrollo puedes cargar un plugin local desde `.opencode/plugins/opente
178
101
  ```jsonc
179
102
  {
180
103
  "$schema": "https://opencode.ai/config.json",
181
- "plugin": [
182
- [
183
- "./.opencode/plugins/openteam.ts",
184
- {
185
- "router": {
186
- "mode": "balanced",
187
- "localDefault": {
188
- "providerID": "ollama",
189
- "modelID": "qwen3:8b"
190
- }
191
- },
192
- "telemetry": {
193
- "path": ".opencode/openteam-local/telemetry.jsonl"
194
- }
195
- }
196
- ]
197
- ]
104
+ "plugin": ["./.opencode/plugins/openteam.ts"]
198
105
  }
199
106
  ```
200
107
 
201
- ## Quickstart: `openteam setup`
108
+ La carga por ruta de desarrollo no cambia el límite de configuración: conserva
109
+ la política del operador en `.opencode/openteam.json`.
202
110
 
203
- La forma más rápida de dejar un repositorio listo para opencode + openteam es el comando interactivo `openteam setup`. Detecta los runtimes locales instalados (Ollama, LM Studio, Lemonade Server, Foundry Local) —que son **opcionales**: puedes usar openteam **solo con frontier**, o apuntar a un Ollama/LM Studio/Lemonade Server que corra en **otra máquina de la red local**—, te deja elegir los modelos locales y el modelo **frontier baseline** (ordenados de más barato-capaz a más caro), y genera tres ficheros:
111
+ ## Quickstart: `openteam setup`
204
112
 
205
- - `opencode.json` en la raíz: declara el plugin `@jmanuelcorral/openteam`, los `provider` locales OpenAI-compatible, el `model` frontier y el `small_model` local.
206
- - `.opencode/openteam.json`: la configuración runtime validada de openteam (baseline, routing, runtimes locales, roles del orquestador y privacidad).
113
+ La forma más rápida de dejar un repositorio listo es `openteam setup`. Detecta
114
+ Ollama, LM Studio, Lemonade Server y Foundry Local —todos opcionales—, permite
115
+ elegir modelos locales y el **frontier baseline** (cheapest-capable primero), y
116
+ genera la configuración y los artefactos de agentes/comandos:
117
+
118
+ - `.opencode/opencode.json` en proyectos nuevos, o el
119
+ `.opencode/opencode.json` / `opencode.json` raíz ya existente: declara el
120
+ plugin, los providers locales, el `model` frontier y el `small_model` local.
121
+ - `.opencode/openteam.json`: la configuración runtime validada de openteam
122
+ (dominio, runtimes locales, políticas de modelo del primary/roles, presupuestos
123
+ y reintentos/relevos acotados).
207
124
  - `.opencode/agent/openteam.md`: el **agente primario `openteam`**, visible en el Tab-switcher.
125
+ - `.opencode/agent/<rol>.md` para los destinos estándar, además de entradas
126
+ `.opencode/command/*.md` y el `.opencode/.gitignore` local.
208
127
 
209
128
  ```powershell
210
129
  # Ejecución puntual, sin instalación global
@@ -217,25 +136,60 @@ openteam setup
217
136
 
218
137
  El asistente:
219
138
 
220
- 1. Sondea los runtimes locales y marca los detectados.
221
- 2. Te deja habilitar runtimes (o **ninguno**: puedes usar openteam **solo con modelos frontier**) y, por cada runtime que habilites, elegir si corre **en esta máquina** o **en otra máquina de la red local** (introduciendo su URL, p. ej. `http://192.168.1.50:11434/v1`); luego eliges el modelo por defecto de cada uno (o lo escribes si no se detectan modelos). Si tienes **más de una máquina del mismo tipo** (p. ej. dos hosts LM Studio), declara cada una como una instancia aparte con su propio id (`lmstudio-a`, `lmstudio-b`), URL y modelos. Para cada instancia también pregunta cuántos **slots de generación concurrente** tiene el runtime (por defecto `4`), para que puedas dejar un slot libre para el trabajo interactivo en vez de saturar el servidor.
222
- 3. Ofrece el modelo frontier baseline a partir del **catálogo completo de [Models.dev](https://models.dev)** que openteam ya integra: una lista rápida con los más **baratos-capaces primero** (incluidos los **gratuitos**, etiquetados como `gratis`), una opción **«Ver todos los modelos por proveedor…»** para navegar el catálogo completo, y **«Otro (custom)»** para escribir un `provider/model`. Si el catálogo no se puede cargar (offline), cae a la lista curada.
223
- 4. Pregunta el modo de routing (`balanced`/`economy`/`quality`), la política de privacidad y si quieres activar el **modo YOLO** (auto-aprobar permisos de opencode). Si no habilitas ningún runtime local, avisa de que estás en **modo solo frontier** y recomienda `consentBeforeFrontier` (porque `forceLocalOnSensitive` no tendría destino local).
224
- 5. Si ya existe `opencode.json` o `.opencode/openteam.json`, pide confirmación antes de sobrescribir.
225
-
226
- Tras `setup`, autentica el provider frontier (`opencode auth login`), asegúrate de que tu runtime local (en esta máquina o en la red) esté accesible si lo habilitaste, y abre opencode en el repositorio: openteam enruta local-first automáticamente. Puedes reajustar el baseline después con `openteam baseline set <provider/model>` o `openteam baseline auto`.
139
+ 1. Sondea runtimes locales y primero pregunta cuáles habilitar. Elegir
140
+ **Ninguno** selecciona global `frontier` directamente, sin una pregunta
141
+ redundante sobre los tres modos, y continúa con la selección frontier.
142
+ 2. Para cada runtime habilitado, configura esta máquina u otro host LAN,
143
+ modelos default/thinking/coder y concurrencia. Varias instancias conservan
144
+ identidades distintas de runtime y provider.
145
+ 3. Si hay algún runtime local, elige el modo del equipo (default `mixed`).
146
+ `local` fija el primario al modelo thinking o default del primer runtime;
147
+ `frontier` pide un modelo frontier; `mixed` pregunta si el primario usa ese
148
+ modelo local o el frontier elegido. Las opciones frontier usan el orden
149
+ cheapest-capable de Models.dev, exploración/custom y fallback curado offline.
150
+ 4. Setup escribe una política primaria exacta con `fallbacks: []`, persiste
151
+ cada worker como política parcial compacta `{ "model": "auto" }` y escribe
152
+ límites `2`/`2`. El schema/config manual permiten primary `"auto"` y
153
+ fallbacks primarios, pero setup no los pregunta.
154
+ 5. Elige si activar **YOLO**. Los archivos existentes requieren confirmación
155
+ antes de sobrescribir.
156
+
157
+ Tras `setup`, autentica un provider frontier si las políticas lo permiten,
158
+ comprueba cada runtime local configurado y abre opencode. Reajusta el baseline
159
+ con `openteam baseline set <provider/model>` o `openteam baseline auto`.
160
+
161
+ > **Nota de upgrade:** `privacyMode` es metadata obsoleta e ignorada y ya no impide ejecución
162
+ > frontier. Convierte cualquier restricción necesaria a
163
+ > `router.executionMode: "local"` o a un `executionMode: "local"` por agente
164
+ > bajo el modo global `mixed`.
227
165
 
228
166
  ## El agente `openteam`
229
167
 
230
- `openteam setup` genera un único **agente primario** llamado `openteam` (`.opencode/agent/openteam.md`). Pulsa **Tab** en opencode para seleccionarlo: así sabes explícitamente que estás en modo openteam, mientras el plugin sigue optimizando el modelo por debajo.
168
+ `openteam setup` genera un único **agente primario** llamado `openteam`
169
+ (`.opencode/agent/openteam.md`). Pulsa **Tab** en opencode para seleccionarlo:
170
+ así sabes explícitamente que estás en modo openteam. Su modelo sigue las
171
+ políticas global y del primario; el prompt no elige dominio por ser juzgado
172
+ sensible o complejo.
231
173
 
232
- Ese orquestador **no trae subagentes precreados**. En **cada petición** su primera acción es comprobar si ya existe equipo (`.opencode/openteam/roster.md` + subagentes en `.opencode/agent/`). Si **existe**, reparte el trabajo entre los especialistas adecuados; si **no existe**, entiende las tareas que implica tu petición, diseña el equipo mínimo y **lo crea a demanda** —sin que tengas que pedírselo explícitamente— antes de pasarle esas tareas (escribiendo `.opencode/agent/<nombre>.md` con `mode: subagent`), reutilizando los existentes antes de crear nuevos. Los roles mecánicos/bulk se dejan enrutar a modelos locales y solo se escala a frontier para arquitectura, seguridad o debugging ambiguo. (Este modelo de equipo temático creado a demanda está inspirado en [Squad](https://bradygaster.github.io/squad/); ver [Agradecimientos](#agradecimientos-e-inspiración).)
174
+ El frontmatter primario generado y `opencode.json.model` usan el mismo modelo
175
+ bootstrap exacto. Los workers generados omiten `model` en frontmatter: manda su
176
+ política en `.opencode/openteam.json`. Guardian, scribe y ralph no están
177
+ forzados a local por nombre.
178
+
179
+ Ese orquestador no trae subagentes específicos del proyecto precreados. En cada
180
+ petición comprueba el roster, reutiliza especialistas existentes y crea el equipo
181
+ mínimo a demanda cuando haga falta. La ubicación de modelos viene de las
182
+ políticas globales y por agente, no de clasificar sensibilidad. El router
183
+ unificado puede seguir derivando requisitos de capacidad y complejidad dentro
184
+ del dominio permitido.
233
185
 
234
186
  El equipo tiene **identidad temática**: el orquestador elige (o te pregunta) un **universo** y nombra a cada agente con un personaje de ese universo, registrando el reparto en `.opencode/openteam/roster.md` (fuera de `.opencode/agent/`, para que opencode no lo cargue como un agente fantasma) para que los nombres **persistan** entre sesiones. Además de los roles específicos del proyecto, contempla tres **roles estándar** creados a demanda:
235
187
 
236
- - **scribe** — memoria silenciosa: registra decisiones y aprendizajes en `.opencode/openteam/decisions.md` sin tocar el código (modelo local).
188
+ - **scribe** — memoria silenciosa: registra decisiones y aprendizajes en `.opencode/openteam/decisions.md` sin tocar el código.
237
189
  - **ralph** — automatización y triage: monitoriza el trabajo pendiente, lo prioriza, coordina la ejecución y **escala al humano** ante bloqueos o aprobaciones.
238
- - **guardian** — seguridad y privacidad: **detecta y enmascara datos sensibles** (PII, secretos, API keys, tokens) antes de que salgan a frontier y hace revisión de seguridad; corre siempre en local y respeta `forceLocalOnSensitive`.
190
+ - **guardian** — revisión de seguridad y consejo sobre política. No es un gate
191
+ automático previo a frontier y no tiene requisito local integrado. Configura
192
+ `executionMode: "local"` si debe quedarse local.
239
193
 
240
194
  Antes de delegar, el orquestador **planifica dependencias y paraleliza**: descompone la petición en tareas, y como opencode ejecuta en paralelo todas las llamadas `task` emitidas en un mismo turno (Vercel AI SDK), lanza a la vez las tareas independientes y secuencia por olas solo las que dependen de un resultado previo. El trabajo que colisiona sobre los mismos ficheros se separa en olas distintas para evitar conflictos.
241
195
 
@@ -273,7 +227,9 @@ Para instalar y probar openteam en otro equipo que ya tenga [opencode](https://o
273
227
 
274
228
  4. **Arranca tu runtime local** si lo habilitaste y no estaba activo (p. ej. `ollama serve`, o abre LM Studio / Foundry Local). Si apuntaste a un runtime en **otra máquina de la red**, asegúrate de que sea accesible desde este equipo (host expuesto y puerto abierto); para Ollama esto normalmente implica arrancarlo con `OLLAMA_HOST=0.0.0.0 ollama serve` en la máquina remota. Si configuraste **solo frontier**, sáltate este paso.
275
229
 
276
- 5. **Abre opencode en el repo**, pulsa **Tab** y elige el agente `openteam`. Dale el primer prompt: creará el equipo de subagentes a demanda y enrutará local-first automáticamente.
230
+ 5. **Abre opencode en el repo**, pulsa **Tab** y elige el agente `openteam`.
231
+ Dale el primer prompt: creará el equipo a demanda y ejecutará cada agente
232
+ dentro del dominio configurado.
277
233
 
278
234
  Comprueba el estado con `openteam doctor` (runtimes + config) y el ahorro con `openteam report`.
279
235
 
@@ -303,11 +259,19 @@ Notas al actualizar:
303
259
 
304
260
  ## Configuración
305
261
 
306
- 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.
262
+ La configuración runtime canónica vive en `.opencode/openteam.json`; este
263
+ repositorio incluye `.opencode/openteam.example.json` como ejemplo v2 mínimo y
264
+ completo, no como contrato byte-for-byte para todas las decisiones de setup.
265
+ La serialización canónica v2 es compacta: omite los valores default de las
266
+ heurísticas legacy, conserva overrides no-default para compatibilidad sin
267
+ política y compacta perfiles resueltos a políticas parciales respecto de su
268
+ baseline integrado o sintetizado. La forma validada por Zod es la de
269
+ `src/config/schema.ts`. `telemetry` es una opción del plugin leída por
270
+ `src/index.ts`, no parte del objeto `OpenTeamConfig` persistido.
307
271
 
308
272
  Los archivos de configuración son estrictos: las claves desconocidas fallan
309
273
  cerrado tanto en la CLI como en el plugin en vez de ignorarse en silencio. Los
310
- errores nombran cada ruta rechazada (por ejemplo `router.trivialPromptMxChars`)
274
+ errores nombran cada ruta rechazada (por ejemplo `router.executionMod`)
311
275
  e incluyen una sugerencia de la clave más cercana cuando existe.
312
276
  Esta validación estricta se aplica al archivo de configuración en ambas rutas;
313
277
  las opciones programáticas del plugin son una superficie separada y aún no se
@@ -358,13 +322,15 @@ ejecutas desde un subdirectorio verás "provider not configured" y debes hacer
358
322
 
359
323
  | Key | Tipo | Default | Descripción |
360
324
  | --- | --- | --- | --- |
325
+ | `configVersion` | `2`, input opcional | canónico `2` | Si falta, se trata como v1 y se migra. Un valor no entero o menor que `1` es desconocido; mayor que `2` no está soportado. |
361
326
  | `baseline.mode` | `"auto" \| "pinned"` | `"auto"` | En `auto`, usa perfiles frontier cheapest-capable cuando se pasan al router; en `pinned`, usa `baseline.pinnedModel` si existe. |
362
327
  | `baseline.pinnedModel` | `ModelRef \| null` | `null` | Modelo frontier fijado explícitamente. `ModelRef` usa `{ "providerID": string, "modelID": string }`. |
363
- | `baseline.hardDefault` | `ModelRef` | `{ "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }` | Fallback frontier si no hay perfiles cheapest-capable o pin válido. |
364
- | `router.mode` | `"economy" \| "balanced" \| "quality"` | `"balanced"` | Modo de routing validado y reservado para política. |
328
+ | `baseline.hardDefault` | `ModelRef` | `{ "providerID": "google", "modelID": "gemini-3.5-flash" }` | Fallback offline/de lista curada configurable cuando ningún perfil live o de catálogo utilizable guía la selección automática. No prevalece sobre los perfiles suministrados; `setup` puede escribir el frontier elegido y siguen permitidos los pins explícitos por agente. |
329
+ | `router.executionMode` | `"local" \| "frontier" \| "mixed"`, opcional | efectivo `"mixed"` | Límite duro global. La serialización canónica escribe `"mixed"` si falta. La política de agente puede estrechar `mixed`, nunca ampliar `local` o `frontier`. |
330
+ | `router.mode` | `"economy" \| "balanced" \| "quality"` | `"balanced"` | Ajuste canónico de heurística legacy para callers sin política de agente v2. No selecciona modelos por agente ni sobreescribe `executionMode` ni añade routing por sensibilidad. |
331
+ | `router.trivialPromptMaxChars` | entero positivo | `280` | Umbral legacy de routing mixed sin política. Se conserva para callers compatibles sin política de agente v2; las políticas v2 generadas no dependen de él. |
332
+ | `router.frontierPromptMinChars` | entero positivo | `2000` | Umbral legacy de routing mixed sin política. Se conserva para callers compatibles sin política de agente v2; las políticas v2 generadas no dependen de él. |
365
333
  | `router.localDefault` | `ModelRef \| null` | `null` | Modelo local principal. No configurado por defecto — ningún modelo local se enruta hasta que configures uno con `openteam setup` o manualmente. |
366
- | `router.trivialPromptMaxChars` | `number` entero positivo | `280` | Prompts sin código hasta este tamaño prefieren local. |
367
- | `router.frontierPromptMinChars` | `number` entero positivo | `2000` | Prompts desde este tamaño se tratan como candidatos a frontier si no aplican guards. |
368
334
  | `local.runtimes` | `LocalRuntime[]` | `[]` | Runtimes locales a sondear. Vacío por defecto — ningún runtime está configurado hasta que ejecutes `openteam setup` o añadas una entrada manualmente. |
369
335
  | `local.runtimes[].id` | `string` | requerido | Identidad de instancia, única dentro del array. Libre (`lmstudio-a`, `lemonade-lan`) para que dos máquinas del mismo tipo sean distintas; si se omite `kind`, debe ser en sí mismo un tipo de runtime (retrocompatibilidad). |
370
336
  | `local.runtimes[].kind` | `"ollama" \| "lmstudio" \| "foundry-local" \| "lemonade"` opcional | migra desde `id` | Tipo de runtime que selecciona el adaptador. Opcional: si falta, se usa `id` como tipo, así toda config previa sigue funcionando sin cambios. |
@@ -377,57 +343,121 @@ ejecutas desde un subdirectorio verás "provider not configured" y debes hacer
377
343
  | `budgets.sessionUSD` | `number` positivo opcional | sin límite | Presupuesto frontier por sesión. |
378
344
  | `budgets.monthlyUSD` | `number` positivo opcional | sin límite | Presupuesto frontier mensual. |
379
345
  | `budgets.frontierTokensPerSession` | `number` entero positivo opcional | sin límite | Límite de tokens frontier por sesión. |
380
- | `budgets.hardStopOnBudgetExhaustion` | `boolean` | `false` | Si es `true`, agotar presupuesto devuelve `blockFrontier`; si es `false`, fuerza local. |
381
- | `privacyMode` | `"forceLocalOnSensitive" \| "consentBeforeFrontier" \| "off"` | `"forceLocalOnSensitive"` | Política de privacidad para tareas sensibles. |
382
- | `orchestrator.roles` | `Record<string, AgentRoleProfile>` | `{}` | Perfiles de rol personalizados o sobrescritos, indexados por role ID. Las entradas de config se validan con el mismo schema estricto que los roles integrados y tienen prioridad sobre `TEAM_ROLES`; si una entrada omite `roleID`, se usa la clave del mapa. Los roles desconocidos no declarados aquí siguen usando el fallback neutral y avisan una vez. |
346
+ | `budgets.hardStopOnBudgetExhaustion` | `boolean` | `false` | Controla la acción de presupuesto; nunca permite salir del dominio. |
347
+ | `orchestrator` | objeto opcional | ausente | Contiene políticas de primary/roles y límites de pasadas. |
348
+ | `orchestrator.maxRetries` | entero no negativo opcional | efectivo `2` | Límite superior de pasadas openteam extra por modelo autorizado; `2` efectivo permite hasta tres pasadas. El default se aplica en runtime, no se materializa en el schema. |
349
+ | `orchestrator.maxModelsPerNode` | entero positivo opcional | efectivo `2` | Total de candidatos por nodo: el seleccionado más como máximo un fallback por defecto. El default de runtime no se materializa; combinado con reintentos permite como máximo seis intentos. |
350
+ | `orchestrator.primary` | `ExecutionPolicy` parcial opcional | ausente | Política del coordinador primario; todos sus campos son opcionales. |
351
+ | `orchestrator.roles` | `Record<string, AgentRoleProfile parcial>` raw | `{}` si existe `orchestrator` | Las entradas raw pueden ser parciales. Las cargadas quedan totalmente fusionadas y validadas: primero perfil integrado o, si no existe, sintetizado; después prevalece el override raw. |
383
352
  | `orchestrator.roles.<role>.opencodeAgent` | `string` no vacío opcional | role ID | Nombre del agente opencode al que se despacha ese rol. |
384
- | `orchestrator.roles.<role>.defaultTier` | `"trivial" \| "simple" \| "moderate" \| "hard"` | requerido | Tier base de complejidad antes de aplicar heurística y elevación por permisos. |
385
- | `orchestrator.roles.<role>.minReasoningTier` | `1`–`5` | requerido | Capacidad mínima de razonamiento para candidatos frontier. |
386
- | `orchestrator.roles.<role>.minCodeQualityTier` | `1`–`5` | requerido | Capacidad mínima de calidad de código para candidatos frontier. |
387
- | `orchestrator.roles.<role>.needsToolCallingByDefault` | `boolean` | requerido | Si el rol requiere tool calling salvo que la tarea indique otra cosa. |
388
- | `orchestrator.roles.<role>.preferredFrontierModels` | `Array<ModelRef \| "auto">` | requerido | Modelos frontier preferidos; usa `[]` para un rol local-first sin preferencia frontier explícita. |
389
- | `orchestrator.roles.<role>.localFirst` | `boolean` | requerido | Si el rol conserva la postura local-first normal en vez de forzar frontier para tareas hard. |
353
+ | `orchestrator.primary.executionMode` / `orchestrator.roles.<role>.executionMode` | `"local" \| "frontier" \| "mixed"`, opcional | heredado | Puede estrechar global `mixed`; no contradecir global `local`/`frontier`. |
354
+ | `orchestrator.primary.model` / `orchestrator.roles.<role>.model` | `ModelRef \| "auto"`, opcional | omitir equivale a `"auto"` | Selección exacta o automática determinista entre modelos capaces, disponibles y dentro del dominio. `mixed` prioriza local si es capaz y después cheapest-capable cuando existe coste de catálogo. Pins estáticamente no configurados, fuera del dominio o incapaces conocidos fallan; candidatos temporalmente offline se omiten solo en runtime. Un coste ausente no se inventa como cero. |
355
+ | `orchestrator.primary.fallbacks` / `orchestrator.roles.<role>.fallbacks` | `ModelRef[]`, opcional | derivados para auto; ninguno para pin exacto | Una lista explícita sustituye fallbacks derivados y conserva orden tras deduplicar y omitir el seleccionado. Cada entrada recibe validación estática de identidad/dominio/capacidad antes del límite. Un backup temporalmente offline no invalida un primary sano: se omite para probar el siguiente candidato autorizado. |
356
+ | `privacyMode` | legacy/obsoleto | ninguno | Solo metadata compatible ignorada; se elimina al persistir canónicamente. Al cargarla emite una vez el aviso de migración `privacy-mode-ignored` con el riesgo de egress frontier y el remedio `executionMode: "local"`; el aviso nunca cambia el routing. |
390
357
  | `telemetry.enabled` | `boolean` plugin option | `true` | Activa/desactiva escritura JSONL. |
391
358
  | `telemetry.path` | `string` plugin option | `.opencode/openteam-local/telemetry.jsonl` | Ruta del log `CostRecord` JSONL. |
392
359
 
393
- Ejemplo de auditor de privacidad/seguridad personalizado:
360
+ `router.localOnly` y `router.frontierOnly` siguen como aliases opcionales de
361
+ parseo para cargar archivos antiguos; la migración y las escrituras canónicas
362
+ los sustituyen por `executionMode`. `TaskSignals.privacySensitive?` también
363
+ sigue como campo histórico opcional, pero clasificación, score, rationale y
364
+ routing lo ignoran.
365
+
366
+ Ejemplo de políticas explícitas para coordinador y workers:
367
+
368
+ Los modelos exactos de política siempre son objetos como
369
+ `{ "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }`, nunca un
370
+ scalar `"provider/model"`. El comando baseline de slash/CLI y el campo `model`
371
+ propio de opencode sí usan la notación scalar. Cada modelo del ejemplo debe
372
+ existir en los providers configurados por el operador. Un ID de instancia como
373
+ `lmstudio-b` y un provider ID como `lmstudio` son conceptos distintos; usa la
374
+ identidad de provider configurada para opencode.
394
375
 
395
376
  ```jsonc
396
377
  {
378
+ "configVersion": 2,
379
+ "router": { "executionMode": "mixed" },
397
380
  "orchestrator": {
381
+ "maxRetries": 2,
382
+ "maxModelsPerNode": 2,
383
+ "primary": {
384
+ "executionMode": "frontier",
385
+ "model": "auto"
386
+ },
398
387
  "roles": {
399
- "galadriel": {
400
- "opencodeAgent": "galadriel",
401
- "defaultTier": "moderate",
402
- "minReasoningTier": 3,
403
- "minCodeQualityTier": 3,
404
- "needsToolCallingByDefault": true,
405
- "preferredFrontierModels": [],
406
- "localFirst": true
388
+ "scribe": {
389
+ "executionMode": "local",
390
+ "model": { "providerID": "ollama", "modelID": "qwen3:8b" }
391
+ },
392
+ "integration": {
393
+ "executionMode": "frontier",
394
+ "model": { "providerID": "anthropic", "modelID": "claude-sonnet-4-5" },
395
+ "fallbacks": [
396
+ { "providerID": "google", "modelID": "gemini-3.5-flash" }
397
+ ]
407
398
  }
408
399
  }
409
400
  }
410
401
  }
411
402
  ```
412
403
 
404
+ El `routeKind` resuelto siempre es `local`, `frontier` o `blocked`, nunca
405
+ `mixed`. Solo pueden ejecutarse el modelo seleccionado y la cadena de fallback
406
+ devuelta. Una decisión bloqueada no despacha; su identidad seleccionada es solo
407
+ un valor de coste/referencia. El estrechamiento por presupuesto no puede
408
+ sustituir un modelo local no aprobado: si no queda ningún candidato autorizado,
409
+ el routing bloquea.
410
+
413
411
  ## Uso
414
412
 
415
- 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`.
413
+ En cada turno, openteam resuelve las políticas global y por agente, filtra por
414
+ dominio, tools y contexto, ordena los candidatos `"auto"` por coste según los
415
+ requisitos de capacidad/complejidad del router unificado y asigna
416
+ `output.message.model`. La sensibilidad del prompt y los metadatos de privacidad
417
+ de Graph no son entradas de routing.
416
418
 
417
419
  La orquestación multiagente usa roles estáticos y subsesiones opencode:
418
420
 
419
- | Rol | Agent opencode | Tier base | Política |
420
- | --- | --- | --- | --- |
421
- | `rusty` | `architect` | `hard` | Arquitectura y decisiones de alto riesgo; frontier auto. |
422
- | `livingston` | `integration` | `moderate` | Integración TS/opencode; tool calling por defecto. |
423
- | `yen` | `local-runtime` | `moderate` | Runtimes locales; local-first con fallback frontier. |
424
- | `basher` | `routing-cost` | `moderate` | Router, coste y presupuesto; local-first. |
425
- | `scribe` | `scribe` | `trivial` | Documentación y resúmenes; local-first. |
426
- | `linus` | `tester` | `simple` | Tests y contratos; local-first con tools. |
421
+ En el trabajo del coordinador, `defaultTier` y los mínimos de capacidad del rol
422
+ son suelos. La clasificación ordinaria de capacidad/complejidad de la tarea
423
+ puede elevar el requisito efectivo para trabajo más difícil, pero no debilitar
424
+ el requisito del rol. El tier efectivo guía routing y telemetría. El vocabulario
425
+ de sensibilidad y la metadata de privacidad de Graph no afectan al routing.
427
426
 
428
- `runRoleTask` ejecuta una subsesión; `runRoleTasks` ejecuta varias con `batchID`. Los roles con `destructive` o `multiFileEdit` elevan el tier antes de elegir modelo.
429
-
430
- 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`.
427
+ | Rol | Agent opencode | Política típica |
428
+ | --- | --- | --- |
429
+ | `rusty` | `architect` | Configura `"auto"` o un modelo exacto del dominio. |
430
+ | `livingston` | `integration` | Suele necesitar tools; el dominio es explícito. |
431
+ | `yen` | `local-runtime` | Puede estrecharse a `local` bajo `mixed`. |
432
+ | `basher` | `routing-cost` | Auto puede optimizar coste dentro del dominio. |
433
+ | `scribe` | `scribe` | Sin restricción local integrada; configúrala si procede. |
434
+ | `linus` | `tester` | Configura modelos con tools/contexto suficientes. |
435
+
436
+ `runRoleTask` ejecuta una subsesión; `runRoleTasks` ejecuta varias con
437
+ `batchID`. Los intentos directos y en batch usan la misma ruta lógica estable
438
+ de reporte y deben probar un reporte actual, cambiado cuando proceda,
439
+ sustantivo y duradero antes del éxito. La política de permisos/review está
440
+ separada de la ubicación de modelo.
441
+
442
+ El dispatch SDK de un hijo usa una autorización de modelo de un solo uso y
443
+ acotada a la instancia del plugin, identificada por la sesión hija, el alias de
444
+ agente y el modelo exactos. Cuando el prompt del SDK público vuelve a entrar por
445
+ `chat.message`, solo esa coincidencia conserva el modelo worker autorizado por
446
+ el coordinador; la autorización se libera al terminar el prompt. Los mensajes
447
+ sin coincidencia y los iniciados por el usuario siguen el routing normal. Este
448
+ mecanismo no amplía dominios ni autoriza modelos fuera de `selected` y
449
+ `fallbackChain`.
450
+
451
+ Para consultar el modelo realmente usado, las razones del relevo y las
452
+ estimaciones de coste/ahorro cuando estén disponibles, revisa el JSONL de
453
+ telemetría. Los campos clave incluyen `promptHash`, `promptChars`, `routeKind`,
454
+ `selected`, `rationale`, `estimatedCostUSD`, `baselineCostUSD`,
455
+ `estimatedSavingsUSD`, `budgetAction`, `tokensIn` y `tokensOut`. Un coste de
456
+ modelo desconocido permanece `null`/desconocido, no se convierte en gratis; el
457
+ ahorro es desconocido si falta alguna estimación necesaria. En auto del
458
+ coordinador, el requisito efectivo de capacidad —el suelo del rol más cualquier
459
+ elevación por clasificación de la tarea— determina tanto la capacidad de los
460
+ candidatos como el baseline frontier capaz usado para comparar costes.
431
461
 
432
462
  ## Comandos runtime
433
463
 
@@ -440,8 +470,9 @@ El plugin registra la herramienta `openteam`. Pídele al agente que la use, o in
440
470
  - `show` — muestra el baseline efectivo.
441
471
  - `set` (con `model` en formato `provider/model`) — fija el baseline (modo `pinned`).
442
472
  - `auto` — vuelve a cheapest-capable (modo `auto`).
443
- - `doctor` — diagnóstico de runtimes locales, privacidad y telemetría.
444
- - `report` — resumen de coste y ahorro desde la telemetría.
473
+ - `doctor` — diagnóstico de dominio, política de modelos, runtimes y telemetría.
474
+ - `report` — estimaciones disponibles de coste y ahorro desde la telemetría;
475
+ los valores desconocidos siguen siendo desconocidos.
445
476
 
446
477
  Los cambios de `set`/`auto` se persisten en `.opencode/openteam.json` y aplican en el siguiente arranque del plugin.
447
478
 
@@ -468,7 +499,7 @@ El paquete expone el binario `openteam`. Con instalación global:
468
499
  ```powershell
469
500
  bun add --global @jmanuelcorral/openteam@latest
470
501
  openteam baseline show
471
- openteam baseline set openai/gpt-5-mini
502
+ openteam baseline set anthropic/claude-sonnet-4-5
472
503
  openteam doctor --config .opencode/openteam.json
473
504
  openteam agents
474
505
  openteam console
@@ -487,25 +518,10 @@ Flags: `--config <path>` y `--telemetry <path>` sobrescriben las rutas por defec
487
518
 
488
519
  ### Ver el LLM de cada agente: `openteam agents`
489
520
 
490
- Lista los agentes de `.opencode/agent/` indicando **qué LLM usa cada uno**: si es **local** (Ollama/LM Studio/Lemonade/Foundry, sin coste de tokens) o **frontier** (consume tu suscripción), y el **proveedor** (Anthropic, OpenAI, GitHub Copilot, Google…). Los agentes sin `model` propio **heredan** el default de `opencode.json` (que openteam enruta local-first por mensaje).
491
-
492
- ```powershell
493
- openteam agents
494
- ```
495
-
496
- ```text
497
- openteam agents — LLM por agente:
498
-
499
- ● openteam [primary ] frontier · Anthropic (consume tu suscripción) (anthropic/claude-sonnet-4-5)
500
- ○ basher [subagent] local · Ollama (sin coste de tokens) (ollama/qwen3:8b)
501
- ○ scribe [subagent] hereda default → frontier · Anthropic (consume tu suscripción) · openteam enruta local-first por mensaje
502
-
503
- Default de opencode.json: anthropic/claude-sonnet-4-5 (frontier · Anthropic)
504
- Leyenda: ● primary · ○ subagent · local = sin coste de tokens · frontier = consume tu suscripción.
505
- ```
506
-
507
- También está disponible **dentro de opencode**: pídele a openteam la lista de agentes y ejecutará la acción `agents` de su herramienta de comandos.
508
-
521
+ Lista los agentes de `.opencode/agent/` con su modelo y proveedor configurados.
522
+ Los agentes sin `model` propio heredan el default de `opencode.json`. Ese
523
+ default no autoriza salir del dominio resuelto: prevalecen las políticas
524
+ efectivas de `.opencode/openteam.json`.
509
525
 
510
526
  ### Modo YOLO (auto-aprobar permisos)
511
527
 
@@ -521,20 +537,30 @@ También puedes activarlo durante `openteam setup` (te lo pregunta), o al vuelo
521
537
 
522
538
  > **Importante: el permiso del agente anula al global.** opencode fusiona el permiso del frontmatter de cada agente **después** del global y gana la última regla que casa; por eso `openteam yolo on/off` regenera `.opencode/agent/openteam.md` para que su `permission` coincida con el estado YOLO. Sin esto, un `bash: ask`/`external_directory: deny` en el agente seguiría pidiendo confirmación aunque el global fuese `"*": allow`. Tras cambiar el modo, **reinicia o recarga opencode** para que los agentes tomen los nuevos permisos, y crea los subagentes con el mismo comodín cuando YOLO esté activo (el orquestador ya lo hace).
523
539
 
524
- > **YOLO no desactiva la privacidad de openteam.** Solo afecta a las aprobaciones de permisos de opencode; con `privacyMode: "forceLocalOnSensitive"`, los prompts sensibles siguen sin salir a frontier. Úsalo solo en entornos de confianza: auto-aprueba también `bash`, escrituras y accesos fuera del workspace (salvo reglas `deny` explícitas).
540
+ > **YOLO no cambia el dominio de ejecución.** Solo afecta a las aprobaciones de
541
+ > opencode y no añade un filtro de sensibilidad. En `frontier` o `mixed`, el
542
+ > contenido del prompt puede enviarse a frontier. Úsalo solo en entornos de
543
+ > confianza.
525
544
 
526
545
  ### Modo de routing: `openteam local`
527
546
 
528
547
  Usa `openteam local` para alternar entre los tres modos globales de routing sin repetir el setup:
529
548
 
530
549
  ```powershell
531
- openteam local status # ¿local-first, solo local o solo frontier? + runtimes configurados
532
- openteam local off # solo frontier (desactiva el routing local-first)
550
+ openteam local status # ¿mixed, local o frontier? + runtimes configurados
551
+ openteam local off # frontier
533
552
  openteam local only # solo local (nunca escala a frontier)
534
- openteam local on # vuelve al routing local-first
553
+ openteam local on # mixed
535
554
  ```
536
555
 
537
- `local off` persiste `router.frontierOnly=true`: el router escoge el **frontier cheapest-capable**, pero respeta privacidad, presupuestos y overrides explícitos por tarea. Los prompts sensibles con `forceLocalOnSensitive` no salen a frontier; `local off` degrada esa política a `consentBeforeFrontier` (imposible forzar local sin runtime) e informa del cambio. `local only` persiste `router.localOnly=true` y limpia `frontierOnly`; se niega a escribir la config salvo que haya al menos un runtime local habilitado.
556
+ Los comandos persisten `router.executionMode`. `local only` es un límite duro:
557
+ ningún pin o fallback de agente puede llegar a frontier, y el comando se rechaza
558
+ sin runtime local habilitado. `local off` no necesita runtime local. `local on`
559
+ permite ambos dominios y cada agente puede estrechar el suyo. Toda escritura
560
+ valida primero las políticas exactas de primary, roles y fallbacks contra el
561
+ dominio propuesto; un conflicto rechaza el comando y deja la config sin cambios.
562
+ También elimina `localOnly`, `frontierOnly` y `privacyMode` raíz; `local status`
563
+ muestra el modo efectivo y las identidades de runtimes habilitados.
538
564
 
539
565
  ### Actualizar el plugin y limpiar la caché: `openteam clear-cache`
540
566
 
@@ -565,7 +591,47 @@ de actualización paso a paso.
565
591
 
566
592
  ### Trabajo iterativo bajo `openteam-orchestrate` 🎯
567
593
 
568
- El trabajo desatendido y de tipo backlog se gestiona **enteramente desde la orquestación** — la iteración es una propiedad del grafo, no un comando aparte. Cuando el coordinador despacha un rol, ese nodo del grafo sigue trabajando en pasadas sucesivas hasta que declara `openteam-status: done` en su artefacto de reporte (el **contrato de salida**) o alcanza su tope de reintentos. El tope es configurable vía `orchestrator.maxRetries` en `.opencode/openteam.json`: cuenta reintentos, así que el valor por defecto `2` significa **tres pasadas por nodo** y `0` desactiva la iteración (una sola pasada). Un nodo que nunca declara completitud se vuelve a despachar hasta el tope en lugar de asumirse terminado, y un **gate de durabilidad** verifica en código que cada rol persistió realmente un reporte no vacío — así ninguna pasada descarta trabajo en silencio. La concurrencia por oleada y la cancelación por dependencias no cambian. Consulta **[docs/es/guide/commands.md](docs/es/guide/commands.md)** para el contrato completo.
594
+ El trabajo desatendido se gestiona desde la orquestación. El modelo actual
595
+ recibe `orchestrator.maxRetries` pasadas extra (default efectivo de runtime `2`,
596
+ tres pasadas como máximo por modelo). La incompletitud persistente consume el
597
+ presupuesto de pasadas del modelo antes de entregar el **mismo nodo** al
598
+ siguiente modelo autorizado. Un fallo retry-safe reconocido de
599
+ transporte/capacidad del prompt (`prompt-timeout`, `prompt-rate-limited`,
600
+ `prompt-connection`, `prompt-server` o `prompt-context-length`) se reintenta en
601
+ ese mismo modelo dentro de su presupuesto de pasadas; en create se reconocen
602
+ las mismas clases salvo context length. `maxRetries` es un límite superior, no
603
+ un mínimo obligatorio de repeticiones: tras confirmar la parada, un fallo de
604
+ transporte elegible puede consumir el presupuesto restante del mismo modelo o
605
+ entregar antes el nodo al siguiente candidato autorizado. Auth,
606
+ content-filter, validation/modelo inválido, rechazo genérico, session ID ausente
607
+ y fallos sin clasificar son terminales. Un candidato detectado como no
608
+ disponible antes del dispatch puede omitirse porque no empezó ningún intento.
609
+ `maxModelsPerNode` tiene
610
+ default efectivo de runtime `2`; juntos, ambos defaults limitan el nodo a hasta
611
+ seis pasadas openteam. Ninguno se materializa en el schema. No es una cuenta
612
+ garantizada de pasadas/llamadas HTTP ni una afirmación sobre reintentos internos
613
+ del SDK/provider.
614
+
615
+ El relevo conserva batch, objetivo, ruta de reporte y estado duradero. Un pin
616
+ exacto sin `fallbacks` no autoriza un segundo modelo. Cada pasada, incluso con
617
+ `maxRetries: 0`, necesita una declaración independiente
618
+ `openteam-status: done` y un reporte duradero con al menos 40 caracteres
619
+ sustantivos tras retirar las líneas de declaración reales. Gana la última
620
+ declaración independiente fuera de bloques de código; los ejemplos citados o
621
+ dentro de fences siguen siendo cuerpo y no declaran completitud. El marcador
622
+ solo no basta. El coordinador lee el texto únicamente para parsear ese estado y
623
+ comprobar sustancia; no copia el cuerpo a resultados de rol, telemetría de
624
+ routing, diagnósticos ni a la proyección solo-referencia.
625
+
626
+ Tras un dispatch de prompt con timeout o excepción/incertidumbre, la petición
627
+ SDK anterior debe terminar y la parada del servidor debe confirmarse antes de
628
+ cualquier reintento o relevo. Tras un abort correcto, el polling acotado
629
+ confirma la parada si la sesión exacta está `idle` o no aparece en un snapshot
630
+ de estado disperso válido; un payload ausente/malformado o una sesión que sigue
631
+ `busy`/`retry` bloquean la continuación. La evidencia de estado no sustituye la
632
+ terminación de la petición. Agotar la cadena termina en fallo/incompleto y no
633
+ ejecuta dependientes. Consulta
634
+ **[docs/es/guide/commands.md](docs/es/guide/commands.md)**.
569
635
 
570
636
  ### Console web multi-sesión (se lanza desde la CLI)
571
637
 
@@ -576,12 +642,11 @@ de opencode abiertas y todas aparecen en la **misma** Console, con una pestaña
576
642
  sesión (más "Todas"), porque cada plugin **escribe eventos redactados** en logs
577
643
  JSONL por sesión y la Console los vigila (`fs.watch`) y **agrega**.
578
644
 
579
- Muestra en vivo: **coste y tokens reales por mensaje** (input/output/reasoning/
580
- cache), **toolcalls con duración** y ok/fallo, ruteo reciente (coste/ahorro y
581
- modelo elegido, **solo hashes de prompt, nunca el texto**), **decisiones** de los
582
- agentes (scribe) y **reuniones** (batches multi-agente del orquestador), progreso
583
- de orquestación e iteración, el equipo de agentes (LLM local/frontier de cada uno) y
584
- últimos commits. Se actualiza por **SSE** (con *polling* de respaldo).
645
+ Muestra en vivo: **uso de tokens registrado y estimaciones de coste por
646
+ mensaje** (input/output/reasoning/cache), toolcalls con duración, routing
647
+ reciente, decisiones, reuniones, progreso, equipo y commits. Solo muestra hashes
648
+ de prompt, nunca el texto. Los límites y estimaciones son finitos y auditables,
649
+ pero no sustituyen la factura del provider. Se actualiza por **SSE**.
585
650
 
586
651
  Cada pestaña de sesión incluye además una **vista "Sesión"**: una consola por la
587
652
  que puedes **ver la salida en vivo** (SSE) y **enviar prompts** o **responder
@@ -635,8 +700,10 @@ stdio, sin dependencias) que expone la memoria del equipo agregada desde los
635
700
  eventos por sesión para que agentes/herramientas la consulten. Se apoya en el
636
701
  mismo `StorageProvider` que la Console y **nunca** expone prompts crudos, solo el
637
702
  estado ya redactado. Tools disponibles: `list_decisions` (filtrable por
638
- `agent`/`tag`), `list_meetings`, `list_sessions` y `cost_summary` (coste/tokens
639
- reales + ahorro estimado vs baseline all-frontier).
703
+ `agent`/`tag`), `list_meetings`, `list_sessions` y `cost_summary` (uso
704
+ registrado y estimaciones disponibles de coste/ahorro frente al baseline
705
+ all-frontier; los costes desconocidos siguen siendo desconocidos y no es una
706
+ factura).
640
707
 
641
708
  Regístralo en `opencode.json` como cualquier MCP server local:
642
709
 
@@ -651,6 +718,13 @@ Regístralo en `opencode.json` como cualquier MCP server local:
651
718
  }
652
719
  ```
653
720
 
721
+ La **tool de escritura `openteam-memory`** del plugin está separada de este
722
+ servidor MCP de solo lectura y de la política de modelo del rol scribe general.
723
+ Su transporte de extracción es explícitamente solo-local y exige un runtime
724
+ local configurado y alcanzable. El modo global `frontier` rechaza la llamada al
725
+ modelo de memoria; la tool no añade memoria frontier ni hace fallback
726
+ silencioso a frontier.
727
+
654
728
  #### Recall semántico (opt-in): `recall_facts`, `recall_preferences`, `similar_tasks`
655
729
 
656
730
  Además de la memoria de equipo, `openteam mcp` puede exponer **recall semántico**
@@ -803,17 +877,24 @@ GitHub Actions.
803
877
 
804
878
  ## Privacidad
805
879
 
806
- 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`.
880
+ openteam **no** detecta sensibilidad ni promete interceptar contenido antes de
881
+ una llamada frontier. `privacyMode` está obsoleto y no tiene autoridad de
882
+ routing. `frontier` y `mixed` permiten egress según la política configurada.
883
+ Para prohibirlo, usa `router.executionMode: "local"` globalmente o estrecha el
884
+ agente a `local` bajo `mixed`.
807
885
 
808
- La telemetría usa `hashPrompt`, actualmente `fnv1a32:<hash>`, y no serializa el prompt completo.
886
+ La redacción de credenciales, la telemetría con hash, el almacenamiento
887
+ solo-referencia, los controles de acceso y los límites finitos de
888
+ presupuesto/modelos/pasadas siguen vigentes. La telemetría usa `hashPrompt`,
889
+ actualmente `fnv1a32:<hash>`, y no serializa el prompt completo.
809
890
 
810
891
  ## Calidad
811
892
 
812
893
  Gates no negociables:
813
894
 
814
895
  - `bun test`
815
- - Coverage global: líneas `>= 85%`, branches `>= 80%`.
816
- - Coverage de `src/router/**`: `100%` lines, branches, statements y functions.
896
+ - Coverage global: líneas/funciones `>= 85%`.
897
+ - Coverage de `src/router/**`: `100%` líneas y funciones.
817
898
  - `bun run typecheck`
818
899
  - `biome check .` o `bun run lint` + `bun run format:check`
819
900
  - Test de determinismo del router.
@@ -825,7 +906,7 @@ Consulta [docs/compatibility.md](docs/compatibility.md). Resumen verificado el `
825
906
 
826
907
  | Superficie | Versión / contrato |
827
908
  | --- | --- |
828
- | openteam | `0.18.0`; versión actual del paquete |
909
+ | openteam | `0.19.0`; versión actual del paquete |
829
910
  | `@opencode-ai/plugin` | `1.18.19` |
830
911
  | `@opencode-ai/sdk` | `1.18.19` |
831
912
  | Hook de routing | `chat.message`; no `chat.params` para cambiar modelo |
@@ -840,11 +921,13 @@ Las contribuciones son bienvenidas. Lee [CONTRIBUTING.md](CONTRIBUTING.md) para
840
921
  | Fase | Estado | Entregables |
841
922
  | --- | --- | --- |
842
923
  | 0. Scaffold/PoC | Hecha | TS/Bun, plugin mínimo, hook `chat.message`. |
843
- | 1. Local registry + router heurístico | Hecha | Ollama/LM Studio/Lemonade/Foundry, probes y `chooseModel` determinista. |
844
- | 2. Clasificador + perfiles + presupuesto + telemetría | Hecha | Clasificador local, `ModelCapabilityProfile`, budgets y `CostRecord`. |
924
+ | 1. Local registry + router | Hecha | Ollama/LM Studio/Lemonade/Foundry, probes y `chooseModel` determinista. |
925
+ | 2. Perfiles + presupuesto + telemetría | Hecha | `ModelCapabilityProfile`, budgets y `CostRecord`. |
845
926
  | 3. Orquestación multiagente | Hecha | Coordinator, roles, child sessions y permisos. |
846
927
  | 4. Empaquetado npm + docs | Hecha | Package exportable, README, ejemplos Windows y matriz de compatibilidad. |
847
928
  | 5. Comandos runtime | Hecha | `baseline show/set/auto`, `doctor` y `report` vía tool, `/openteam` y CLI `bin`. |
929
+ | 6. Console web + memoria MCP | Hecha | Console multi-sesión solo-loopback, MCP de solo lectura y recall semántico opt-in. |
930
+ | MVP del agent stack | En curso | Config v2 con dominios, políticas por agente, relevo acotado, retirada del routing por sensibilidad y eliminación de la resolución duplicada de política dentro de Graph. El routing unificado por capacidad/complejidad permanece. La migración LangGraph sigue pendiente por separado. |
848
931
 
849
932
  ## Licencia
850
933