A decision record for AI agents. Signed, hash-addressed, with reasons you can re-run.
When an agent accepts, rejects, or proposes something, it writes a warrant: a small JSON record that says what was decided, under which policy, because of which reasons, based on which evidence — signed by the actor, addressed by its own hash, linked to the decisions that came before it.
{
"decision": "reject",
"subject": { "hash": "d5cf37…", "note": "PR-42" },
"under": [ "cb3a0a… (policy in force, by hash)" ],
"because": [
{ "kind": "check", "check": "05d234…", "runtime": "cmd@v1",
"verdict": "fail", "transcript": "9dc0c3…" },
{ "kind": "prose", "text": "policy clause 1: coverage drops 87.0 -> 84.2" }
],
"evidence": [ "9dc0c3…" ],
"actor": { "id": "agent-b@vendor2" },
"prior": [ "00f79f…" ],
"ts": 1751677200
}The record's hash is its identity. Change one byte of the decision, the policy reference, or the reasons — the hash changes, and every later record that cited it stops resolving. Nothing can be quietly edited after the fact.
A trace tells you what an agent did. A warrant proves why it was allowed to — and the proof survives the agent. Logs are mutable, vendor-shaped prose. Warrants are:
- Immutable — identity is the hash of the content.
- Signed — you know which actor decided.
- Anchored —
underpins the exact bytes of the policy that was in force, not "the policy" in someone's memory. - Re-checkable — a reason can be an executable check. Anyone can re-run it and get the same verdict.
- Linked —
priormakes decisions a chain: propose → reject (with reasons) → revise → accept.warrant why <hash>walks the whole chain.
A rejection is a first-class record, not an absence. This is the part that matters as agents get autonomy: the "no, because" survives, gets cited by hash, and stops the same argument from being re-had from scratch.
git clone https://github.com/s0fractal/warrant && cd warrant
pip install cryptography # the one dependency (Ed25519)
alias warrant="python3 $PWD/impl/warrant.py" # no packaging yet — this is itwarrant init # .warrants/ store in your repo
warrant keygen --out me.key # Ed25519; prints your pubkey
printf 'demo diff\n' > diff.patch # the thing being decided about
POL=$(warrant policy add examples/policy.txt) # pin the rules in force -> hash
P=$(warrant propose --subject diff.patch --under $POL \
--reason "utility fns needed" --actor me@host --key me.key)
R=$(warrant reject $P --check examples/check.sh --verdict fail \
--reason "clause 1: coverage drop" --actor me@host --key me.key)
A=$(warrant accept $R --check examples/check.sh --verdict pass \
--actor me@host --key me.key)
warrant why $A # decision -> reasons -> checks -> policy, verified
warrant verify # every hash, signature, and link in the storeThe store is plain files, content-addressed, git-friendly. No server, no vendor, no account.
Not an agent framework. Not a blockchain. Not observability. It is one file format and five verbs, designed to be boring: any language can implement it from the spec in an afternoon, and two implementations agree on every hash.
SPEC.md — the format (v0.3 draft: the v0.1/v0.2 body schema plus v0.3 settlement, key-state and multi-root rules), canonicalization rules, and worked test vectors with real hashes and signatures (examples/). Reason runtimes: prose, cmd@v1 (a check command run in a container), and — new in v0.2 — ski@v1: a portable, deterministic, budget-bounded check. The check is a content-addressed SKI term evaluated per Σ-GLYPH Book I; the verdict is a hash comparison; work AND peak memory are bounded by the ATP budget, so re-verifying a stranger's reason is safe by construction. warrant check <hash> re-runs one.
impl/warrant.py — reference implementation (M1): the five verbs on a plain-file store, one file, stdlib + Ed25519 (pip install cryptography). It must pass its own law:
python3 impl/warrant.py conformance examples # all SPEC §8 vectors, byte-exact
python3 impl/warrant.py selftest # live round-trip + tamper detectionimpl-go/ — independent Go implementation for cross-checking the spec:
(cd impl-go && go build -o warrant-go .) # stdlib-only; binary is not committed
./impl-go/warrant-go conformance examples # same SPEC §8 vectors
./impl-go/warrant-go selftest examples # schema and verification edgesFirst real user: sigma-glyph files its review adjudications as warrants (.warrants/ in that repo) — the maintainer's accept/reject decisions are signed, hash-addressed, and cite CI gates as cmd@v1 checks.
License: MIT.
Beyond integrity (verify), v0.3 adds settlement semantics (SPEC §5.1/§7/§9):
python3 impl/warrant.py verify --settlement --trust-config trust.json
python3 impl/warrant.py settle <settling-wid> candidate-body.json
./impl-go/warrant-go verify --settlement --trust-config trust.json <store>
# NB: Python takes a global --store flag; Go verify/settle take the store as a
# positional argument — Go is deliberately verify-only (no filing surface).Settlement-active roots come from your local trust configuration (plus
policy-authorized adoptions); genesis.json is advisory and must be pinned to
be used. Re-litigation of a settled subject requires new evidence or a new
outcome fingerprint — prose never re-opens anything. Key rotation/revocation
are warrants; key state derives from the DAG. Both implementations must agree
on every settlement outcome: python3 tests/settlement.py.