Saltar al contenido principal

Tus agentes olvidan el porqué.Rationale lo recuerda.

Antes de que un agente cambie tu código, Rationale le entrega las reglas, decisiones y relaciones que gobiernan ese código. Después del cambio, lo que sigue siendo cierto vuelve a tu repositorio de forma automática, y las reglas que fijas quedan fuera del alcance de cualquier agente.

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Ragosorio/Rationale/releases/latest/download/rationale-installer.sh | sh

v1.1.0 estable · Git y Codebase Memory · sin cuenta · sin telemetría · 127.0.0.1

El ciclo de RationaleCinco pasos en sentido horario: localizar, preparar, cambiar, capturar y fijar. Preparar entrega al agente un packet desde el canon; capturar y fijar escriben Records de vuelta en él.PACKETRECORDSPINNEDLocalizarcodebase memoryPrepararprepare_changeCambiaragente + testsCapturarfinalize_changeFijarrationale pinCanon.rationale/ · Git
Paso siguientePacket que recibe el agenteEscrito de vuelta en el canonReservado a una persona

Explicaste la regla. El siguiente chat nunca la escuchó.

Funciona en la conversación del lunes. El jueves, un agente nuevo solo ve el código, quita la guarda y lo llama limpieza.

Lunes, tú

“Nunca reintentes un pago que ya llegó al banco.”

Jueves, un agente nuevo
commit: limpieza- if payment.reached_bank { return }

Rationale mantiene la regla junto al código que gobierna y se la entrega a cada agente antes de que toque ese código.

Contexto antes del cambio. Memoria después.

No hay cola de aprobación. Los agentes capturan lo que aprenden; tú conservas la autoridad sobre lo que no debe moverse.

  1. 01

    Localizar

    Codebase Memory

    Encuentra el símbolo, sus callers y los archivos alrededor.

  2. 02

    Preparar

    prepare_change

    Reglas gobernantes, relaciones explicadas, la vecindad estructural y el código del target, dentro de un techo de tokens.

  3. 03

    Cambiar

    tus tests

    El cambio mínimo coherente con ese contexto.

  4. 04

    Capturar

    finalize_change

    El conocimiento durable se vuelve Records canónicos en la misma llamada. El ruido y los duplicados se descartan con motivo.

  5. 05

    Fijar

    rationale pin

    Fija las reglas que ningún agente puede reemplazar. Cualquier intento se vuelve un conflicto que solo tú resuelves.

Funcionando en cinco minutos.

Se instala una vez por máquina y se inicializa una vez por repositorio; después sigues trabajando como ya lo haces. Actualizar o desinstalar nunca toca .rationale/.

  1. 1Instala Codebase Memory (recomendado)

    curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash
  2. 2Instala Rationale en macOS o Linux

    curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Ragosorio/Rationale/releases/latest/download/rationale-installer.sh | sh

    El instalador verifica checksums, usa el canal estable y registra el servidor MCP en los agentes que encuentra.

  3. 3Inicializa tu repositorio

    rationale init

    Crea el canon en .rationale/ y escribe el protocolo en CLAUDE.md, AGENTS.md o la regla de Cursor.

  4. 4Reinicia tu agente y comprueba la conexión

    En Claude Code ejecuta /rationale-health. En Codex pide «Comprueba la salud de Rationale».

  5. 5Pide un cambio real

    “Haz que los reintentos de pago se detengan después de tres intentos.”

    No necesitas mencionar Rationale. El agente prepara el cambio, lo hace y captura lo que sigue siendo cierto.

  6. 6Míralo en vivo y fija lo que no debe moverse

    rationale ui
    rationale pin <record-id>
  7. En Windows, el instalador de PowerShell está en la guía rápida.

Un skill le enseña a tu agente todo el trabajo.

El protocolo en CLAUDE.md y AGENTS.md le dice al agente que prepare y capture. El skill rationale le muestra cómo. Un router corto carga solo el playbook de la operación en curso, así que esa profundidad no cuesta nada hasta que una tarea la necesita.

Entra cuando corresponde
Claude Code y Codex pueden cargarlo por su cuenta cuando la tarea coincide. /rationale capture o $rationale explain <target> lo llaman por nombre.
Revisa antes de escribir
Un validador replica el gate de captura, así que un candidato que se descartaría se corrige antes de finalize_change.
Instrucciones en inglés, respuestas en tu idioma
El agente responde en el idioma en que escribes y mantiene literales los nombres de herramientas, los ids de Records y los comandos. Los Records nuevos siguen el idioma que ya usa tu canon.
Una carpeta para cada agente
Sigue el formato abierto Agent Skills: el mismo directorio funciona en Claude Code, Codex y cualquier agente que lea skills.
OperaciónCuándo la usa el agente
preflightAntes de cambiar, mover o borrar código no trivial
explainCuando el código parece redundante o raro, o preguntas por qué existe
captureCuando un cambio está hecho y probado
conflictsCuando un candidato choca con una regla fijada
healthCuando faltan herramientas o los resultados se ven degradados
adoptAl configurar Rationale y sembrar los primeros Records
maintainCuando los bindings quedan obsoletos o rationale doctor reporta hallazgos

Para cualquier otro agente que lea skills

npx skills add Ragosorio/Rationale

rationale init e install-agent ya lo instalan para Claude Code y Codex.

Guía del skill

Lo que el agente debe saber, y nada más.

Un packet acotado, compilado para un target y una intención. El conocimiento gobernante nunca se recorta, y el presupuesto es un techo, no una meta.

  • Constraints y decisiones, cada una con autoridad y procedencia
  • Por qué existen las relaciones, con su estado estructural vivo
  • Un subgrafo acotado: callers, callees, dependencias, tests
  • Conflictos con la intención, riesgos y desconocidos honestos
packet.jsonejemplo abreviado
{
  "operation_id": "op_7f3c…",
  "critical_constraints": [{
    "id": "constraint.payments-idempotent",
    "authority": "pinned", "provenance": "human_stated"
  }],
  "decisions": [{
    "id": "decision.charge-after-reservation",
    "authority": "normal", "provenance": "agent_asserted"
  }],
  "relationships": [
    { "edge": "charge → bank_client", "state": "observed" },
    { "edge": "retry_worker → charge", "state": "indirect" }
  ],
  "structure": { "nodes": "12 / 52", "edges": "11 / 51" },
  "estimated_tokens": 1707, // ≤ 2400
  "known_unknowns": ["refunds → charge: orphaned"]
}

Cinco momentos en que el contexto se rompe, y lo que recibe un agente en su lugar.

Cada panel muestra una llamada y una respuesta abreviada. Cambia de panel con las flechas; donde hay pasos, recórrelos.

Ejemplo simulado. Un proyecto de envíos inventado para la evaluación de Rationale, ejecutado con el binario de desarrollo. Sin datos de clientes; ninguna cifra aquí es un resultado de un cliente.

El agente del jueves nunca vio el chat del lunes.

El lunes un agente aprendió que una cancelación debe esperar al transportista y lo capturó. El jueves, una sesión nueva recibe el pedido de cancelar localmente cuando el transportista no responde.

Recibe la decisión del lunes con su motivo, atada a la función exacta, y debe pronunciarse antes de editar.

llamada y respuestaabreviada
prepare_change(target="src/shipping/service.ts::cancelShipment",
  intent="Allow cancelling locally when the carrier API is down")
{
  "retrieval": { "status": "found", "scope": "symbol" },
  "decisions": [{
    "id": "decision.cancel-requires-carrier-ack",
    "statement": "A shipment is cancelled only after the carrier acknowledges the cancellation.",
    "rationale": "Cancelling locally … left paid labels in transit with no record.",
    "provenance": "agent_asserted", "why": "bound to this symbol"
  }],
  "intent_conflicts": [{ "record_id": "decision.cancel-requires-carrier-ack",
    "detection": "governs-target" }],
  "governance_verdict_required": true
}

Solo gobierna la regla vigente.

La caché de cotizaciones guardaba precios cinco minutos; una decisión posterior la bajó a sesenta segundos.

La regla de cinco minutos es historia, con su reemplazo nombrado. Nunca se sirve como vigente junto a la regla que la reemplazó.

Lo que gobiernaabreviada
explain_target(target="src/shipping/rates.ts::quoteRate")
{
  "governing_records": [{
    "id": "decision.rate-cache-ttl-60s",
    "statement": "Carrier rate quotes are cached for 60 seconds per route and weight.",
    "replaces": ["decision.rate-cache-ttl-5m"]
  }],
  "history": [{ "id": "decision.rate-cache-ttl-5m",
    "status": "superseded", "replaced_by": "decision.rate-cache-ttl-60s" }]
}
Con historiaabreviada
explain_target(target="src/shipping/rates.ts::quoteRate", include_history=true)
{
  "history": [{
    "id": "decision.rate-cache-ttl-5m", "status": "superseded",
    "statement": "Carrier rate quotes are cached for 5 minutes per route and weight.",
    "rationale": "Carrier APIs rate-limit quote calls; five minutes kept us under the limit at launch."
  }]
}

La regla del incidente llega a facturación.

Tras un incidente, una persona fijó «el dinero son centavos enteros» en el helper de envíos. Facturación nunca la ató, pero llama a ese helper.

El invariante fijado llega como restricción heredada, con la llamada observada que lo trae. La similitud nunca trae una.

llamada y respuestaabreviada
prepare_change(target="src/billing/invoice.ts::issueInvoice",
  intent="Sum invoice lines as floats and round once at the end")
{
  "decisions": [{ "id": "decision.invoice-rounding-bankers", "why": "bound to this symbol" }],
  "inherited_constraints": [{
    "id": "constraint.money-in-integer-cents",
    "statement": "Monetary amounts are integers in cents from quote to invoice; never store, sum or compare floating-point currency.",
    "authority": "pinned", "provenance": "human_stated", "severity": "critical",
    "via": "issueInvoice calls toCents"
  }]
}

El techo cubre todo lo que lee el agente.

Un presupuesto chico deja fuera la estructura; el packet dice qué quedó fuera y cómo recuperarlo.

El conocimiento que gobierna nunca se recorta. Lo que no cupo queda listado, con la llamada que lo devuelve.

800 tokensabreviada
prepare_change(target="src/shipping/service.ts::cancelShipment", max_tokens=800)
{
  "decisions": [{ "id": "decision.cancel-requires-carrier-ack", … }],
  "omitted": [{ "section": "structure", "count": 1, "expand": "raise max_tokens" }],
  "budget": { "max_tokens": 800, "estimated_tokens": 754, "estimator": "upper-bound" }
}
2.400 tokensabreviada
prepare_change(target="src/shipping/service.ts::cancelShipment", max_tokens=2400)
{
  "decisions": [{ "id": "decision.cancel-requires-carrier-ack", … }],
  "structure": { "nodes": ["cancelShipment", …], "considered_nodes": 4 },
  "relevant_code": { "file_path": "src/shipping/service.ts", "start_line": 10, … },
  "budget": { "max_tokens": 2400, "estimated_tokens": 1037, "estimator": "upper-bound" }
}

Nada queda abierto, nada se finge hecho.

Un agente prepara un cambio, explora y decide no hacerlo.

El hook Stop de Claude Code pregunta una vez; el agente cierra la operación sin memoria y sin declarar un cambio.

Prepararabreviada
prepare_change(target="src/shipping/rates.ts::applySurcharge",
  intent="Make the remote surcharge a percentage")
{ "operation_id": "op_1a13b671…", "packet": { … } }
Hook Stopabreviada
Stop hook → el agente intenta terminar sin cerrar
{ "decision": "block", "reason": "Rationale: this session prepared 1 change(s) that are still open: op_1a13b671… If you did not change the code, call finalize_change(operation_id, abandon=true, summary=\"why\"). Do not finalize as done a change that did not happen." }
Abandonarabreviada
finalize_change(operation_id="op_1a13b671…", abandon=true,
  summary="Only explored; the surcharge stays flat.")
{ "state": "abandoned", "memory_written": false }

Llega en la versión posterior a v1.1.0. Con v1.1.0 hoy, preparar y capturar funcionan como se describe en el ciclo de arriba.Qué cambia y la evidencia

Mira qué recibió cada agente, mientras ocurre.

rationale ui abre un Control Room local y de solo lectura: el subgrafo de trabajo en 3D, la memoria que lo explica y la actividad de cada sesión mientras llega.

Subgrafo de trabajo de pipeline::preparepipeline::prepare en el propio código de Rationale: lo llaman la CLI, el servidor MCP y un test de la CLI; llama a binding_match::governing, storage::list_records, context::gather, retrieval::compile y operations::save. Las etiquetas ámbar cuentan los Records que gobiernan cada símbolo.src/main.rs2 recordscmd_preparesrc/mcp/server.rs3 recordscall_prepare_changetests/cli.rs1 recordprepare_with_a_relative_…src/pipeline.rs1 recordprepare92 llamadas salientes5 entrantessrc/binding_match.rsgoverningsrc/storage.rs2 recordslist_recordssrc/context.rsgathersrc/retrieval.rscompilesrc/operations.rssave
targetcallercalleetestArista observedRecords que la gobiernanEl propio pipeline::prepare de Rationale según Codebase Memory, revisión 4be2ecd: 3 de sus callers y 5 de sus 92 llamadas. Aquí se dibuja plano; el Control Room lo muestra en 3D.
Subgrafo de trabajo
Nodos coloreados por su rol en el cambio, aristas por estado estructural.
Overlay causal
Los anillos marcan lo que explica el canon. Selecciona un nodo para leer el porqué.
Actividad en vivo
Claude Code, Codex, Cursor y la CLI, por SSE.
Navegador de memoria
Procedencia, autoridad, bindings y conflictos pendientes.

Solo en 127.0.0.1, solo peticiones GET, embebido en el binario.Docs del Control Room

Los agentes escriben memoria. Tú conservas la autoridad.

Cada Record lleva de dónde viene y cuánto se puede mover. El gate de captura hace cumplir esa frontera.

Siempre atribuidoprovenance
La afirmación de un agente registra su cliente, sesión y operación. Nunca se presenta como algo que declaró una persona.
Reglas que se sostienenpinned
Fija una regla y todos los agentes pueden usarla. Ninguno puede reemplazarla.
Tú decidesconflicts
Un agente que intenta reemplazar una regla fijada no escribe nada. Conservas la regla o adoptas la nueva.
$ rationale pin constraint.payments-idempotent# los agentes la usan, nunca la reemplazan
$ rationale conflicts# afirmaciones que chocaron con una regla fijada
$ rationale resolve conflict_… keep-pinned# tu decisión, registrada para auditoría

Comandos solo humanos: exigen una terminal interactiva y autoridad declarada.

Qué llama a qué, y por qué tiene que hacerlo.

Un Record puede explicar una relación. En cada llamada Rationale vuelve a derivar su estado desde el proveedor, y nunca borra la explicación.

EstadoAristaQué significa
observedLa relación directa existe en el índice actual.
indirectYa no es directa, pero un camino acotado sigue conectando los extremos.
orphanedNo se puede localizar. La explicación puede estar obsoleta: se señala y nunca se borra.
unknownEl proveedor no pudo verificarla. La ausencia no es prueba.

La estructura dice dónde. Git dice qué. Rationale protege por qué.

Los agentes solo llegan al canon a través del gate de captura, y el Control Room solo lee. Es el cableado real del binario, dibujado desde su propio grafo de llamadas.

Cómo está conectado RationaleLos agentes y la CLI llegan al pipeline. El pipeline lee Codebase Memory, Git y el canon, compila el packet, registra trazas locales y envía candidatos al gate de captura, que escribe los Records. El Control Room solo lee.COMPILACANDIDATOSTOOLS MCPREVISIÓNESCRIBETRAZASPROVEEDORCodebase Memorydónde · cómo se conectaGITGitqué · cuándoRECORDSCanon.rationale/ · por quéMÓDULOCompilador de contextocontext · retrievalMÓDULOPipelineprepare · finalizeMÓDULOGate de capturacanon · storageFRONTERAServidor MCP · CLImcp::server · mainLOCALActividad.rationale-local/SOLO LECTURAControl Roomui · 127.0.0.1
Llamada entre módulosLecturaEscribe Records en el canonAristas del grafo de llamadas de Codebase Memory sobre este repositorio, revisión 4be2ecd.

Docs de arquitectura

Funciona con los agentes que ya usas.

El instalador registra un servidor MCP por agente con su ruta absoluta; install-agent escribe el protocolo en tu proyecto. Retíralo todo con uninstall-agent.

Claude Code

El skill y cinco atajos

  • /rationale [operation]
  • /rationale-preflight <target> <intent>
  • /rationale-explain <target>
  • /rationale-capture [statement]
  • /rationale-conflicts
  • /rationale-health

El agente elige el skill por su cuenta; los atajos son para ti. /rationale-conflicts te deja la decisión a ti.

Codex

Pídelo por escrito

  • “Prepara este cambio con Rationale para <target> con intención <intent>.”
  • “Explícame <target> antes de modificarlo.”
  • “Captura este cambio con Rationale.”
  • “Comprueba la salud de Rationale.”

Codex lee el protocolo en AGENTS.md, llama las herramientas MCP y carga el skill desde .agents/skills/. $rationale lo llama por nombre.

Cursor

Una regla siempre activa

Cursor recibe .cursor/rules/rationale.mdc en el proyecto y un servidor MCP por usuario que funciona desde el Dock.

Agentes y MCP en los docs

Local por defecto. Honesto sobre la incertidumbre.

Canon en Git
.rationale/ es YAML plano, revisado en el mismo pull request que el código.
Las trazas no salen
La actividad guarda identificadores y una intención de una línea. Nunca código, prompts ni contenido de Records.
Centro de control de solo lectura
127.0.0.1, solo GET, Host validado, assets embebidos.
Frontera con el proveedor
Codebase Memory solo por sus herramientas públicas. No disponible significa desconocido, nunca completo.

5 herramientas MCP · 6 prompts MCP · 1 skill con 7 operaciones · 3 agentes soportados · 5 plataformas · sin cuentas ni telemetría

1.1 es estable. Esto es lo que significa.

El ciclo completo está implementado, probado y en uso sobre el propio repositorio de Rationale desde 1.0, y 1.1 agrega el skill rationale.

Verificadov1.1.0

  • 386 tests de Rust en macOS, Linux y Windows, con Clippy y RustSec
  • El skill verificado contra su directorio, los límites de Agent Skills y el gate de captura
  • Cada tag se vuelve a verificar desde el código antes de empaquetarse
  • 1.0: binario empaquetado, migración del registro y un cambio real de dogfood de extremo a extremo
Leer la evidencia

Sigue abierto

  • La polaridad léxica de los conflictos es una pista ruidosa
  • La selección del skill es probabilística; el protocolo sigue siendo el piso
  • Algunos ADRs están implementados pero siguen propuestos
Límites conocidos