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
@@ -0,0 +1,345 @@
1
+ # Capa 2-3 — El mesh (v2)
2
+
3
+ Detalle de la malla: bus, fichas, roster, leases, spawn policy, idle pool.
4
+
5
+ ---
6
+
7
+ ## La ficha: schema único
8
+
9
+ 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.
10
+
11
+ ```yaml
12
+ id: e-frontend # id de despliegue, único por corrida
13
+ role: frontend-developer
14
+ display_name: Frontend Developer
15
+ source:
16
+ kind: agency-agents # agency-agents | factory
17
+ division: engineering
18
+ path: engineering/frontend-developer.md
19
+ source_prompt: <el system prompt original, verbatim>
20
+ vibe: <la personality hook de una línea del frontmatter>
21
+ missions: [<subtítulos de "Core Mission">]
22
+ deliverables: [<subtítulos de "Technical Deliverables">]
23
+ rules: [<items de "Critical Rules">]
24
+ capabilities:
25
+ - react-component-design
26
+ - css-architecture
27
+ - accessibility
28
+ tools: [read, glob, grep, edit, write, bash]
29
+ scope:
30
+ may_touch: ["src/components/**", "src/hooks/**"]
31
+ forbidden: ["src/server/**", "**/*.env*"]
32
+ can_delegate: true # este rol puede tirar subagentes nuevos
33
+ delegate_budget: 2
34
+ peers: # con quién tiene relación de pares (para pedir ayuda)
35
+ - e-architect
36
+ - e-qa
37
+ - e-security
38
+ must_not: # límites duros, leídos por los coordinadores
39
+ - "no editar archivos fuera de may_touch"
40
+ - "no tocar archivos de forbidden"
41
+ - "no aprobar tu propio trabajo"
42
+ on_finish: "idle-join" # al terminar su objetivo entra al pool de ayuda
43
+ escalate_to: coordinator-flow
44
+ ```
45
+
46
+ ### Resolución: catálogo primero, factory después
47
+
48
+ El catálogo de agency-agents tiene **306 agentes en 25 divisiones**. La especialidad real de cada uno está en el **cuerpo**, no en el `description` del frontmatter:
49
+
50
+ - **Core Mission** → los subtítulos son la especialidad declarada
51
+ - **Technical Deliverables** → lo que sabe producir
52
+ - **Advanced Capabilities** → lo que maneja mejor
53
+
54
+ El matcher pondera: nombre del rol (40%) · misión literal (35%) · misión conceptual (20%) · cuerpo (5%) · división (0%).
55
+
56
+ ```
57
+ 1. CATALOG MATCH (preferido)
58
+ Buscar en agency-agents/<division>/*.md el agente cuya especialidad
59
+ declarada en el cuerpo matchea las capacidades pedidas.
60
+ → source.kind = agency-agents, source_prompt = el prompt original
61
+
62
+ 2. FACTORY (si no hay match, o la cobertura es < 60%)
63
+ Se genera desde template: system prompt = rol + ficha + working
64
+ discipline + capabilities + objetivo de la corrida, con la MISMA
65
+ estructura de 10 secciones que agency-agents.
66
+ → source.kind = factory
67
+ Se registra como AGENT-CANDIDATE para promoverlo a skill después
68
+ ```
69
+
70
+ **Regla de cobertura**: antes de desplegar, se calcula qué fracción del objetivo cubre el **panel** (primario + complementos). Si es < 60%, se crea un rol nuevo con factory en vez de forzar un mal match.
71
+
72
+ Esto evita el "subagente monotono", que es el síntoma exacto del problema original.
73
+
74
+ ### El panel de roles
75
+
76
+ Un objetivo casi nunca es de un solo dominio. El panel devuelve:
77
+
78
+ - **primario** — el mejor match global. Se lleva la card.
79
+ - **complementos** — los agentes que cubren lo que el primario NO cubre. Son sus pares en el bus.
80
+ - **sin cubrir** — lo que nadie del panel cubre. Señal de que la card debería partirse en dos.
81
+
82
+ Ejemplo real:
83
+
84
+ ```
85
+ PIDE: react, form, validation, accessibility, frontend
86
+
87
+ PRIMARIO 28% engineering-section-508-specialist
88
+ cubre: form, accessibility
89
+ + COMPLEM. 23% engineering-frontend-developer
90
+ aporta: react, frontend
91
+ ```
92
+
93
+ ### Los 4 artefactos de un agente desplegado
94
+
95
+ Un agente **no arranca sin `misiones.md`**. Nunca.
96
+
97
+ | Artefacto | Contenido |
98
+ |---|---|
99
+ | `ficha.md` | Quién sos: rol, especialidad, origen, vibe |
100
+ | `misiones.md` | Tu misión · lo que ya sabés · lo que NO sabés |
101
+ | `protocolo.md` | Cómo trabajás · tu territorio · qué se espera · límites · éxito |
102
+ | `bus.md` | Tu canal: dónde, formato, TTLs, cómo acusar recibo |
103
+
104
+ Y `briefing.md` con el documento completo, para lectura humana.
105
+
106
+ ### El briefing: orden y mínimo
107
+
108
+ Cada agente recibe un briefing de **10 secciones en orden fijo**. El orden va 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.
109
+
110
+ | # | Sección | Qué le dice |
111
+ |---|---|---|
112
+ | 1 | Quién sos | Rol, especialidad de origen, vibe |
113
+ | 2 | Tu misión | Card, criterios de aceptación numerados, gate |
114
+ | 3 | Lo que ya sabés | Decisiones, restricciones, piezas, trampas |
115
+ | 4 | Lo que NO sabés | Huecos explícitos y a quién preguntarle |
116
+ | 5 | Tu territorio | may_touch / forbidden / prohibiciones de la ficha |
117
+ | 6 | Cómo trabajás | Ciclo, cuándo pedir ayuda, delegar, escalar |
118
+ | 7 | Tu canal | Bus: dónde, formato, TTL, ack |
119
+ | 8 | Qué se espera de vos | handoff.md y evidence.md |
120
+ | 9 | Lo que no podés hacer | Prohibiciones (están en código) |
121
+ | 10 | Cómo se mide que terminaste | Las tres condiciones de terminado |
122
+
123
+ **Mínimo**: las 10 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.
124
+
125
+ **La sección 3 se alimenta del ledger** (`.oficina/context.md`). Es lo que evita repetir lo ya decidido.
126
+
127
+ ---
128
+
129
+ ## El bus
130
+
131
+ ### Layout
132
+
133
+ ```
134
+ .oficina/
135
+ ├── bus/
136
+ │ ├── coord-command/0001-<msgid>.json # canal del Comandante
137
+ │ ├── coord-arch/0001-<msgid>.json # canal del Arquitecto
138
+ │ ├── coord-flow/0001-<msgid>.json # canal del Integrador
139
+ │ └── peer/0001-<msgid>.json # canal general entre pares
140
+ ├── inbox/<agentId>/ # índice de lo que le llegó
141
+ ├── roster.json # quién existe, qué puede, qué hace
142
+ ├── leases/<taskId>.json # lock con TTL
143
+ ```
144
+
145
+ ### Envelope
146
+
147
+ ```json
148
+ {
149
+ "id": "m-0042",
150
+ "seq": 42,
151
+ "from": "e-frontend",
152
+ "to": ["e-architect"],
153
+ "kind": "HELP_REQUEST",
154
+ "subject": "T-03",
155
+ "body": {
156
+ "need": "convertir este componente a streaming SSR",
157
+ "why_me": "tengo el contexto del componente pero no el del server"
158
+ },
159
+ "reply_to": null,
160
+ "in_reply_to": null,
161
+ "ttl_sec": 900,
162
+ "created_at": "2026-10-21T15:04:00Z",
163
+ "priority": "normal",
164
+ "idempotency_key": "T-03-help-request-1",
165
+ "hops": 0
166
+ }
167
+ ```
168
+
169
+ ### Semántica
170
+
171
+ - **Append-only**: los mensajes nunca se borran, se archivan. `seq` es monótono por canal.
172
+ - **Escritura atómica**: write a `.tmp` + `rename` → nunca hay un JSON partido en el read.
173
+ - **Polling, no push**: cada agente hace `glob` de su inbox cada N turnos.
174
+ - **Ack**: el receptor escribe `inbox/<agentId>/<msgid>.ack`. El emisor ve quién leyó.
175
+ - **TTL**: mensaje expirado = invisible para nuevos lectores, sigue en el log para auditoría.
176
+ - **Idempotency key**: un `HELP_REQUEST` con la misma key no se duplica.
177
+ - **Canal `peer` broadcast**: un `HELP_REQUEST` puede ir a `to: ["*"]` para broadcast de "necesito X" al pool, y el primero que puede toma el lease.
178
+
179
+ ### Tipos de mensaje
180
+
181
+ | Kind | Quién lo emite | Para qué |
182
+ |---|---|---|
183
+ | `HELP_REQUEST` | cualquier agente | pedir ayuda a un peer o al pool |
184
+ | `HELP_ACCEPT` / `HELP_DECLINE` / `HELP_PARTIAL` / `HELP_QUESTION` | el que recibe | triage del pedido |
185
+ | `QUESTION` / `ANSWER` | agente ↔ coordinador | consultas de dominio |
186
+ | `SPAWN_REQUEST` / `SPAWN_APPROVED` / `SPAWN_REJECTED` | agente ↔ Integrador | gestión de spawns |
187
+ | `CLAIM` / `RELEASE` | agente ↔ Integrador | estado de trabajo |
188
+ | `STATUS` / `NOTICE` | cualquiera | información general |
189
+
190
+ ---
191
+
192
+ ## El protocolo de ayuda
193
+
194
+ ### Cuándo se pide ayuda
195
+
196
+ Un especialista pide ayuda cuando, **en este orden**:
197
+
198
+ 1. La tarea es de otro dominio → pide al peer de ese dominio
199
+ 2. La tarea es de otro dominio y **ese peer no está desplegado** → **despliega uno**
200
+ 3. La tarea está en su scope pero ve que otro lo haría mejor → pide
201
+ 4. Está bloqueado por una dependencia → pide al dueño del lease
202
+
203
+ ### El que recibe evalúa (no acepta por cortesía)
204
+
205
+ Al recibir un `HELP_REQUEST`, el receptor **hace su propio triage**:
206
+
207
+ ```
208
+ 1. ¿Entiendo la tarea? → si no: HELP_DECLINE + explicar
209
+ 2. ¿Está en mi scope/ficha? → si no: HELP_DECLINE + sugerir a quién
210
+ 3. ¿Puedo hacerlo YA sin romper mi
211
+ propia card en curso? → si no: HELP_DECLINE + "cuando termine"
212
+ 4. ¿Tengo el contexto necesario? → si no: HELP_QUESTION (pregunta de vuelta)
213
+ 5. ¿Vale la pena? (costo vs. valor) → si no: HELP_DECLINE + alternativa
214
+ 6. ¿Puedo con mi presupuesto? → si no: HELP_DECLINE + "sin presupuesto"
215
+ ```
216
+
217
+ | Respuesta | Cuándo | Payload |
218
+ |---|---|---|
219
+ | `HELP_ACCEPT` | Puede y corresponde | `scope`, `deadline`, `needs_from_me` |
220
+ | `HELP_DECLINE` | No puede o no le corresponde | `reason`, `alternative`, `available_at` |
221
+ | `HELP_PARTIAL` | Puede una parte | `can_do`, `cannot_do`, `split_suggestion` |
222
+ | `HELP_QUESTION` | No entiende o falta info | `question` — ida y vuelta máximo 2 turnos |
223
+
224
+ **Anti-deadlock**: una cadena de ayuda (A pide a B, B pide a C) tiene **máximo 2 saltos**. Si se excede, el pedido escala al coordinador de flujo.
225
+
226
+ **Anti-monotonía en la ayuda**: la rotación de revisor se extiende a la ayuda. Si el mismo par (A↔B) ya se ayudaron 2 veces, el tercer pedido se enruta a un tercero.
227
+
228
+ ---
229
+
230
+ ## Política de spawn
231
+
232
+ Un especialista puede desplegar un subagente nuevo **solo si**:
233
+
234
+ 1. El rol buscado **no está en el roster activo** (no duplicar)
235
+ 2. El rol sale de `agency-agents` por catálogo, o de factory con cobertura ≥ 60%
236
+ 3. El presupuesto global lo permite (`max_concurrent`, `max_spawns_total`)
237
+ 4. **El deployment es visible en el roster y en el board** — no es invisible
238
+
239
+ Y **debe reportarlo** al Integrador:
240
+
241
+ ```json
242
+ {
243
+ "kind": "SPAWN_REQUEST",
244
+ "requested_role": "motion-designer",
245
+ "source": {"kind": "agency-agents", "path": "design/motion-designer.md"},
246
+ "reason": "T-03 necesita transiciones que exceden mi scope de CSS",
247
+ "budget": {"spawns_used": 1, "spawns_remaining": 1}
248
+ }
249
+ ```
250
+
251
+ El Integrador **aprueba o rechaza**: si la capacidad ya la cubre un peer desplegado, rechaza y le indica a quién preguntar. Esto mata el "cada agente se clona su propio equipo".
252
+
253
+ **Coherencia clave**: el subagente-account de un subagente es el **mismo `id` de ficha** (no un clon). Hereda la ficha, el bus, el lease, y aparece en el roster. Cuando termina, vuelve al pool de idle.
254
+
255
+ ---
256
+
257
+ ## El pool idle
258
+
259
+ ### Ciclo de vida de un agente
260
+
261
+ ```
262
+ DEPLOYED ──► WORKING ──► (sus cards en DONE) ──► IDLE_AVAILABLE ──► (ayuda) ──► WORKING
263
+ │ │
264
+ └──► BLOCKED (espera input) ──► IDLE_AVAILABLE │
265
+ ▼
266
+ RETIRED (fin de corrida)
267
+ ```
268
+
269
+ ### Registro en el roster
270
+
271
+ ```json
272
+ {
273
+ "id": "e-frontend",
274
+ "state": "idle_available",
275
+ "capabilities": ["react-component-design", "css-architecture"],
276
+ "idle_since": "2026-10-21T15:22:00Z",
277
+ "can_accept": true,
278
+ "lease": null
279
+ }
280
+ ```
281
+
282
+ ### Los tres modos de ayudar
283
+
284
+ 1. **Atender un `HELP_REQUEST` dirigido** (to: ["e-frontend"]) → triage → accept/decline
285
+ 2. **Atender un broadcast** `to: ["*"]` → el primero que acepta **toma el lease** → los demás lo ven ocupado y se retiran
286
+ 3. **Claim proactivo**: si hay work packages sin owner en el board y tu capability matchea el mejor → **reclamás**, avisás al Integrador, y lo hacés. No esperás que te lo asignen.
287
+
288
+ El modo 3 es lo que convierte la oficina de "N agentes en paralelo" a "N agentes que se acomodan solos según la carga".
289
+
290
+ ---
291
+
292
+ ## Leases
293
+
294
+ Un agente que trabaja una card **toma un lease** con TTL. El heartbeat lo extiende. Si el agente muere, el lease expira y la card se reasigna.
295
+
296
+ Sin esto, una card queda trabada por un subagente que murió en silencio.
297
+
298
+ ```
299
+ leases/<taskId>.json
300
+ {
301
+ "taskId": "T-03",
302
+ "agentId": "e-frontend",
303
+ "acquiredAt": "...",
304
+ "expiresAt": "...",
305
+ "heartbeatAt": "...",
306
+ "renewals": 12
307
+ }
308
+ ```
309
+
310
+ **Double-claim**: el lease lo bloquea. Si dos agentes discuten por la misma card, el lease decide — no la discusión.
311
+
312
+ ---
313
+
314
+ ## Deadlock, starvation y agentes muertos
315
+
316
+ | Problema | Señal | Respuesta |
317
+ |---|---|---|
318
+ | **Deadlock** | dos cards se esperan mutuamente | Romper el ciclo: una cede, o partir una. Lo detecta el Integrador. |
319
+ | **Starvation** | una card espera demasiado | Priorizarla o avisar al Comandante. |
320
+ | **Doble claim** | dos agentes en la misma card | El lease lo bloquea. |
321
+ | **Agente muerto** | sin heartbeat en 3× `heartbeat_sec` | Su card se reasigna, su lease expira. |
322
+
323
+ ---
324
+
325
+ ## Arbitraje de los coordinadores
326
+
327
+ ```
328
+ Pregunta de un especialista
329
+ |
330
+ ├─ ¿es de scope/objetivo/prioridad? → COMANDANTE
331
+ ├─ ¿es de diseño/patrón/contrato? → ARQUITECTO
332
+ ├─ ¿es de flujo/lease/gate/calidad? → INTEGRADOR
333
+ |
334
+ └─ ¿cruza dos dominios?
335
+ → ARQUITECTO (decisión técnica) con visto bueno del COMANDANTE
336
+ si tiene impacto de scope; si el Integrador detecta deadlock
337
+ → INTEGRADOR reparte y avisa.
338
+ ```
339
+
340
+ **Las preguntas al coordinador van por el bus**, no por chat. Un especialista nunca interrumpe al humano para preguntar algo que un coordinador puede resolver.
341
+
342
+ Solo llega al humano si:
343
+ - El coordinador no puede decidir (requiere criterio de producto/negocio)
344
+ - Hay conflicto entre dominios que ningún coordinador resuelve
345
+ - Se agotó el presupuesto o hay un bloqueo externo
@@ -0,0 +1,342 @@
1
+ # Protocolo de OFICINA
2
+
3
+ Este documento es la ley de la oficina. Si una regla acá y el criterio propio del agent discrepan, gana el criterio propio del agent — pero debe dejarlo escrito en el artefacto para que el Director pueda corregirlo.
4
+
5
+ ---
6
+
7
+ ## 0. PROJECT_ROOT y OFFICE_DIR
8
+
9
+ Los permisos y las rutas relativas se resuelven contra el **directorio de trabajo de la sesión**, que no siempre es el proyecto. Antes de la primera card:
10
+
11
+ 1. Detectá `PROJECT_ROOT` buscando un marker de proyecto (`package.json`, `pyproject.toml`, `setup.py`, `Cargo.toml`, `go.mod`, `pom.xml`, `build.gradle`, `Makefile`, `.git`) en el cwd, y si no hay, en los subdirectorios de primer nivel.
12
+ 2. `OFFICE_DIR = PROJECT_ROOT/.oficina/`. Si no se puede crear ahí, usá `~/.oficina/<slug>/`.
13
+ 3. **Todos los prompts de delegación llevan el PROJECT_ROOT absoluto.** Decí "todos los paths son relativos a `<PROJECT_ROOT>`" porque los subagentes heredan el cwd de la sesión.
14
+ 4. Anotá el PROJECT_ROOT y el OFFICE_DIR en `board.md` para que una sesión retomada los encuentre sin recalcular.
15
+
16
+ ### La oficina se vigila a sí misma
17
+
18
+ El Verificador, en la fase 6 (diff review), además de buscar debug statements y archivos fuera de scope, **verifica que solo se haya tocado lo que la card autorizaba**. Si un agente modificó archivos fuera de su scope — incluido el Director tocando código de producción — eso es un finding y la card va a REWORK.
19
+
20
+ La oficina no confía en la disciplina: la audita.
21
+
22
+ ---
23
+
24
+ ## 1. Ciclo de vida de una card
25
+
26
+ ```
27
+ TODO ──(deps ok + agente asignado)──> IN_PROGRESS
28
+ │ │
29
+ │ ├──(owner entrega handoff + evidence)──> REVIEW
30
+ │ │ │
31
+ │ │ ┌─────────────────���────┴──────────┐
32
+ │ │ │ Crítico (≠ owner) │
33
+ │ │ │ APROBADO ─────────┐ │
34
+ │ │ │ RECHAZADO ──┐ │ │
35
+ │ │ └──────────────┼─────┘ │
36
+ │ │ │ │
37
+ │ │ Verificador + Guardián
38
+ │ │ │
39
+ │ │ ┌──────────────────┴───────────────┐
40
+ │ │ │ PASS ────────────> DONE │
41
+ │ │ │ FAIL ──> REWORK ─┘ │
42
+ │ │ │
43
+ │ │ Rework 1 → vuelve a IN_PROGRESS (mismo owner, feedback)
44
+ │ │ Rework 2 → REPLAN (Director rehace la card, puede cambiar owner)
45
+ │ │ Rework 3 → ESCALATED (pide decisión al usuario)
46
+ └──────────────────────────────────────────┘
47
+ ```
48
+
49
+ ---
50
+
51
+ ## 2. Artefactos: la memoria de la oficina
52
+
53
+ Una card vive en `.oficina/artifacts/<card-id>/`. Si no hay archivo, no hay hecho.
54
+
55
+ ### `handoff.md` (lo escribe el owner)
56
+
57
+ ```markdown
58
+ # <card-id> — <título>
59
+
60
+ **Owner:** <agente>
61
+ **Estado:** IN_PROGRESS → REVIEW
62
+ **Fecha:** <ISO>
63
+
64
+ ## Qué hice
65
+ <qué se implementó, en concreto>
66
+
67
+ ## Archivos tocados
68
+ - `path/to/file.ts` — <qué cambió y por qué>
69
+ - `path/to/other.ts` — ...
70
+
71
+ ## Decisiones tomadas
72
+ - <decisión> — <rationale>
73
+
74
+ ## Qué quedó afuera
75
+ - <qué NO se hizo y por qué>
76
+
77
+ ## Qué necesita el siguiente
78
+ - <lo que la siguiente card o el usuario debe saber>
79
+ ```
80
+
81
+ ### `evidence.md` (lo escribe el owner)
82
+
83
+ Salida **real** de comandos. Sin cromo, sin "debería funcionar":
84
+
85
+ ```markdown
86
+ # Evidencia — <card-id>
87
+
88
+ ## Comando: `npm test`
89
+ ```
90
+ <salida real pegada>
91
+ ```
92
+ **Resultado:** PASS (23 tests, 0 fail)
93
+ ```
94
+
95
+ Regla: si no pegaste la salida real, la card no tiene evidencia y va a REWORK.
96
+
97
+ ### `review.md` (lo escribe el Crítico)
98
+
99
+ ```markdown
100
+ # Revisión — <card-id>
101
+
102
+ **Revisor:** <agente> (≠ owner)
103
+ **Alcance:** <archivos exactos revisados>
104
+ **Ledger:** <qué se leyó completo, callers leídos, paths compartidos trazados>
105
+
106
+ ## Veredicto: APROBADO | RECHAZADO
107
+
108
+ ## Findings
109
+
110
+ ### [C-001] <título>
111
+ - **Confianza:** 92
112
+ - **Ubicación:** `path/file.ts:42`
113
+ - **Categoría:** Security
114
+ - **Descripción:** <qué está mal>
115
+ - **Escenario de reproducción:** <pasos concretos que lo disparan>
116
+ - **Baseline:** <evidencia de que lo introdujo esta card>
117
+ - **Fix:** <dirección>
118
+ - **Test de regresión:** <dónde va>
119
+
120
+ ## Dimensiones revisadas
121
+ - security: <sí/no — por qué>
122
+ - performance: <sí/no — por qué>
123
+ - architecture: <sí/no — por qué>
124
+ - testing: <sí/no — por qué>
125
+ ```
126
+
127
+ ### `gates.md` (lo escriben Verificador y Guardián)
128
+
129
+ ```markdown
130
+ # Gates — <card-id>
131
+
132
+ ## Técnico
133
+ | # | Fase | Comando | Resultado | Detalle |
134
+ |---|------|---------|-----------|---------|
135
+ | 1 | Build | `npm run build` | PASS | exit 0 |
136
+ | 2 | Type check | `tsc --noEmit` | PASS | 0 errores |
137
+ | 3 | Lint | `eslint .` | FAIL | 3 warnings nuevos |
138
+ | 4 | Tests | `npm test` | PASS | 23/23 |
139
+ | 5 | Sec grep | `grep -rE "AKIA..."` | PASS | 0 |
140
+ | 6 | Diff | `git diff main` | PASS | 4 archivos |
141
+
142
+ **Gate técnico:** FAIL
143
+
144
+ ## Seguridad
145
+ - Trust boundaries: <mapeadas>
146
+ - Input paths auditados: <lista>
147
+ - Secretos: <resultado del escaneo>
148
+ - Dependencias: <resultado>
149
+ - Findings de seguridad: <lista o "ninguno">
150
+
151
+ **Gate seguridad:** PASS
152
+ ```
153
+
154
+ ### `decision.md` (lo escribe el Director)
155
+
156
+ ```markdown
157
+ # Decisión — <card-id>
158
+
159
+ **Decisión:** APROBADA | REWORK | REPLAN | ESCALADA
160
+ **Razón:** <por qué>
161
+ **Siguiente:** <qué card sigue, o qué se le pregunta al usuario>
162
+ ```
163
+
164
+ ---
165
+
166
+ ## 3. Handoff: cómo se coordinan sin hablar
167
+
168
+ El problema: los subagentes son stateless. No se ven entre sí.
169
+
170
+ La solución: **el disco es el bus de mensajes**.
171
+
172
+ ```
173
+ Implementador ──escribe──> artifacts/T-01/handoff.md
174
+ │
175
+ ▼
176
+ Crítico ──lee──────> artifacts/T-01/handoff.md + artifacts/T-00/handoff.md
177
+ │
178
+ ▼
179
+ artifacts/T-01/review.md
180
+ │
181
+ ▼
182
+ Verificador ──lee──────> artifacts/T-01/{handoff,evidence,review}.md
183
+ │
184
+ ▼
185
+ artifacts/T-01/gates.md
186
+ │
187
+ ▼
188
+ Director ──lee──────> artifacts/T-01/*.md → actualiza board.md + state.json
189
+ ```
190
+
191
+ **Regla de lectura:** antes de empezar una card, el agente lee **todos** los `handoff.md` de cards previas que le importen + `context.md`. No pregunta, lee.
192
+
193
+ **Regla de escritura:** cada agente deja su salida en su archivo. Nunca en el chat.
194
+
195
+ ### `.oficina/context.md` — el ledger acumulado
196
+
197
+ ```markdown
198
+ # Contexto de la corrida — <objetivo>
199
+
200
+ ## Decisiones tomadas
201
+ - [T-00] Usamos JWT con refresh tokens porque <razón> (decidido por code-architect)
202
+
203
+ ## Constraints descubiertos
204
+ - [T-01] El proyecto usa Prisma, no SQL directo
205
+ - [T-02] Los tests corren con `npm test` (no `npm run test:unit`)
206
+
207
+ ## Piezas construidas
208
+ - [T-01] `src/auth/login.ts` — endpoint de login, retorna access + refresh
209
+ - [T-02] `prisma/schema.prisma` — modelo User con email único
210
+
211
+ ## Trampas encontradas
212
+ - [T-01] `src/lib/oldAuth.ts` está muerto, no borrar (lo usa `scripts/legacy-migrate.ts`)
213
+
214
+ ## Temas abiertos
215
+ - Falta decidir rate limiting en login
216
+ ```
217
+
218
+ Este archivo es **lo que evita la repetición**. El Director lo actualiza al cerrar cada card.
219
+
220
+ ---
221
+
222
+ ## 4. Gates de calidad (quality bar)
223
+
224
+ De la skill `verification-loop`. El Verificador corre las 6 fases.
225
+
226
+ **Reglas:**
227
+ - Una fase aplicable en FAIL → la card va a REWORK.
228
+ - Una fase no aplicable → `N/A` con el motivo explícito. Ej: "N/A — el proyecto no tiene type checker".
229
+ - Gate técnico y gate seguridad son **independientes**: security PASS + tech FAIL = REWORK.
230
+ - El Crítico y el Verificador son gates distintos. Reviewer ok + build roto = REWORK. Build ok + review con findings = REWORK.
231
+
232
+ **Umbral de confianza de findings:** ≥ 80. Findings por debajo se descartan con la razón anotada (no se borran en silencio).
233
+
234
+ ---
235
+
236
+ ## 5. Escalamiento
237
+
238
+ Escalar es caro. No hacerlo por todo. Reglas:
239
+
240
+ | Situación | Acción |
241
+ |---|---|
242
+ | Card rechazada 1 vez | Rework automático. Sin escalar. |
243
+ | Card rechazada 2 veces | **Replan**: el Director rehace la card — puede cambiar owner, scope, approach, o partirla en dos. Sin escalar. |
244
+ | Card rechazada 3 veces | **ESCALAR**: se le presenta al usuario el objetivo de la card, los 3 intentos, por qué falló, y 2-3 opciones concretas con recomendación. |
245
+ | Dependencia externa (API caída, credencial faltante, decisión de producto) | **ESCALAR** inmediatamente. No reintentar. |
246
+ | Objetivo ambiguo con impacto grande en el diseño | **ESCALAR** antes de construir. |
247
+ | Conflicto entre cards (mismo archivo, approaches incompatibles) | **ESCALAR**. |
248
+ | Presupuesto de cards/agentes agotado | **ESCALAR** con informe de lo alcanzado. |
249
+
250
+ **Formato de escalación:**
251
+
252
+ ```markdown
253
+ ## 🛑 Escalación — <card-id>
254
+
255
+ **Objetivo de la card:** ...
256
+ **Qué intenté:** 3 intentos (resumen de 1 línea cada uno)
257
+ **Por qué no avanza:** <causa raíz>
258
+ **Archivos en juego:** ...
259
+
260
+ **Opción A:** <qué hacer> — <trade-off>
261
+ **Opción B:** <qué hacer> — <trade-off>
262
+ **Opción C:** <qué hacer> — <trade-off>
263
+
264
+ **Mi recomendación:** <Opción X> porque <razón>
265
+ ```
266
+
267
+ Nunca escalar con un monólogo. Siempre con opciones.
268
+
269
+ ---
270
+
271
+ ## 6. Checkpoints (control pane)
272
+
273
+ Cada 3 cards completadas → informe al usuario:
274
+
275
+ ```markdown
276
+ ## 🏢 Checkpoint — <n>/<total> cards
277
+
278
+ **Objetivo:** <objetivo original>
279
+ **Progreso:** <n>/<total> cards DONE
280
+
281
+ | Card | Estado | Owner | Gates | Revisión |
282
+ |------|--------|-------|-------|----------|
283
+ | T-00 | DONE | code-explorer | ✅ | APROBADO |
284
+ | T-01 | IN_PROGRESS | general | — | — |
285
+ | T-02 | BLOCKED | general | ❌ | RECHAZADO |
286
+
287
+ **Bloqueos:** <ninguno | lista con owner y acción>
288
+ **Siguiente:** <qué sigue>
289
+ ```
290
+
291
+ El checkpoint **no pide permiso**. Informa y sigue. Solo frena si hay una escalación.
292
+
293
+ ---
294
+
295
+ ## 7. Informe final de entrega
296
+
297
+ ```markdown
298
+ # 🏢 OFICINA — Informe de entrega
299
+
300
+ **Objetivo:** <objetivo original>
301
+ **Fecha:** <ISO>
302
+ **Resultado:** CUMPLIDO | PARCIAL | BLOQUEADO
303
+
304
+ ## Trabajo entregado
305
+ | Card | Qué entregó | Owner | Evidencia |
306
+ |------|-------------|-------|-----------|
307
+ | T-00 | Mapa de auth existente | code-explorer | artifacts/T-00/ |
308
+
309
+ ## Gates finales
310
+ - Técnico: PASS/FAIL (<fases>)
311
+ - Seguridad: PASS/FAIL (<hallazgos>)
312
+ - Revisiones: <n> APROBADAS, <n> RECHAZADAS
313
+
314
+ ## Archivos tocados
315
+ - <lista>
316
+
317
+ ## Decisiones clave
318
+ - <decisión> — <razón>
319
+
320
+ ## Qué NO se hizo
321
+ - <alcance excluido> — <por qué>
322
+
323
+ ## Deuda técnica dejada
324
+ - <deuda> — <por qué se aceptó>
325
+
326
+ ## Recomendaciones
327
+ - <qué haría distinto la próxima vez>
328
+ ```
329
+
330
+ ---
331
+
332
+ ## 8. Recuperación tras reinicio
333
+
334
+ Si la sesión se corta a mitad de una corrida:
335
+
336
+ 1. Leer `.oficina/state.json` → obtener card actual, iteración, contadores
337
+ 2. Leer `.oficina/board.md` → ver el panorama
338
+ 3. Buscar artifacts de la card en curso: si hay `handoff.md` pero no `review.md` → la card está en REVIEW, delegar al Crítico
339
+ 4. Si no hay artifacts → la card está en IN_PROGRESS, reasignar al owner
340
+ 5. `context.md` mantiene el conocimiento acumulado
341
+
342
+ **Nunca arranques de cero si existe `.oficina/`.**