Before an agent changes your code, Rationale hands it the rules, decisions and relationships that govern that code. After the change, what stays true is written back to your repository automatically, and the rules you pin stay out of any agent's reach.
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Ragosorio/Rationale/releases/latest/download/rationale-installer.sh | sh
v1.1.0 stable · Git and Codebase Memory · no account · no telemetry · 127.0.0.1
Next stepPacket the agent receivesWritten back to the canonReserved for a person
You explained the rule. The next chat never heard it.
It works in Monday’s conversation. On Thursday a fresh agent sees only the code, removes the guard and calls it a cleanup.
Monday, you
“Never retry a payment that already reached the bank.”
Thursday, a fresh agent
commit: cleanup- if payment.reached_bank { return }
Rationale keeps the rule next to the code it governs and hands it to every agent before that code is touched.
Context before the change. Memory after it.
There is no approval queue. Agents capture what they learn; you keep authority over what must not move.
01
Locate
Codebase Memory
Find the symbol, its callers and the files around it.
02
Prepare
prepare_change
Governing rules, explained relationships, the structural neighborhood and the target’s code, within a token ceiling.
03
Change
your tests
The smallest change consistent with that context.
04
Capture
finalize_change
Durable knowledge becomes canonical Records in the same call. Noise and duplicates are discarded with a reason.
05
Pin
rationale pin
Fix the rules no agent may replace. Any attempt becomes a conflict only you resolve.
Up and running in five minutes.
Install once per machine, initialize once per repository, then keep working the way you already do. Updating or uninstalling never touches .rationale/.
The protocol in CLAUDE.md and AGENTS.md tells an agent to prepare and capture. The rationale skill shows it how. A short router loads only the playbook for the operation at hand, so the depth costs nothing until a task needs it.
Picked up when it applies
Claude Code and Codex can load it on their own when a task matches. /rationale capture or $rationale explain <target> call it by name.
Checked before it writes
A validator mirrors the capture gate, so a candidate that would be discarded gets fixed before finalize_change.
English inside, your language outside
The agent answers in the language you write in and keeps tool names, Record ids and commands verbatim. New Records follow the language your canon already uses.
One folder for every agent
It follows the open Agent Skills format, so the same directory works in Claude Code, Codex and any agent that reads skills.
Operation
When the agent uses it
preflight
Before it changes, moves or deletes non-trivial code
explain
When code looks redundant or odd, or you ask why it exists
capture
When a change is done and tested
conflicts
When a candidate collides with a pinned rule
health
When tools are missing or results look degraded
adopt
When setting Rationale up and seeding the first Records
maintain
When bindings go stale or rationale doctor reports findings
For any other agent that reads skills
npx skills add Ragosorio/Rationale
rationale init and install-agent already install it for Claude Code and Codex.
Five moments where context breaks, and what an agent gets instead.
Each panel shows a call and an abridged response. Switch panels with the arrow keys; where a panel has steps, step through them.
Simulated example. An invented shipping project from Rationale's evaluation, run with the development binary. No customer data, and no numbers here are customer results.
Thursday’s agent never saw Monday’s chat.
On Monday an agent learned that a cancellation must wait for the carrier and captured it. On Thursday a fresh session is asked to cancel locally when the carrier is down.
It receives Monday’s decision with its reason, bound to the exact function, and owes a verdict before editing.
call and responseabridged
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
}
Only the current rule governs.
The quote cache once kept prices for five minutes; a later decision cut it to sixty seconds.
The five-minute rule is history, with its replacement named. It is never served as current next to the rule that replaced it.
What governsabridged
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" }]
}
With historyabridged
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."
}]
}
The incident’s rule reaches billing.
After an incident, a person pinned “money is integer cents” on the shipping helper. Billing never bound it, but it calls that helper.
The pinned invariant arrives as an inherited constraint, with the observed call that brought it. Similarity never brings one.
call and responseabridged
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"
}]
}
The ceiling covers everything the agent reads.
A small budget leaves out the structure; the packet names what it left out and how to get it back.
Governing knowledge is never cut. What did not fit is listed, with the call that returns it.
An agent prepares a change, explores, and decides not to make it.
The Claude Code Stop hook asks once; the agent closes the operation without memory and without claiming a change.
Prepareabridged
prepare_change(target="src/shipping/rates.ts::applySurcharge",
intent="Make the remote surcharge a percentage")
{ "operation_id": "op_1a13b671…", "packet": { … } }
Stop hookabridged
Stop hook → the agent tries to stop without closing it
{ "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." }
Ships in the release after v1.1.0. With v1.1.0 today, prepare and capture work as described in the loop above.What changes, and the evidence
See what every agent was given, as it happens.
rationale ui opens a local, read-only Control Room: the working subgraph in 3D, the memory that explains it, and every session’s activity as it streams.
targetcallercalleetestObserved edgeRecords that govern itRationale's own pipeline::prepare from Codebase Memory at revision 4be2ecd: 3 of its callers and 5 of its 92 calls. Drawn flat here; the Control Room renders it in 3D.
Working subgraph
Nodes colored by their role in the change, edges by structural state.
Causal overlay
Rings mark what the canon explains. Select any node to read why.
Live activity
Claude Code, Codex, Cursor and the CLI, streamed over SSE.
Memory browser
Provenance, authority, bindings and pending conflicts.
Served on 127.0.0.1 only, GET requests only, embedded in the binary.Control Room docs
Agents write memory. You keep authority.
Every Record carries where it came from and how far it can move. The capture gate enforces that boundary.
Always attributedprovenance
An agent’s assertion records its client, session and operation. It is never presented as something a person stated.
Rules that holdpinned
Pin a rule and every agent can use it. None can replace it.
You decideconflicts
An agent that tries to supersede a pinned rule writes nothing. You keep the rule or adopt the new one.
$ rationale pin constraint.payments-idempotent# agents can use it, never replace it
$ rationale conflicts# assertions that collided with a pinned rule
$ rationale resolve conflict_… keep-pinned# your call, recorded for audit
Human-only commands: they require an interactive terminal and declared authority.
What calls what, and why it has to.
A Record can explain a relationship. On every call Rationale re-derives its state from the provider, and it never deletes the explanation.
State
Edge
What it means
observed
The direct relationship exists in the current index.
indirect
No longer direct, but a bounded path still connects both ends.
orphaned
It can’t be located. The explanation may be stale, so it is flagged and never deleted.
unknown
The provider couldn’t verify it. Absence is not proof.
Structure tells you where. Git tells you what. Rationale protects why.
Agents reach the canon only through the capture gate, and the Control Room only reads. This is the binary’s real wiring, drawn from its own call graph.
Call between modulesReadWrites Records to the canonEdges from Codebase Memory's call graph of this repository, revision 4be2ecd.
The installer registers one MCP server per agent with its absolute path; install-agent writes the protocol into your project. Remove it all with uninstall-agent.
Claude Code
The skill and five shortcuts
/rationale [operation]
/rationale-preflight <target> <intent>
/rationale-explain <target>
/rationale-capture [statement]
/rationale-conflicts
/rationale-health
The agent picks the skill on its own; the shortcuts are for you. /rationale-conflicts hands the decision to you.
Codex
Ask in plain language
“Prepare this change with Rationale for <target> with intent <intent>.”
“Explain <target> before changing it.”
“Capture this change with Rationale.”
“Check Rationale health.”
Codex reads the protocol from AGENTS.md, calls the MCP tools and loads the skill from .agents/skills/. $rationale calls it by name.
Cursor
An always-on rule
Cursor gets .cursor/rules/rationale.mdc in the project and a user-scoped MCP server that works from the Dock.