Escritores paralelos
Escritores paralelos
Objetivos
- Elegir dónde corre cada writer: mismo árbol o worktree aislado.
- Derivar y escribir una superficie de edición válida.
- Transmitir invariantes que un worker no podría descubrir por sí mismo.
- Pasar skills y recoger aprendizajes con el protocolo del proyecto.
Dónde corre cada writer
La regla fue dictada por el mantenedor en una especificación con esta explicación: en otro repositorio puede haber alguien trabajando ya, de modo que se parte siempre de main, y en local se usa lo más sencillo y lo que consuma menos tokens. El resultado:
flowchart TD
A["Unidad paralela"] --> B{"¿Está en otro repositorio?"}
B -->|"Sí"| C["Worktree nuevo basado en el main<br/>de ese repositorio"]
B -->|"No"| D{"¿Necesita el mismo archivo<br/>que otra unidad?"}
D -->|"Sí"| E["Worktrees aislados"]
D -->|"No"| F["Mismo árbol, con superficies<br/>declaradas y disjuntas"]
Nunca se trabaja en una copia que otra persona podría estar usando.
Reglas al compartir el árbol
| Regla | Motivo |
|---|---|
| El parent es dueño de Git | Los workers no hacen add, commit ni operaciones de rama |
| Sin formateadores, generadores ni instalaciones de todo el repositorio | Tocarían archivos de otra unidad |
| Un archivo compartido tiene un solo dueño, o lo edita el parent al final | Evita conflictos dentro del árbol |
| El parent contrasta el diff de cada writer con su superficie | Detecta escrituras fuera de lo permitido |
| Una comprobación de costura al final: la suite completa, una vez | Detecta incompatibilidades entre unidades |
sequenceDiagram
participant P as Parent
participant A as Writer A
participant B as Writer B
P->>A: Unidad A, superficie A, invariantes y verificación
P->>B: Unidad B, superficie B, invariantes y verificación
A-->>P: Resultado y S# cubiertas
B-->>P: Resultado y S# cubiertas
P->>P: Contrastar cada diff con su superficie
P->>P: Editar archivos compartidos
P->>P: Comprobación de costura una vez
P->>P: Crear los commits
Allowed edit surfaces
Un writer acotado se niega a escribir fuera de las superficies permitidas exactas, y se detiene si faltan. Corresponde al parent derivarlas antes de lanzarlo y pasarlas bajo el encabezado ## Allowed edit surfaces.
Formato
## Allowed edit surfaces
src/reports/export.ts
src/reports/export.test.ts
docs/reports/*.md
`docs/guia de uso.md`
## Contexto
Esta prosa ya no forma parte de la lista.
Las reglas de formato son:
- Rutas relativas al repositorio o globs estrechos, una por línea.
- Nunca
., la raíz del repositorio ni una ruta absoluta. - Las rutas con espacios van entre comillas invertidas completas.
- La sección termina en el siguiente encabezado Markdown. Toda línea no vacía antes de ese encabezado debe ser una entrada válida, de modo que la explicación va en otra sección.
- Se listan expresamente los destinos no rastreados preexistentes que el writer puede escribir.
- Se listan los directorios donde se permiten archivos nuevos, si hacen falta.
- Nada más allá de la tarea delegada. La fuente equipara una superficie demasiado amplia con no tener ninguna.
Si no se puede derivar
No se lanza el writer y no se le pide a la persona que escriba rutas. El parent deriva un conjunto candidato con las rutas exactas que tocaría la tarea y lo presenta como una elección para aprobar o declinar. Una pregunta de texto libre sobre qué rutas autorizar no es un escalamiento válido.
Invariantes
Las unidades construidas en paralelo no pueden verse entre sí. La fuente lo destaca: el prompt es el único lugar donde aprenden ciertas reglas.
Each writer prompt names the existing helpers its unit must reuse for shared state (for example the function that adds an entry other commands also add) and the invariants they keep (ordering, uniqueness, validation, normalization).
internal/components/agentguidance/routing.go
Un ejemplo:
## Invariantes
Para agregar una entrada al catálogo, usa `addCatalogEntry()` en `src/catalog.ts`.
Mantiene el orden alfabético y rechaza identificadores duplicados.
No escribas en el archivo del catálogo de forma directa.
Esta regla vale también inline: quien escriba reutiliza la función existente para el estado compartido y nunca reimplementa ese paso.
Anatomía de un prompt para un writer
Reuniendo las secciones que exigen los contratos:
Spec: odd/tasks/csv-export.md, T2, S2. Lee el documento hasta ## Log.
## Allowed edit surfaces
src/reports/export.ts
src/reports/export.test.ts
## Skills to load before work
.claude/skills/go-testing/SKILL.md
## Invariantes
Usa `formatRow()` para serializar: mantiene el orden de columnas.
## Verification
bun test src/reports/export.test.ts
## Known environmental failures
bun test src/legacy/parser.test.ts
| Sección | Quién la define | Efecto |
|---|---|---|
| Referencia a la especificación | Parent | El worker lee la fuente original |
## Allowed edit surfaces | Parent | Límite de escritura |
## Skills to load before work | Parent | Skills que se leen antes de empezar |
## Verification | Parent | Comandos exactos, en primer plano, informados como <comando>: <resultado observado> |
## Known environmental failures | Parent | Fallas ya presentes en la base, con evidencia. Cualquier otra fuerza partial |
La heurística de tamaño también se reenvía: las ~400 líneas siguen siendo solo orientativas para el subagente.
Skills
La sección de registro define cómo llegan los skills a un subagente:
- El parent resuelve los skills una vez por sesión o antes de la primera delegación, leyendo
.atl/skill-registry.md. - Compara el contexto de la tarea con la columna Trigger / description.
- Pasa solo las rutas
Pathque coinciden. - Indica a los subagentes que lean esos
SKILL.mdantes de leer, escribir o probar.
Los subagentes no vuelven a descubrir el registro. Su informe skill_resolution permite detectar fallas de orquestación:
| Valor | Significado |
|---|---|
paths-injected | El parent entregó las rutas exactas |
fallback-registry | El subagente las cargó del registro. Degradado pero auditable |
fallback-path | El subagente cargó rutas explícitas. Degradado pero auditable |
none | No se cargó ningún skill |
Un valor de respaldo se considera una brecha de orquestación, y se corrige en las delegaciones siguientes. El contrato del worker de OpenCode usa además paths-invalid cuando un skill listado no se pudo cargar.
El registro se refresca con gentle-ai skill-registry refresh, o con --force para ignorar la caché.
Key Learnings
Al delegar a un worker genérico de exploración, escritura o verificación, el parent incluye una instrucción de cierre: tras el resultado normal, el worker termina con un bloque ## Key Learnings de 1 a 5 elementos numerados.
| Regla | Valor |
|---|---|
| Contenido | Oraciones factuales autónomas, de al menos 20 caracteres y 4 palabras |
| Ausencia | Se omite si no hay aprendizaje reutilizable |
| Alcance | Solo el texto final, nunca la salida intermedia de herramientas |
| Quién persiste | El proveedor de memoria Engram lo extrae como captura pasiva. El worker no lo analiza ni invoca herramientas |
| Excepción | Los agentes que deben devolver JSON estricto no reciben esta instrucción |
Es independiente de un mem_save explícito.
Actividad
Diseña dos unidades paralelas para un cambio real de tu proyecto:
- Comprueba que cumplen las cuatro condiciones del paralelismo.
- Escribe la superficie de cada una y confirma que son disjuntas.
- Identifica un helper compartido y escribe su invariante.
- Decide quién edita el archivo que ambas necesitarían, por ejemplo un índice de rutas.
Autoevaluación
-
Dos unidades del mismo repositorio necesitan editar el mismo archivo. ¿Qué dice la regla?
- A. Usar worktrees aislados, o asignar un dueño al archivo compartido
- B. Que ambas lo editen y resolver conflictos al final
- C. Prohibir la delegación
- D. Crear dos ramas de larga duración
-
¿Qué entrada es válida en una superficie?
- A.
. - B.
/home/yo/repo/src/app.ts - C.
src/reports/export.ts - D. “Los archivos de reportes”
- A.
-
No puedes derivar la superficie. ¿Qué haces?
- A. Lanzar el writer sin ella
- B. Pedirle a la persona que escriba los globs
- C. Autorizar todo el repositorio de forma temporal
- D. Presentar un conjunto candidato para aprobar o declinar
-
¿Qué es la comprobación de costura?
- A. Revisar el estilo del código
- B. Una ejecución de la suite completa al terminar las unidades paralelas
- C. Una revisión RDD por cada unidad
- D. Comprobar que cada writer leyó su skill
Respuestas
- A. Según la regla de escritores paralelos, los que necesitan el mismo archivo usan worktrees, y en el mismo árbol un archivo compartido tiene un dueño o lo edita el parent.
- C. Debe ser relativa y exacta, o un glob estrecho.
- D. Una pregunta de texto libre sobre rutas no es válida.
- B. “One seam check runs at the end (the full suite, once).”
Lista de control
- Sé cuándo uso el mismo árbol y cuándo un worktree.
- Derivo la superficie antes de lanzar un writer.
- Pongo los helpers e invariantes en el prompt.
- El parent conserva el control de Git.
Fuentes
internal/components/agentguidance/routing.go, internal/assets/skills/_shared/odd-orchestrator-sections.md, internal/assets/opencode/agents/gentle-ai-worker.md, odd/tasks/1731-parity-delegate-for-reason.md, docs/usage.md.