Saltar al contenido principal

Arquitectura de orquestación

Rapid OS tiene dos capas. El plumbing (rapid spec, rapid run, rapid evidence, rapid eval…) es el motor de gobernanza v3: registros inmutables, contratos, evidencia y evaluación. El porcelain (rapid start, rapid next, rapid check, rapid task, rapid attach, rapid finish, rapid approve, rapid status, rapid abort) es la capa de intención que conduce un run usando el plumbing. Los shortcuts son archivos que enseñan a un agente a seguir ese bucle; el modo avanzado usa el plumbing directamente.

Esta página describe cómo encajan las piezas. Los límites de lo que se ejecuta están en límites del producto.


1. Porcelain sobre plumbing​

Persona / agente ¿quién decide?
│ /rapid-<modo> <objetivo>
▼
Shortcuts y hooks (por harness) enseñan el bucle y vigilan al agente
│ rapid next / start / check / task / attach / finish
▼
PORCELAIN rapid_os/orchestration/ Conductor (puro) + lifecycle (E/S)
│ llama a los registries, nunca a funciones de la CLI
▼
PLUMBING rapid_os/adapters/ SpecRegistry · RunRegistry · EvidenceRegistry · EvalRegistry
rapid_os/domain/ contratos, RunState, RunEvidence, BehavioralEvaluator
▼
.rapid-os/ specs/ runs/ evidence/ evals/ ledger append-only (+ session.json y scratch/)
  • El porcelain no crea otro modelo de datos: cada acción termina en registros del plumbing (specs, runs, estados, evidencia, reportes) con los mismos digests.
  • El ledger es append-only: ningún verbo reescribe archivos bajo .rapid-os/runs, evidence o evals.
  • Un gate humano nunca se reconoce automáticamente (ver sección 8).

2. El bucle​

┌────────────────────────────────────────────────────────────┐
│ │
▼ │
rapid next --json ──► action.kind │
│ │
├─ author_spec ──► redactar la spec ──► rapid start <modo> --spec-file -
├─ run_baseline / activate / verify ──► ejecutar action.command
├─ implement_task ──► implementar ──► rapid check -- <tests> ──► action.after (rapid task done)
│ │
├─ await_human_approval ──► SE DETIENE: una persona ejecuta rapid approve <gate> ──┐
├─ blocked ──► explicar el motivo (p. ej. rapid abort tras un rechazo) │
└─ finish ──► rapid finish ──► veredicto (PASS / PASS_WITH_WAIVERS / FAIL / UNVERIFIED)
▲ │
└──────────────────────┘

rapid next nunca muta el estado: calcula la siguiente acción y se puede repetir. rapid check ejecuta un comando y registra evidencia; rapid finish registra los cambios, reconoce los gates de máquina que ya cumplen las reglas y evalúa el run.


3. El Conductor: una función pura con el evaluador como oráculo​

next_action(contract, state, evidence, playbook, *, evaluator, test_command) (en rapid_os/orchestration/conductor.py) no hace E/S: recibe el contrato, el RunState, la evidencia y el playbook del modo, y devuelve un NextAction. La E/S (leer el ledger, escribir evidencia, ejecutar rapid check) vive en lifecycle.py.

El Conductor no reimplementa las reglas de gobernanza: pregunta al BehavioralEvaluator. Evalúa el run en memoria (evaluator.evaluate(...)) y lee las aserciones (UNVERIFIED, FAIL, PASS) para decidir qué falta.

gate_satisfied(contract, state, evidence, gate_id, *, evaluator) formaliza esa idea: reconoce hipotéticamente el gate (en una copia del estado) y vuelve a evaluar. Si la aserción del gate pasa a PASS, la evidencia ya lo respalda y reconocerlo es seguro; si no, falta evidencia. Así rapid start y rapid finish solo reconocen gates de máquina cuando la evidencia los justifica, y nunca un gate humano.

Orden de las reglas (la primera que aplica gana):

#CondiciónAcción
1El run es terminaldone (con el resultado)
2El run está blockedblocked
3Una revisión humana fue rechazada (changes_requested)blocked con el comando rapid abort: el gate queda en FAIL en ese run
4prepared con gate.baseline pendienterun_baseline (o activate si ya se cumple)
5active con tareas sin terminarimplement_task (reglas del modo: bugfix pide rapid check --expect fail sobre T001; research cierra tareas con --no-check)
6Todas las tareas terminalesrefactor: blocked si bajan los tests pasados respecto a la baseline; una aserción en FAIL → blocked
7Tarea o gate de máquina sin verificar, o la capability tests.execute sin observarverify
8Gates humanos pendientesawait_human_approval
9Todo resueltofinish

Los playbooks (templates/modes/<modo>.json) aportan la plantilla de spec y los textos de cada acción; las reglas específicas de cada modo están en las guías de modo.


4. El esquema de NextAction​

rapid next --json (y rapid start --json, rapid finish --json) devuelven:

{
"schema_version": 1,
"run_id": "booking-availability-r1-run-001",
"mode": "feature",
"action": {
"kind": "implement_task",
"task_id": "T001",
"instructions": "Implementa solo la tarea indicada. Corre los tests con rapid check.",
"command": ["rapid", "task", "start", "T001"],
"after": ["rapid", "task", "done", "T001"]
},
"awaiting_human": ["gate.final-verification"],
"missing": ["task.T001.evidence", "gate.gate.tests.evidence"],
"progress": {"tasks_done": 0, "tasks_total": 1},
"outcome": null
}
CampoSignificado
action.kindauthor_spec, run_baseline, activate, implement_task, verify, await_human_approval, finish, done o blocked
action.commandComando exacto a ejecutar (como lista argv) o null
action.afterComando a ejecutar cuando el agente termina el trabajo de la acción (p. ej. rapid task done) o null
action.task_id, action.gate_idsTarea o gates a los que se refiere la acción (opcionales)
action.spec_templatePlantilla de spec del modo, en author_spec (opcional)
action.workspace_pathWorktree aislado del run, si lo tiene (opcional)
awaiting_humanGates humanos pendientes
missingAserciones del evaluador aún sin cumplir
outcomeVeredicto o resultado, solo cuando kind es done

Los campos opcionales se omiten cuando no se usan, así que la salida de un modo sin worktree no cambia.


5. .rapid-os/session.json​

El porcelain recuerda el run activo en .rapid-os/session.json (rapid init lo añade a .gitignore si existe). No forma parte del ledger y no tiene digest:

CampoSignificado
schema_version, active_run_id, mode, harnessRun activo, modo y harness elegidos
start_headHEAD de git al iniciar; rapid finish registra los cambios contra él
start_untracked (opcional)Archivos sin seguimiento que ya existían al iniciar; rapid finish no se los atribuye al run
workspace_path (opcional)Worktree aislado creado con rapid start --worktree

rapid abort borra el archivo; rapid validate lo comprueba contra el RunRegistry (RAPID1304, RAPID1305). Junto a él, .rapid-os/scratch/ guarda los logs de rapid check y el estado de los hooks; ambos son desechables.


6. Productores de evidencia del porcelain​

Cada verbo que registra evidencia lo hace con un productor identificable:

ProductorQuién lo escribeEvidencia
rapid:checkrapid check, rapid task done, baseline de rapid starttest_result o command_result, con el log como artefacto
rapid:startrapid startworkspace (current o isolated)
rapid:finishrapid finishfile_change con los archivos modificados por el run, sin .rapid-os/ ni artefactos de herramientas (__pycache__, *.pyc, .pytest_cache...); sin cambios reales no se registra
rapid:attachrapid attachartifact con el archivo adjunto, ligado a una tarea
userrapid approve; rapid finish --accept-test-commandreview con el resultado, el revisor, via (rapid:approve o rapid:finish) y, en una aprobación, el tree aprobado
harness:<id>un harness externo, vía rapid evidence addcualquiera; ver los rulesets v2 y v3

rapid evidence add rechaza los productores rapid:* y un review de user (RAPID1430): solo los escriben los comandos de arriba. El registro los sigue leyendo.


7. Ruleset v2​

Los runs creados antes de Rapid OS 3.2 se evalúan con el ruleset v2 (rapid eval run --ruleset {1,2,3}); los runs nuevos registran ruleset_version: 3 en su contrato y se evalúan con el ruleset v3 (ver Evaluaciones de comportamiento): los gates de tests solo aceptan checks que ejecutó Rapid OS con un resumen contado o test_command y un árbol registrado, los gates humanos solo aceptan un review de rapid approve, y lo que no se puede comparar falla cerrado. Ruleset v2:

  • gate.architecture: en feature, bugfix y refactor, si existe architecture.json, el contrato añade este gate de máquina (architecture_check, posterior a la ejecución, obligatorio, no dispensable). rapid next propone rapid check --gate gate.architecture -- rapid arch check y las violaciones son RAPID1420. Ver Arquitectura por stack.
  • expectation: "fail": rapid check --expect fail --task <id> registra un fallo esperado. Genera la aserción reproduction.<tarea> en PASS si el comando falló de verdad (y en FAIL si no), y esa evidencia no cuenta como fallo de la tarea ni sirve de evidencia de gate.baseline o gate.tests. Solo se admite ligada a una tarea (RAPID1320).
  • harness:* no cierra gates humanos: la evidencia de revisión producida por un harness:<id> queda UNVERIFIED para los gates de revisión humana. Solo una revisión de rapid approve (productor user) puede respaldarlos.

8. rapid approve: capas de defensa y su límite​

Aprobar un gate humano exige estas comprobaciones, de la más barata a la más fuerte:

  1. TTY: sin terminal interactiva falla con RAPID1310 (un EOF durante la confirmación se trata igual).
  2. Marcador de sesión: CLAUDE_CODE_CHILD_SESSION=1 rechaza la ejecución.
  3. Ascendencia: si algún proceso ancestro es el binario de Claude Code (claude/claude.exe), falla con RAPID1310 aunque haya TTY y no queden variables.
  4. Confirmación textual: hay que teclear aprobar <gate-id> (dispensar <gate-id> para --waive).
  5. Hooks de Claude Code (opcionales): PreToolUse deniega al agente rapid approve, rapid abort, rapid run gate, rapid evidence add y la edición de .rapid-os/, y deniega quitar las variables de sesión.
  6. Evidencia: la aprobación queda como review con productor user; el evaluador no acepta la de un harness:* (ruleset v2).

Límite conocido. Son defensas de mejor esfuerzo, no una garantía criptográfica. La detección por ascendencia no ve a un proceso que se desacopla de su padre (doble fork, setsid, nohup … &), a un claude.exe renombrado ni a un pid reutilizado; un TTY se puede emular; el análisis de comandos de los hooks no detecta uno construido en tiempo de ejecución; y la identidad del revisor es la que se declara. La regla de fondo no cambia: una persona aprueba, en su propia terminal.


9. Dónde está cada pieza​

PiezaMódulo
Conductor, NextActionrapid_os/orchestration/conductor.py, actions.py
Verbos del porcelain (E/S)rapid_os/orchestration/lifecycle.py, check.py, session.py, workspace.py
Playbookstemplates/modes/*.json, rapid_os/orchestration/playbooks.py
Hooksrapid_os/orchestration/hooks.py (decisión pura), hook_runtime.py, rapid_os/adapters/claude_hooks.py
Shortcutstemplates/shortcuts/*.md, rapid_os/adapters/shortcut_installer.py, rapid_os/adapters/agents/
Ascendencia de procesosrapid_os/core/ancestry.py
Motor de gobernanzaArquitectura v3