oficina-opencode 0.0.0-stage → 2.0.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 (117) hide show
  1. package/DESIGN.md +145 -0
  2. package/LICENSE +21 -0
  3. package/README.md +670 -2
  4. package/agents/oficina-architect.md +72 -0
  5. package/agents/oficina-commander.md +108 -0
  6. package/agents/oficina-critico.md +148 -0
  7. package/agents/oficina-director.md +160 -0
  8. package/agents/oficina-guardian.md +128 -0
  9. package/agents/oficina-integrator.md +98 -0
  10. package/agents/oficina-verificador.md +88 -0
  11. package/commands/oficina.md +36 -0
  12. package/dist/cli.d.ts +12 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +394 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/core/briefing.d.ts +115 -0
  17. package/dist/core/briefing.d.ts.map +1 -0
  18. package/dist/core/briefing.js +410 -0
  19. package/dist/core/briefing.js.map +1 -0
  20. package/dist/core/bus.d.ts +132 -0
  21. package/dist/core/bus.d.ts.map +1 -0
  22. package/dist/core/bus.js +250 -0
  23. package/dist/core/bus.js.map +1 -0
  24. package/dist/core/catalog.d.ts +303 -0
  25. package/dist/core/catalog.d.ts.map +1 -0
  26. package/dist/core/catalog.js +816 -0
  27. package/dist/core/catalog.js.map +1 -0
  28. package/dist/core/dispatch.d.ts +110 -0
  29. package/dist/core/dispatch.d.ts.map +1 -0
  30. package/dist/core/dispatch.js +301 -0
  31. package/dist/core/dispatch.js.map +1 -0
  32. package/dist/core/factory.d.ts +74 -0
  33. package/dist/core/factory.d.ts.map +1 -0
  34. package/dist/core/factory.js +243 -0
  35. package/dist/core/factory.js.map +1 -0
  36. package/dist/core/fsx.d.ts +39 -0
  37. package/dist/core/fsx.d.ts.map +1 -0
  38. package/dist/core/fsx.js +113 -0
  39. package/dist/core/fsx.js.map +1 -0
  40. package/dist/core/gates.d.ts +97 -0
  41. package/dist/core/gates.d.ts.map +1 -0
  42. package/dist/core/gates.js +467 -0
  43. package/dist/core/gates.js.map +1 -0
  44. package/dist/core/leases.d.ts +46 -0
  45. package/dist/core/leases.d.ts.map +1 -0
  46. package/dist/core/leases.js +94 -0
  47. package/dist/core/leases.js.map +1 -0
  48. package/dist/core/log.d.ts +30 -0
  49. package/dist/core/log.d.ts.map +1 -0
  50. package/dist/core/log.js +43 -0
  51. package/dist/core/log.js.map +1 -0
  52. package/dist/core/mesa.d.ts +82 -0
  53. package/dist/core/mesa.d.ts.map +1 -0
  54. package/dist/core/mesa.js +178 -0
  55. package/dist/core/mesa.js.map +1 -0
  56. package/dist/core/office.d.ts +208 -0
  57. package/dist/core/office.d.ts.map +1 -0
  58. package/dist/core/office.js +618 -0
  59. package/dist/core/office.js.map +1 -0
  60. package/dist/core/paths.d.ts +67 -0
  61. package/dist/core/paths.d.ts.map +1 -0
  62. package/dist/core/paths.js +136 -0
  63. package/dist/core/paths.js.map +1 -0
  64. package/dist/core/retry.d.ts +41 -0
  65. package/dist/core/retry.d.ts.map +1 -0
  66. package/dist/core/retry.js +86 -0
  67. package/dist/core/retry.js.map +1 -0
  68. package/dist/core/roster.d.ts +47 -0
  69. package/dist/core/roster.d.ts.map +1 -0
  70. package/dist/core/roster.js +146 -0
  71. package/dist/core/roster.js.map +1 -0
  72. package/dist/core/router.d.ts +67 -0
  73. package/dist/core/router.d.ts.map +1 -0
  74. package/dist/core/router.js +186 -0
  75. package/dist/core/router.js.map +1 -0
  76. package/dist/core/state.d.ts +89 -0
  77. package/dist/core/state.d.ts.map +1 -0
  78. package/dist/core/state.js +303 -0
  79. package/dist/core/state.js.map +1 -0
  80. package/dist/core/types.d.ts +333 -0
  81. package/dist/core/types.d.ts.map +1 -0
  82. package/dist/core/types.js +27 -0
  83. package/dist/core/types.js.map +1 -0
  84. package/dist/hooks/compacting.d.ts +18 -0
  85. package/dist/hooks/compacting.d.ts.map +1 -0
  86. package/dist/hooks/compacting.js +72 -0
  87. package/dist/hooks/compacting.js.map +1 -0
  88. package/dist/hooks/scopeGuard.d.ts +39 -0
  89. package/dist/hooks/scopeGuard.d.ts.map +1 -0
  90. package/dist/hooks/scopeGuard.js +114 -0
  91. package/dist/hooks/scopeGuard.js.map +1 -0
  92. package/dist/hooks/sessionIdle.d.ts +35 -0
  93. package/dist/hooks/sessionIdle.d.ts.map +1 -0
  94. package/dist/hooks/sessionIdle.js +110 -0
  95. package/dist/hooks/sessionIdle.js.map +1 -0
  96. package/dist/hooks/systemTransform.d.ts +18 -0
  97. package/dist/hooks/systemTransform.d.ts.map +1 -0
  98. package/dist/hooks/systemTransform.js +63 -0
  99. package/dist/hooks/systemTransform.js.map +1 -0
  100. package/dist/index.d.ts +36 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +103 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/tools/index.d.ts +22 -0
  105. package/dist/tools/index.d.ts.map +1 -0
  106. package/dist/tools/index.js +854 -0
  107. package/dist/tools/index.js.map +1 -0
  108. package/docs/ARCHITECTURE.md +258 -0
  109. package/docs/QUE-ES.md +337 -0
  110. package/examples/opencode.json +7 -0
  111. package/package.json +81 -4
  112. package/skills/oficina/README.md +120 -0
  113. package/skills/oficina/SKILL.md +251 -0
  114. package/skills/oficina/reference/mesh.md +345 -0
  115. package/skills/oficina/reference/protocol.md +342 -0
  116. package/skills/oficina/reference/roles.md +171 -0
  117. package/skills/oficina/reference/templates.md +278 -0
package/README.md CHANGED
@@ -1,3 +1,671 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # AI-OFFICE
4
+
5
+ ### Una oficina de agentes para OpenCode donde el trabajo no se detiene cuando el modelo dice «terminé».
6
+
7
+ [![npm](https://img.shields.io/npm/v/oficina-opencode?label=npm&color=cb3837)](https://www.npmjs.com/package/oficina-opencode)
8
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/SOCRAMbt/El-ltimoTPP/tree/main/LICENSE)
9
+ [![node](https://img.shields.io/badge/node-%3E%3D20-339933.svg)](https://nodejs.org)
10
+ [![tests](https://img.shields.io/badge/tests-213%20passing-22a06b.svg)](https://github.com/SOCRAMbt/El-ltimoTPP/tree/main/tests)
11
+ [![coverage](https://img.shields.io/badge/coverage-87.3%25-7c3aed.svg)](https://vitest.dev)
12
+ [![types](https://img.shields.io/badge/typescript-strict-3178c6.svg)](https://github.com/SOCRAMbt/El-ltimoTPP/blob/main/tsconfig.json)
13
+
14
+ **4 hooks · 13 tools · 7 agentes · 6 gates · 6 invariantes duros · 306 roles de catálogo**
15
+
16
+ > **¿Preferís la versión en humano?** → [`docs/QUE-ES.md`](https://github.com/SOCRAMbt/El-ltimoTPP/blob/main/docs/QUE-ES.md) — qué es, qué hace y por qué, sin jerga.
17
+ > **¿Preferís el porqué técnico?** → [`docs/ARCHITECTURE.md`](https://github.com/SOCRAMbt/El-ltimoTPP/blob/main/docs/ARCHITECTURE.md)
18
+
19
+ [Documentación](#arquitectura) · [Instalación](#instalación) · [Uso](#uso) · [CLI](#cli-operación)
20
+
21
+ </div>
22
+
23
+ ---
24
+
25
+ ## El problema
26
+
27
+ Working con agents tiene cinco fallas concretas. No son falta de inteligencia: son falta de **estructura**.
28
+
29
+ | Falla | Qué pasa en la práctica |
30
+ |---|---|
31
+ | **El modelo decide cuándo terminar** | Dice «listo, terminado» con la mitad del trabajo sin hacer, y la sesión para ahí. |
32
+ | **El trabajo se hace lineal** | Todo en un solo contexto: un agente, una tarea, un hilo. Los subagentes existen pero se desaprovechan. |
33
+ | **Nadie orquesta** | No hay un plan, no hay prioridad, no hay un dueño por tarea. |
34
+ | **El contexto se pierde** | Hay que repetir lo que ya se dijo, lo ya se decidió y lo ya se encontró. |
35
+ | **Los subagentes son islands** | No se piden ayuda, no se coordinan, no se benefician del trabajo del otro. |
36
+
37
+ Una skill de markdown no arregla ninguna de las cinco. Un sistema con reglas escritas en código, no: porque **no dependen de que el modelo tenga ganas de seguirlas**.
38
+
39
+ ---
40
+
41
+ ## Qué es
42
+
43
+ **AI-OFFICE** es un plugin de OpenCode que convierte la orquestación en **código ejecutable**, no en instrucciones.
44
+
45
+ ```
46
+ Skill → "Hacé lo que corresponda" → depende de que el modelo quiera
47
+ Plugin → máquina de estados + hooks → no depende de la buena voluntad
48
+ ```
49
+
50
+ Cuatro piezas lo hacen posible:
51
+
52
+ **1. Un hook que no deja que la sesión muera.** Cuando la sesión queda `idle` y quedan cards sin terminar, el motor manda un prompt sintético y la corrida sigue. El modelo **no puede declarar que terminó**: el estado lo dice.
53
+
54
+ **2. Un guard que no deja editar fuera de scope.** `tool.execute.before` intercepta cada `edit`/`write` y lo rechaza si el archivo está fuera del scope de la card. "No toques eso" deja de ser una sugerencia.
55
+
56
+ **3. Gates que se ejecutan, no se opinan.** Build, type check, lint, tests, escaneo de secretos y diff review. El motor corre los comandos, lee los exit codes y decide. La salida real queda pegada en el artefacto.
57
+
58
+ **4. Invariantes que el código garantiza.** `gate_required_before_done` y `reviewer_neq_owner` no son recomendaciones: `assertInvariants` lanza y la transición no ocurre.
59
+
60
+ Y una quinta, que es lo que hace confiable todo lo demás:
61
+
62
+ **5. El roster se arma según el objetivo.** Los roles salen del catálogo real de agency-agents (**306 agentes, 25 divisiones**), matcheados contra lo que la card pide. Y cada agente recibe un **briefing** de 10 secciones con lo que sabe, lo que no, y qué tiene que entregar.
63
+
64
+ ---
65
+
66
+ ## Arquitectura
67
+
68
+ Cuatro capas. De abajo hacia arriba.
69
+
70
+ ```
71
+ ┌──────────────────────────────────────────────────────────────────────┐
72
+ │ CAPA 3 — COORDINACIÓN │
73
+ │ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────────┐ │
74
+ │ │ COMANDANTE │ │ ARQUITECTO │ │ INTEGRADOR │ │
75
+ │ │ scope │ │ cross-cutting│ │ DAG · leases · gates │ │
76
+ │ │ objetivo │ │ patrones │ │ presupuesto · anti-deadlock│ │
77
+ │ │ prioridad │ │ contratos │ │ │ │
78
+ │ └───────┬──────┘ └──────┬───────┘ └────────────┬──────────────┘ │
79
+ │ │ │ │ │
80
+ │ ════════╪════════════════╪═══════════════════════╪═════════════ │
81
+ │ ▼ ▼ ▼ │
82
+ │ CAPA 2 — BUS DE MENSAJES (append-only sobre disco) │
83
+ │ bus/<canal>/<seq>-<msgid>.json │
84
+ │ inbox/<agentId>/ · roster.json · leases/<taskId>.json │
85
+ │ canales: coord-command │ coord-arch │ coord-flow │ peer │
86
+ │ │ │
87
+ │ ▼ │
88
+ │ CAPA 1 — ESPECIALISTAS (ficha normalizada) │
89
+ │ E1 E2 E3 E4 E5 E6 E7 E8 E9 E10 │
90
+ │ briefing: ficha.md · misiones.md · protocolo.md · bus.md │
91
+ │ │ │
92
+ │ ▼ │
93
+ │ CAPA 0 — ROSTER / FICHAS (resolución de roles) │
94
+ │ agency-agents/<division>/*.md → ficha │ catálogo < 60% → factory│
95
+ └──────────────────────────────────────────────────────────────────────┘
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Capa 0 — De dónde sale la especialidad
101
+
102
+ El repo de agency-agents tiene **306 agentes en 25 divisiones**, y cada uno trae un briefing de 10 secciones. La especialidad real **no está en el `description`** del frontmatter: está en el cuerpo.
103
+
104
+ Un agente de statistics declara:
105
+ - `description`: *"Expert in quantitative research methodology..."*
106
+ - **Core Mission** → *Pressure-Test Quantitative Claims*, *Design Sound Studies*
107
+ - **Technical Deliverables** → *Claim Interrogation Framework*, *Effect Size Report*
108
+ - **Advanced Capabilities** → *Causal Inference*, *Experimental Design*
109
+
110
+ La `description` dice de qué se ocupa. El cuerpo dice **en qué es exactamente bueno**. Un matcher que solo mira la `description` no puede distinguir a un metodólogo de un analista de datos — aunque uno de los dos sea exactamente lo que la card necesita.
111
+
112
+ Por eso el parser extrae las secciones del cuerpo, y el score pondera cada señal por lo que aporta:
113
+
114
+ | Señal | Peso | Por qué |
115
+ |---|---|---|
116
+ | **Identidad** (slug + nombre + `description` + `vibe`) | 35% | Las dos últimas son **líneas curadas** que dicen de qué se ocupa el agente. El cuerpo son 300 líneas donde cualquier palabra genérica aparece |
117
+ | **Misión, overlap literal** | 28% | Lo que el agente dice que sabe hacer, con sus palabras |
118
+ | **Misión, overlap conceptual** | 18% | Puentea sinónimos con una taxonomía de 26 dominios |
119
+ | **División** | 10% | Una card de e2e testing va a la división `testing`, no a `engineering` |
120
+ | **Cuerpo completo** | 5% | Ruido: "review" aparece en todos |
121
+
122
+ **Sinónimos por capability**, no por concepto. La taxonomía agrupa; los sinónimos no. `"e2e"` es `"end-to-end"`, pero `"e2e"` **no** es `"playwright"`. Esa distinción separa a un especialista de un generalista que menciona la tool de pasada.
123
+
124
+ **Lematización**: `"testing"` ~ `"test"`, `"validation"` ~ `"validate"`. El Commander pide capabilities en sus palabras y los agentes usan las suyas.
125
+
126
+ **Focus de misión**: qué fracción de las misiones declaradas del agente tiene que ver con el objetivo. Un `Test Automation Engineer` tiene las 5 en el dominio → focus 1. Un PDF engine con *una* misión sobre "Playwright Browser Context Pools" y las otras 7 sobre PDF → focus 0.12. **Este es el discriminante real.**
127
+
128
+ El score final combina: cobertura (35%) + recall (30%) + focus (25%) + F1 (10%).
129
+
130
+ Resolución real contra el catálogo:
131
+
132
+ | Objetivo | Primario | Cobertura |
133
+ |---|---|---|
134
+ | Pipeline de datos con ingesta y agregación | `engineering-data-engineer` | 76% |
135
+ | Migración de Postgres con partitioning | `engineering-gaussdb-expert` | 60% |
136
+ | Formulario de login en React con accesibilidad | `engineering-uswds-developer` | 56% |
137
+ | CI/CD con Docker y Kubernetes | `engineering-devops-automator` | 53% |
138
+ | Agente de GIS y cartografía | `gis-web-gis-developer` | 52% |
139
+ | Tests e2e con Playwright | `testing-test-automation-engineer` | 47% |
140
+ | Seguridad de un endpoint API | `testing-api-tester` | 42% |
141
+
142
+ Reproducible: `npx tsx scripts/demo-roles.ts`
143
+
144
+ ### El panel: primario + complementos
145
+
146
+ Un objetivo casi nunca es de un solo dominio. *"Formulario de login en React con validación y accesibilidad"* necesita un frontend (que no sabe de ARIA) **y** un especialista en accesibilidad (que no sabe de React).
147
+
148
+ Si el sistema elige uno solo, deja huecos. Si elige varios sin criterio, duplica capacidad. El panel resuelve las dos cosas:
149
+
150
+ ```
151
+ OBJETIVO: Implementar un formulario de login en React con validación y accesibilidad
152
+ PIDE: react, form, validation, accessibility, frontend
153
+
154
+ PRIMARIO 56% engineering/engineering-uswds-developer
155
+ "USWDS Developer"
156
+ cubre: react, css, form, accessibility
157
+
158
+ + COMPLEM. 39% engineering/engineering-section-508-specialist
159
+ "Section 508 Accessibility Specialist"
160
+ aporta: form, accessibility
161
+ ```
162
+
163
+ El primario se lleva la card. Los complementos son los agentes que cubren **lo que el primario no cubre**, y son sus pares naturales en el bus. Y lo que nadie cubre **se reporta explícitamente**: es la señal de que la card debería partirse en dos.
164
+
165
+ ### La ficha: un solo schema
166
+
167
+ Venga el rol de `agency-agents` o de la factory, se materializa en la **misma** ficha. Esa unificación es lo que permite que el bus, el matching de ayuda, la rotación y los coordinadores no necesiten saber el origen de nada.
168
+
169
+ ```yaml
170
+ id: e-frontend
171
+ role: frontend-developer
172
+ source:
173
+ kind: agency-agents
174
+ division: engineering
175
+ path: engineering/frontend-developer.md
176
+ vibe: "Pixel obsessive, allergic to dead CSS."
177
+ missions: ["Create Modern Web Applications", "Optimize Performance and UX"]
178
+ deliverables: ["Component Library", "Design Token System"]
179
+ rules: ["Never ship a component without a test", "..."]
180
+ capabilities: [react, component, ui, web, accessibility, performance, ...]
181
+ scope:
182
+ mayTouch: ["src/components/**", "src/hooks/**"]
183
+ forbidden: ["src/server/**", "**/*.env*"]
184
+ can_delegate: true
185
+ delegate_budget: 2
186
+ peers: [e-architect, e-qa, e-security]
187
+ must_not:
188
+ - "no editar archivos fuera de may_touch"
189
+ - "no aprobar tu propio trabajo"
190
+ on_finish: idle-join
191
+ escalate_to: coordinator-flow
192
+ ```
193
+
194
+ ### La factory: el mismo briefing, sin catálogo
195
+
196
+ Un rol fabricado tiene que ser **indistinguible en calidad** de uno del catálogo. Si el catálogo tiene agentes con briefing de 10 secciones, uno fabricado con un prompt de 5 líneas se nota: es monótono, no tiene criterio propio, y el resto de la malla lo trata como de segunda.
197
+
198
+ Por eso la factory emite **exactamente la misma estructura**: Identity & Memory, Core Mission, Critical Rules, Technical Deliverables, Workflow Process, Communication Style, Learning & Memory, Success Metrics, Advanced Capabilities. El parser no distingue el origen.
199
+
200
+ Y lo importante: el prompt fabricado **no es genérico**. Lleva las capabilities concretas, el scope, el objetivo de la corrida, los modos de fallo del rol y el contexto de la card.
201
+
202
+ ---
203
+
204
+ ## El equipo se arma
205
+
206
+ El flujo completo es: **doy un objetivo → el jefe lo divide → crea los subagentes → arrancan a trabajar juntos**.
207
+
208
+ `oficina_dispatch` es el momento en que eso pasa:
209
+
210
+ 1. **El Comandante descompone** el objetivo en cards (`oficina_plan`). Cada card dice qué se produce, cómo se sabe que está bien, y qué archivos puede tocar.
211
+ 2. **El dispatch resuelve los roles.** Para cada card busca en el catálogo de agency-agents el agente que mejor encaja, calcula el **panel** (primario + complementos), y si la cobertura queda baja **fabrica** el rol con la card como contexto.
212
+ 3. **Materializa los agentes** en `.opencode/agents/` del proyecto, cada uno con su briefing de 10 secciones y su prompt de especialidad. Quedan versionados con el repo: la próxima sesión ya están registrados.
213
+ 4. **Los arranca en paralelo** vía `session.prompt` con una parte `subtask` — la vía que OpenCode provee para crear subagentes reales.
214
+
215
+ El resultado:
216
+
217
+ ```
218
+ ▸ formulario de login en React con validación y accesibilidad
219
+ → `oficina-engineering-uswds-developer` card T-00
220
+ + `oficina-testing-api-tester` par libre aporta: validation
221
+ → `oficina-engineering-section-508-specialist` card T-01
222
+ + `oficina-testing-accessibility-auditor` par libre aporta: aria
223
+ → `oficina-testing-test-automation-engineer` card T-02
224
+ ```
225
+
226
+ Los **pares libres** son los complementos: están en la mesa, pueden recibir un pedido de ayuda, y pueden reclamar una card que quedó sin dueño.
227
+
228
+ ---
229
+
230
+ ## La mesa
231
+
232
+ Los subagentes son procesos aislados: no se ven, no saben quién más trabaja, no saben a quién preguntarle. La **mesa** es la vista compartida — vive en disco, así que todos la leen sin memoria compartida.
233
+
234
+ `oficina_mesa` responde:
235
+
236
+ - **Quién está trabajando en qué** — y qué archivos toca cada uno
237
+ - **Quién está libre** y puede recibir un pedido de ayuda
238
+ - **Qué cards no tienen owner** — reclamables proactivamente
239
+ - **Qué ayuda sigue sin responder** y **qué preguntas están abiertas**
240
+
241
+ Y cuando la sesión queda `idle`, el hook de auto-continuación inyecta esa foto en el prompt del agente que arranca. Sin esto, el peer mesh es un bus al que nadie mira.
242
+
243
+ ### El ciclo de un agente
244
+
245
+ ```
246
+ DEPLOYED → WORKING → (terminó) → IDLE_AVAILABLE → (ayuda) → WORKING
247
+ ↓ ↑
248
+ BLOCKED ──→ IDLE_AVAILABLE ──────────────────┘
249
+ ```
250
+
251
+ Cuando un agente termina, **ofrece ayuda** para lo que sigue. No queda esperando.
252
+
253
+ ### Hablar por el bus
254
+
255
+ El que recibe un pedido de ayuda **hace su propio triage** — no acepta por cortesía:
256
+
257
+ 1. ¿Entiendo la tarea? → si no, `HELP_DECLINE` + explicar
258
+ 2. ¿Está en mi scope? → si no, `HELP_DECLINE` + sugerir a quién
259
+ 3. ¿Puedo hacerlo ya sin romper mi card? → si no, `HELP_DECLINE` + "cuando termine"
260
+ 4. ¿Tengo el contexto? → si no, `HELP_QUESTION` por el bus
261
+ 5. ¿Vale la pena? → si no, `HELP_DECLINE` + alternativa
262
+ 6. ¿Tengo presupuesto? → si no, `HELP_DECLINE` + "sin presupuesto"
263
+
264
+ **Anti-deadlock**: máximo 2 saltos en una cadena de ayuda; después escala al Integrador.
265
+ **Anti-monotonía**: si el par A↔B ya se ayudaron 2 veces, el tercer pedido va a un tercero.
266
+
267
+ ---
268
+
269
+ ## Capa 1 — El briefing: qué sabe cada agente antes de arrancar
270
+
271
+ Un subagente arranca con el contexto vacío. Si el Commander le pasa un prompt suelta (*"implementá el login"*), el agente tiene que adivinar: qué sabe del proyecto, qué espera de él, qué puede tocar, a quién preguntarle si se traba, y qué tiene que entregar. Adivinar es la fuente de todo el trabajo que se repite y de los agentes que se salen del scope.
272
+
273
+ El briefing es el contrato de información. Tiene **orden fijo** y **mínimo verificable**.
274
+
275
+ ### El orden
276
+
277
+ La información llega de lo más estable a lo más cambiante. Un agente lee de arriba hacia abajo y siempre tiene lo que necesita para el paso siguiente.
278
+
279
+ | # | Sección | Qué le dice |
280
+ |---|---|---|
281
+ | 1 | **Quién sos** | Rol, especialidad de origen, de dónde viene tu briefing, tu vibe |
282
+ | 2 | **Tu misión** | La card exacta, los criterios de aceptación numerados, el control de calidad |
283
+ | 3 | **Lo que ya sabés** | Decisiones tomadas, restricciones descubiertas, piezas construidas, trampas |
284
+ | 4 | **Lo que NO sabés** | Los huecos explícitos y **a quién preguntarle** por cada uno |
285
+ | 5 | **Tu territorio** | Qué podés tocar, qué no, y qué prohibiciones trae tu ficha |
286
+ | 6 | **Cómo trabajás** | El ciclo, cuándo pedir ayuda, cuándo delegar, cuándo escalar |
287
+ | 7 | **Tu canal** | Dónde dejás y encontrás mensajes, formato, TTLs, cómo acusar recibo |
288
+ | 8 | **Qué se espera de vos** | Los entregables exactos: `handoff.md` y `evidence.md` |
289
+ | 9 | **Lo que no podés hacer** | Las prohibiciones duras. Están en código, no en tu criterio |
290
+ | 10 | **Cómo se mide que terminaste** | Las tres condiciones de terminado |
291
+
292
+ ### El mínimo
293
+
294
+ Las diez secciones son **requeridas**. Si alguna queda vacía, el briefing se marca `INCOMPLETO` y **el agente no arranca**. Un briefing a medio llenar produce un agente a medio informado, que es peor que no tener agente.
295
+
296
+ ### Los cuatro artefactos
297
+
298
+ El briefing se materializa en cuatro archivos en disco, porque un agente no "recuerda" un prompt largo: lo lee.
299
+
300
+ ```
301
+ .oficina/fichas/<agentId>/
302
+ ├── ficha.md ← Quién sos
303
+ ├── misiones.md ← Tu misión · lo que ya sabés · lo que NO sabés
304
+ ├── protocolo.md ← Cómo trabajás · tu territorio · qué se espera · límites · éxito
305
+ ├── bus.md ← Tu canal
306
+ └── briefing.md ← el documento completo, para lectura humana
307
+ ```
308
+
309
+ **El agente no arranca sin `misiones.md`. Nunca.**
310
+
311
+ ### El ledger: lo que ya sabés
312
+
313
+ La sección 3 se alimenta del **contexto acumulado** de la corrida (`.oficina/context.md`), que registra decisiones, restricciones, piezas construidas y trampas. Es lo que evita que un agente repita lo que ya se decidió — y lo que convierte al bus en algo más que un tablón de avisos.
314
+
315
+ ---
316
+
317
+ ## Capa 2 — El bus
318
+
319
+ Los subagentes de OpenCode son **procesos aislados sin memoria compartida**. No pueden hablarse de facto. La solución coherente es un bus append-only sobre disco.
320
+
321
+ ```json
322
+ {
323
+ "id": "m-0042",
324
+ "seq": 42,
325
+ "from": "e-frontend",
326
+ "to": ["e-architect"],
327
+ "kind": "HELP_REQUEST",
328
+ "subject": "T-03",
329
+ "body": {
330
+ "need": "convertir este componente a streaming SSR",
331
+ "why_me": "tengo el contexto del componente pero no el del server"
332
+ },
333
+ "reply_to": null,
334
+ "in_reply_to": null,
335
+ "ttl_sec": 900,
336
+ "created_at": "2026-10-21T15:04:00Z",
337
+ "priority": "normal",
338
+ "idempotency_key": "help:T-03:e-frontend:a1b2c3",
339
+ "hops": 0
340
+ }
341
+ ```
342
+
343
+ | Garantía | Implementación | Por qué importa |
344
+ |---|---|---|
345
+ | **Append-only** | Los mensajes nunca se borran; `seq` es monótono por canal | El log es la auditoría |
346
+ | **Escritura atómica** | `.tmp` + `rename` | Nunca hay un JSON partido en el read |
347
+ | **Ack** | `inbox/<agentId>/<msgid>.ack` | El emisor sabe quién leyó |
348
+ | **TTL** | Vencido = invisible para lectores nuevos, sigue en el log | Un pedido viejo no bloquea nada |
349
+ | **Idempotency key** | Mismo key = mismo mensaje | Evita el storm de «¿me ayudás?» |
350
+ | **Broadcast** | `to: ["*"]` al pool | El primero que acepta toma el lease |
351
+ | **Anti-deadlock** | `hops` máximo 2 | Una cadena de ayuda no se enquista |
352
+
353
+ ### El que recibe hace su propio triage
354
+
355
+ No acepta por cortesía. Seis preguntas, en orden:
356
+
357
+ 1. ¿Entiendo la tarea? → si no, `HELP_DECLINE` + explicar
358
+ 2. ¿Está en mi scope? → si no, `HELP_DECLINE` + sugerir a quién
359
+ 3. ¿Puedo hacerlo **ya** sin romper mi card? → si no, `HELP_DECLINE` + «cuando termine»
360
+ 4. ¿Tengo el contexto? → si no, `HELP_QUESTION` por el bus
361
+ 5. ¿Vale la pena? → si no, `HELP_DECLINE` + alternativa
362
+ 6. ¿Tengo presupuesto? → si no, `HELP_DECLINE` + «sin presupuesto»
363
+
364
+ ---
365
+
366
+ ## Los 4 hooks
367
+
368
+ Acá es donde el protocolo deja de ser una intención.
369
+
370
+ | Hook | Qué hace | Por qué importa |
371
+ |---|---|---|
372
+ | `event` → `session.idle` | Si queda trabajo, manda un prompt sintético y la corrida sigue | La oficina trabaja sola. El modelo no declara el fin: el estado. |
373
+ | `tool.execute.before` | Bloquea escrituras fuera del scope de la card | «No toques eso» pasa de instrucción a restricción |
374
+ | `experimental.chat.system.transform` | Inyecta el estado de la oficina en cada llamada | El agente no repregunta lo que ya sabe ni repite trabajo |
375
+ | `experimental.session.compacting` | Reinyecta el estado **leído del disco** al compactar | Sin esto, la oficina se olvida a mitad de camino |
376
+
377
+ El hook de auto-continuación tiene guardas duras: solo reanuda si queda trabajo real, tope de 25 auto-reanudaciones por sesión, cooldown de 1,5 s entre reanudaciones, y nunca reanuda una corrida `paused`, `blocked` o `delivered`.
378
+
379
+ ---
380
+
381
+ ## Los 6 gates
382
+
383
+ De la skill `verification-loop`. Se ejecutan de verdad; el motor interpreta los exit codes.
384
+
385
+ | # | Fase | Node | Python | Go | Rust |
386
+ |---|---|---|---|---|---|
387
+ | 1 | Build | `npm run build` | `python -m build` | `go build ./...` | `cargo build` |
388
+ | 2 | Type check | `npm run typecheck` | `mypy` | `go vet ./...` | `cargo check` |
389
+ | 3 | Lint | `npm run lint` | `ruff` | `golangci-lint` | `cargo clippy` |
390
+ | 4 | Tests | `npm run test` | `pytest` | `go test` | `cargo test` |
391
+ | 5 | Secretos | escaneo en código | ← | ← | ← |
392
+ | 6 | Diff review | `git diff --stat` | ← | ← | ← |
393
+
394
+ **Reglas de honestidad** — no negociables:
395
+
396
+ - Nunca `PASS` en una fase que no se corrió → `NOT RUN` y eso hace fallar el gate
397
+ - Nunca output inventado
398
+ - `N/A` siempre con motivo explícito
399
+ - Una fase aplicable en `FAIL` = gate `FAIL`. No se promedia
400
+ - El escaneo de secretos corre **en TypeScript**, no shelling out a `grep` (que no existe en Windows), y **redacta** el valor: un log de gate que imprime la credencial completa la acaba de filtrar
401
+
402
+ ---
403
+
404
+ ## Invariantes duros
405
+
406
+ Los implementa el código. Un prompt puede pedirle al modelo que sea cuidadoso; el motor no puede romperlos.
407
+
408
+ | Invariante | Valor |
409
+ |---|---|
410
+ | `gate_required_before_done` | `true` — sin gates en `PASS` no hay `DONE` |
411
+ | `reviewer_neq_owner` | `true` — no hay auto-aprobación |
412
+ | `max_concurrent_agents` | 10 base · 14 hard cap |
413
+ | `max_spawn_depth` | 2 niveles bajo el coordinador |
414
+ | `max_spawns_total` | 20 por corrida |
415
+ | `max_help_chain_hops` | 2 — anti-deadlock |
416
+ | `max_messages_per_agent` | 150 — anti-spam |
417
+ | `msg_ttl_sec` | 900 |
418
+ | `lease_ttl_sec` | 1800 — con heartbeat; si el agente muere, expira |
419
+ | `heartbeat_sec` | 60 |
420
+ | `max_review_rejections` | 3 → escalación |
421
+ | `max_cards` · `max_agent_calls` | 20 · 40 por corrida |
422
+
423
+ ---
424
+
425
+ ## Los 3 coordinadores
426
+
427
+ Un solo coordinador es cuello de botella y punto único de falla.
428
+
429
+ | | COMANDANTE | ARQUITECTO | INTEGRADOR |
430
+ |---|---|---|---|
431
+ | **Dominio** | Scope, objetivo, prioridades | Decisiones técnicas cross-cutting | DAG, leases, gates, calidad |
432
+ | **Responde** | ¿esto está en el objetivo? | ¿qué patrón usamos? | ¿quién tiene T-07? ¿pasó el gate? |
433
+ | **Detecta** | Scope creep, requisitos no cubiertos | Drift arquitectónico, decisiones inconsistentes | Deadlock, starvation, gates rojos, doble-claim |
434
+ | **Nunca** | Diseñar ni revisar código | Escribir código | Escribir código |
435
+
436
+ **Arbitraje**: scope → Comandante. Patrón/contrato → Arquitecto. Flujo/lease/gate → Integrador. Si cruza dos dominios, el Arquitecto decide lo técnico con visto bueno del Comandante; si el Integrador detecta deadlock, reparte y avisa.
437
+
438
+ Las preguntas de un especialista al coordinador **van por el bus**, no interrumpen al humano. Al usuario solo llega lo que ningún coordinador puede resolver.
439
+
440
+ ---
441
+
442
+ ## Los 13 tools
443
+
444
+ Trece, no treinta. Cada tool que se suma es ruido en el contexto de todos los agentes.
445
+
446
+ | Tool | Qué hace |
447
+ |---|---|
448
+ | `oficina_plan` | Guarda el plan de cards. El modelo propone; el motor valida y rutea owner/reviewer |
449
+ | `oficina_dispatch` | **Arma el equipo**: resuelve los roles, materializa los agentes con su briefing y los arranca en paralelo |
450
+ | `oficina_mesa` | **La mesa**: quién trabaja en qué, quién está libre, qué ayuda espera respuesta, qué cards no tienen owner |
451
+ | `oficina_board` | Estado: cards, owners, agentes libres, agentes sin heartbeat, presupuesto |
452
+ | `oficina_assign` | Toma trabajo — la próxima card, o claim proactivo de una puntual |
453
+ | `oficina_submit` | Entrega handoff + evidencia real → pasa a `REVIEW` |
454
+ | `oficina_review` | Registra el veredicto. El motor **rechaza** que el owner se auto-revise |
455
+ | `oficina_gate` | Corre los 6 gates. Exit codes reales, no opinión |
456
+ | `oficina_bus` | Bus: `send` · `receive` · `ack` · `help` |
457
+ | `oficina_spawn` | Pide desplegar un agente. El Integrador aprueba o rechaza |
458
+ | `oficina_escalate` | Escala al usuario con 2-3 opciones concretas y recomendación |
459
+ | `oficina_ficha` | Resuelve un rol a ficha y **despliega** el agente con su briefing |
460
+ | `oficina_brief` | Muestra el briefing y el **panel de roles** sin desplegar: decisión del Comandante |
461
+
462
+ ---
463
+
464
+ ## Los 7 agentes
465
+
466
+ | Agente | Rol | Aprueba? |
467
+ |---|---|---|
468
+ | `oficina-commander` | Scope, objetivo, prioridades | No revisa técnico |
469
+ | `oficina-architect` | Decisiones técnicas cross-cutting | No revisa técnico |
470
+ | `oficina-integrator` | DAG, leases, gates, presupuesto | No revisa técnico |
471
+ | `oficina-critico` | Revisión con confianza calibrada (umbral 80) | Sí |
472
+ | `oficina-guardian` | Secretos, inyecciones, deps, auth | Sí |
473
+ | `oficina-verificador` | Ejecuta build/typecheck/lint/test | Sí |
474
+ | `oficina-director` | Dirección de la oficina v1 (fallback) | No |
475
+
476
+ ---
477
+
478
+ ## Instalación
479
+
480
+ ### Desde npm
481
+
482
+ ```bash
483
+ npm install -g oficina-opencode
484
+ ```
485
+
486
+ ### Local (desarrollo)
487
+
488
+ ```bash
489
+ git clone https://github.com/SOCRAMbt/El-ltimoTPP.git
490
+ cd El-ltimoTPP
491
+ npm install
492
+ npm run build
493
+
494
+ cd ~/.config/opencode
495
+ npm install file:/ruta/a/El-ltimoTPP
496
+ ```
497
+
498
+ Y el entry point en `~/.config/opencode/plugins/oficina.js`:
499
+
500
+ ```js
501
+ export { OficinaPlugin, default } from "oficina-opencode"
502
+ ```
503
+
504
+ ### Configuración
505
+
506
+ `~/.config/opencode/opencode.json`:
507
+
508
+ ```json
509
+ {
510
+ "experimental": {
511
+ "subagent_depth": 3
512
+ }
513
+ }
514
+ ```
515
+
516
+ `subagent_depth: 3` es **obligatorio**: con el default (`1`) los subagentes no pueden delegar a otros subagentes, y la malla no arranca.
517
+
518
+ ### Los assets del protocolo
519
+
520
+ ```bash
521
+ oficina install --target ~/.config/opencode
522
+ ```
523
+
524
+ Instala la skill, los 7 agentes, el comando y el entry point del plugin.
525
+
526
+ ---
527
+
528
+ ## Uso
529
+
530
+ Desde la raíz del proyecto:
531
+
532
+ ```text
533
+ /oficina Agregar autenticación JWT con refresh rotation
534
+ ```
535
+
536
+ El comando carga la skill `oficina`, el plugin registra las tools, y la corrida arranca sola.
537
+
538
+ El ciclo:
539
+
540
+ ```
541
+ OBJETIVO → PLAN (Comandante)
542
+ ↓
543
+ STANDUP — la card con deps satisfechas
544
+ ↓
545
+ TRABAJO (owner) → handoff.md + evidence.md
546
+ ↓
547
+ AUTO-REVIEW (oficina-critico, ≠ owner)
548
+ ↓
549
+ GATES (oficina-verificador + oficina-guardian)
550
+ ↓
551
+ ┌────────┴────────┐
552
+ DONE REWORK → REPLAN → ESCALADA
553
+ ```
554
+
555
+ ---
556
+
557
+ ## CLI — operación
558
+
559
+ ```bash
560
+ oficina init [objetivo] # Crea .oficina/ en el proyecto
561
+ oficina status # Cards, agentes, presupuesto, escalaciones
562
+ oficina board # Tablero Kanban
563
+ oficina bus # Estadísticas del bus
564
+ oficina audit T-03 # Artefactos, gates y review de una card
565
+ oficina verify # Corre los gates de las cards en review
566
+ oficina install --target <dir> # Instala skill, agentes y comando
567
+ oficina catalog --agency-root <path> # Lista el catálogo de roles disponible
568
+ oficina reset --force # Abandona la corrida
569
+ ```
570
+
571
+ ---
572
+
573
+ ## Estructura de la corrida
574
+
575
+ ```
576
+ <proyecto>/.oficina/
577
+ ├── board.md # Kanban legible por humanos
578
+ ├── state.json # estado legible por máquinas — retoma tras reinicio
579
+ ├── context.md # ledger de conocimiento acumulado
580
+ ├── roster.json # quién existe, qué puede, qué está haciendo
581
+ ├── config.json
582
+ ├── bus/
583
+ │ ├── coord-command/0001-m-xxxxxxxx.json
584
+ │ ├── coord-arch/
585
+ │ ├── coord-flow/
586
+ │ └── peer/
587
+ ├── inbox/<agentId>/ # acks
588
+ ├── leases/<taskId>.json
589
+ ├── fichas/<agentId>/ # los 4 artefactos del briefing + briefing.md
590
+ └── artifacts/<cardId>/
591
+ ├── handoff.md # qué hizo el owner
592
+ ├── evidence.md # salida real de los comandos
593
+ ├── review.md # veredicto del crítico
594
+ ├── gates.md # PASS/FAIL técnico y seguridad
595
+ └── decision.md # decisión del director
596
+ ```
597
+
598
+ El formato de artefactos es compatible con OFICINA v1 (la skill). El plugin **migra el estado v1 automáticamente**: objetivo, cards y resultados se conservan.
599
+
600
+ ---
601
+
602
+ ## Código
603
+
604
+ 24 archivos TypeScript · 14 módulos en `core/` · 1 toolset · 4 hooks.
605
+
606
+ ```
607
+ src/
608
+ ├── index.ts # entry del plugin: tools + hooks
609
+ ├── cli.ts # CLI de operación
610
+ ├── core/
611
+ │ ├── types.ts # el schema único del sistema
612
+ │ ├── state.ts # máquina de estados + invariantes + migración v1
613
+ │ ├── bus.ts # bus append-only con TTL/ack/idempotencia
614
+ │ ├── roster.ts # quién existe + pool idle
615
+ │ ├── leases.ts # leases con TTL y heartbeat
616
+ │ ├── catalog.ts # escaneo de agency-agents + matching + panel
617
+ │ ├── factory.ts # generación de roles con briefing de 10 secciones
618
+ │ ├── briefing.ts # el contrato de información del agente
619
+ │ ├── router.ts # enrutado + rotación anti-monotonía
620
+ │ ├── gates.ts # runner de los 6 gates + escaneo de secretos
621
+ │ ├── retry.ts # política de 3 golpes
622
+ │ ├── office.ts # la fachada que amarra todo
623
+ │ ├── paths.ts # resolución de project root
624
+ │ ├── fsx.ts # IO atómico
625
+ │ └── log.ts # logging estructurado
626
+ ├── tools/index.ts # las 11 tools
627
+ └── hooks/
628
+ ├── sessionIdle.ts # auto-continuación
629
+ ├── scopeGuard.ts # enforcement de scope
630
+ ├── systemTransform.ts
631
+ └── compacting.ts
632
+ ```
633
+
634
+ ### Dependencias
635
+
636
+ Una sola, y es peer del host: `@opencode-ai/plugin`. Zod entra por `tool.schema` — la instancia del propio plugin — para que los tipos nunca divergan de la versión que el host está corriendo.
637
+
638
+ ---
639
+
640
+ ## Testing
641
+
642
+ ```bash
643
+ npm test # 213 tests, 14 archivos
644
+ npm run coverage # 90.2% stmts · 82.8% branches
645
+ npm run typecheck # tsc --noEmit, strict
646
+ npm run build # tsc → dist/
647
+ ```
648
+
649
+ | Suite | Cubre |
650
+ |---|---|
651
+ | `bus.test.ts` | Append-only, ack, TTL, idempotencia, broadcast, prioridad, atomicidad |
652
+ | `state.test.ts` | Transiciones, invariantes duros, selección de card, ciclo de corrida |
653
+ | `gates.test.ts` | Detección de tooling, las 6 fases, N/A con motivo, consolidación, redacción |
654
+ | `router.test.ts` | Enrutado, rotación, reviewer ≠ owner, política de 3 golpes, presupuesto |
655
+ | `leases.test.ts` | Adquisición, heartbeat, expiración, double-claim, reasignación |
656
+ | `catalog.test.ts` | Frontmatter, secciones, extracción, matching ponderado, panel, factory |
657
+ | `catalogReal.test.ts` | El catálogo real de 306 agentes: estructuras, matching, división |
658
+ | `briefing.test.ts` | Orden, mínimo, las 10 secciones, los 4 artefactos, INCOMPLETO |
659
+ | `office.test.ts` | Ciclo completo end-to-end, invariantes, artefactos en disco |
660
+ | `scopeGuard.test.ts` | Globs, extracción de path, enforcement de scope |
661
+ | `plugin.test.ts` | El plugin contra un host mockeado: tools, hooks, auto-resume |
662
+ | `migration.test.ts` | Migración v1 → v2 sin pérdida de datos |
663
+ | `cli.test.ts` | init, status, board, install, audit, reset, idempotencia |
664
+
665
+ ---
666
+
667
+ ## Licencia
668
+
669
+ MIT — ver [LICENSE](https://github.com/SOCRAMbt/El-ltimoTPP/tree/main/LICENSE).
670
+
671
+ El diseño se apoya en los patrones de `durable-execution` y `workflow-engine-design`: estado durable antes de los efectos, leases con TTL, transiciones nombradas explícitamente y at-least-once con reconciliación por idempotency key.