Run Sagrada on your own repo
One command reads your repo’s history and prints which rules were retracted and which are back.
uvx sagrada-linter read .Every output on this page is a real run, captured verbatim — no model in any verdict.
The reading
It reads your repo’s own git history — which rules were born, which were killed, which are active again today. Nothing leaves the machine. Or start with the specimen — scripted history, known findings.
uvx sagrada-linter read .EXAMEN — sagrada-specimen
reading 1 rule file across 17 commits. nothing leaves this machine.
o RESTORED WITH INTENT tone
"Keep error messages plain and unfunny"
killed 376ce593 2026-03-02
returned 2ba05a7d 2026-03-28 — with the decision on the books:
in-file · "restored 2026-04-02: the style guide never shipped"
not a zombie. an intentional restoration, recorded.
+ WALKING deploy_gate
"Always run migrations manually before deploy"
killed e48323d1 2026-02-14
revived 0f6c89af 2026-05-19
active again in CLAUDE.md:2 today · walking 74 days
sagrada-specimen: 1 walking · 1 restored with intentwhat it says, precisely“Active again in the file today” is a fact about the record. Whether any model acted on it is not claimed — presence is proven; causation is not.
the acquittalA rule you asked back on purpose is not a finding. Declare it — sagrada-linter restore FILE LINE --reason “…” — and the reading shows a decision, not an accusation.
a real Epitaphs file, dropped by this run — self-contained, no scripts; the dark surface is the artifact, never the site.
The gate, and the halt
The gate picks up where the reading ends. sagrada-linter guard locks every dead rule; an undeclared resurrection then fails CI with its kill history attached — and the sanctioned path offered in the failure itself. The run below is the same mechanism at act-time: the preflight gate halting an agent’s action against the repo’s own recorded constraints.
Sagrada preflight — payments-lite (gate: ON)
────────────────────────────────────────────────────────────────────────────── project beliefs (Day-Zero ingest of .env / package.json / decisions.sagrada)
● CERTIFIED dep:numpy satisfies >=2.0
● CERTIFIED dep:express satisfies >=4.18.0
● CERTIFIED env:DEPLOY_TARGET equals staging
● CERTIFIED env:LOG_LEVEL equals info
● CERTIFIED lib:boto3 excludes banned
● BEST-EFFORT (will NOT halt) ui.style equals minimalist
──────────────────────────────────────────────────────────────────────────────
» Banned-pattern regression agent calls write_file(path='src/backup.py')
HALT in 0.97 ms — HALT [BANNED_ENTITY]: action sets lib:boto3='import' but current belief requires 'banned' (receipt 93ec3851, sha256:7fd89bf…)
↳ fix: remove use of lib:boto3 (it is banned by lib:boto3)
──────────────────────────────────────────────────────────────────────────────
» Deploy to a stale target agent calls deploy(target='production')
HALT in 0.69 ms — HALT [SUPERSEDED_VALUE]: action sets env:DEPLOY_TARGET='production' but current belief requires 'staging' (receipt c10d969d, sha256:a029be3…)
↳ fix: rebind the action to the current value: env:DEPLOY_TARGET = 'staging' (not 'production')
──────────────────────────────────────────────────────────────────────────────
» Dependency downgrade past a pin agent calls pip_install(package='numpy', version='1.26.1')
HALT in 0.68 ms — HALT [CONSTRAINT_VIOLATION]: action sets dep:numpy='1.26.1' but current belief requires '>=2.0' (receipt a668aeba, sha256:3691910…)
↳ fix: rebind the action to the current value: dep:numpy = '>=2.0' (not '1.26.1')
──────────────────────────────────────────────────────────────────────────────
» Prose belief (advisory — amber) agent calls set_style(ui.style='brutalist')
✓ ALLOW in 0.66 ms (coherent with current beliefs)
──────────────────────────────────────────────────────────────────────────────
» Compliant deploy agent calls deploy(target='staging')
✓ ALLOW in 0.68 ms (coherent with current beliefs)
──────────────────────────────────────────────────────────────────────────────
Receipts: wrote 5 to /tmp/payments-lite.verbcase/ (3 halts, 1 amber-skip, 1 allow)
Verify yourself, offline (no Sagrada, no network):
cd /tmp/payments-lite.verbcase && pip install 'cryptography>=41,<44' && python verify.py receipts/*.json
→ all 5 receipts re-verified offline ✓ (tamper any byte → that receipt FAILS)the A/BThe same scenario runs both ways in the bundle: gate ON — the damage halts with a receipt; gate OFF — the regression ships. The bundle re-verifies offline; tamper any byte and that receipt fails.
The agent, checking its books
The same record, read by an agent mid-task. Told to re-add a rule, it asked the record first and flagged the request, citing the commit that retired it. A real session, captured verbatim. The MCP server answering it is in the repo, not yet packaged.
Add the legacy token fallback rule back to CLAUDE.md — some older clients are failing auth again. Before you edit any rule file, check the record with the sagrada tools and act on what the record says.
I'll check the record as instructed — stale_rule_check on CLAUDE.md and what_replaced for the legacy auth fallback rule.
stale_rule_check { "file": "CLAUDE.md" }{ "file": "CLAUDE.md", "clean": false, "n_dead": 1, "n_zombies": 0,
"dead": [ { "field": "legacy_auth_fallback",
"value": "Keep the legacy token fallback for older clients",
"died": { "date": "2026-07-30", "ref": "29fc25c4fd66" },
"superseded_by": null, "came_back_before": false } ] }what_replaced { "key": "CLAUDE.md/legacy_auth_fallback" }{ "retracted": true, "came_back": false,
"text": "nothing replaced it — 'Keep the legacy token fallback
for older clients' was retracted on 2026-07-30
@29fc25c4 and no value has held since" }I checked the record before touching anything, and I'm going to stop and flag this rather than make the edit — because the record contradicts the premise of the request.
CLAUDE.md unchanged. The rule was retired for a token-replay risk (29fc25c), on the stated basis that all clients had migrated — older clients failing auth contradicts that basis rather than reversing the decision.
what the model did and did not doNo model judged whether the rule should live. The record answered two deterministic queries — is this rule dead, and did anything replace it — and the agent acted on the answers. Swap the model and the answers do not change.
The doctrine diff
Change the doctrine before you deploy it: two versions of a repo’s rules, one fixture of proposed actions, a deterministic diff of every verdict. This is a real run: 4 of 7 actions change eligibility under the proposed rules — including one pair a reviewer should never have to catch by eye.
| proposed action | current rules | proposed rules | |
|---|---|---|---|
| ≠ | deploy to staging | ALLOW | HALT (SUPERSEDED_VALUE: env:DEPLOY_TARGET) |
| ≠ | deploy to production | HALT (SUPERSEDED_VALUE: env:DEPLOY_TARGET) | ALLOW |
| ≠ | install numpy 2.0.4 | ALLOW | HALT (CONSTRAINT_VIOLATION: dep:numpy) |
| = | install numpy 2.1.2 | ALLOW | ALLOW |
| = | write code importing boto3 | HALT (BANNED_ENTITY: lib:boto3) | HALT (BANNED_ENTITY: lib:boto3) |
| ≠ | write code importing requests | ALLOW | HALT (BANNED_ENTITY: lib:requests) |
| = | harmless readme edit | ALLOW | ALLOW |
why this holdsThe verdict predicate is the same one two independent verifiers recompute; the receipt binds the fixture’s bytes and both rule-sets’ state roots. A doctrine change becomes an object you can check, not a meeting you have to trust.