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 intent

what 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.

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.

you
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.
agent
I'll check the record as instructed — stale_rule_check on CLAUDE.md and what_replaced for the legacy auth fallback rule.
→ record
stale_rule_check { "file": "CLAUDE.md" }
← record
{ "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 } ] }
→ record
what_replaced { "key": "CLAUDE.md/legacy_auth_fallback" }
← record
{ "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" }
agent
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.
outcome
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 actioncurrent rulesproposed rules
deploy to stagingALLOWHALT (SUPERSEDED_VALUE: env:DEPLOY_TARGET)
deploy to productionHALT (SUPERSEDED_VALUE: env:DEPLOY_TARGET)ALLOW
install numpy 2.0.4ALLOWHALT (CONSTRAINT_VIOLATION: dep:numpy)
=install numpy 2.1.2ALLOWALLOW
=write code importing boto3HALT (BANNED_ENTITY: lib:boto3)HALT (BANNED_ENTITY: lib:boto3)
write code importing requestsALLOWHALT (BANNED_ENTITY: lib:requests)
=harmless readme editALLOWALLOW

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.