docket
The test suite was how CI governed code; the contract is how humans govern agents.
ELI5
What's the problem? You tell your agent "never break the public API", "keep it under 2000 lines", "page within 60 seconds". The rule holds — for that one task. Next session, new agent, fresh context: the rule only survives if somebody repeats it. Tests guard your code, but nothing guards the rules themselves — and even a rule that is written down somewhere is never re-checked after the next change quietly breaks it. Repeating rules is not enforcing them.
How does this repo solve it? You write the rule down once, as a
small YAML contract with a mechanical check attached, and import it
into your repo's ledger. From then on docket check --all is a gate:
after every change it re-proves exactly the rules the change touched
and leaves the standing proof of untouched rules alone. Green means
"still proven", not "someone remembered to mention it". The parts a
machine can't judge get routed to a named human instead of being
silently dropped.
"But can't the AI just ignore all of this?" Yes — exactly the way a
developer can just never run the tests. And that's fine, because those
are two different failures, and only one of them is deadly. A safety
system can lie from the inside: it says "checked ✓" when nothing
was really checked — that one kills you, because even when everyone
plays along, green means nothing. Docket is built so this cannot
happen: green only ever comes from a check that actually ran, and a
human "looks fine" can never stand in for a missing proof. Or a safety
system can be walked around from the outside: the agent simply
never opens the courtroom. No tool can prevent that (whatever wraps
the agent can be ignored too) — but docket makes it impossible to
hide: every state you see is recomputed from the evidence at that
moment, so an ignored ledger shows stale and unproven the instant
a human glances at it. Closing the walk-around takes one line you
already know: make docket check --all a required CI check, and
"ignore it" stops being an option at the merge. Rule of thumb:
docket guarantees green cannot lie; your CI guarantees nobody ships
without looking.
The longer version
Obligations that must hold across many changes have no home. A change-scoped tool creates requirements while planning a change and archives them when the change completes — the obligation dies with the work that satisfied it. At one-human scale that is survivable. When agents outnumber the humans reviewing them, it is not.
So docket is the repo's courtroom: a file-native ledger of obligations
(contracts), the evidence that satisfies them, and the verdicts that
bind them. Contracts are amortized authority — a handful of
sovereign human decisions, mechanically enforced many times without
re-asking. The human appears at three moments: the glance (status),
the verdict (verdict), the amendment (amend). They decide; they
never score.
Features
- Evidence that knows what it proved. Every check binds to the clause's own declared slice of the repository (a content-hash manifest), its normative text, and its acceptance. Change a file in clause A's slice and only A goes stale — its neighbours keep holding on their original evidence. Restore the exact bytes and the original evidence is admissible again.
- A door, not a linter. Contracts enter through the Accord (admission checks A1–A9): one MUST per clause, born-checkable acceptance, provenance anchors, no qualitative hopes without a number or a residue. Import is atomic — one refusal and nothing becomes law.
- A gate that fails closed.
docket check --allexits non-zero for every active mechanical clause lacking current green proof —unprovenandpending-harnessincluded. An accepted verdict cannot substitute for a passing check, an empty evidence bundle holds nothing, and a command that mutates its own slice while exiting zero is not green. - Qualitative law that decomposes instead of being refused. An intent ("do not overengineer") enters as prose plus mechanically decidable proxies plus a human-verdict residue clause naming its authority. No no-residue escape: full mechanical coverage would claim the statement was never qualitative.
- State is derived, never stored. Git is the database. Every state
you see (
holding,stale,unproven,broken,review, …) is recomputed from law plus history at read time; no status field exists to rot. - Producer-agnostic by construction. Contracts arrive from SFD prototype interviews, compiled regulations, SLAs, legacy suites — the door defines quality, not the producer. If a change would require docket to know who produced or consumes a contract, the change is wrong.
When to use
Reach for docket when an obligation must outlive the changes that satisfy it — compat promises, SLAs, security policies, architecture ceilings, "don't overengineer". It is not a task tracker, not CI, not a spec system, and not a change-lifecycle governor; it deliberately owns no worktrees, no repair loops, and no second definition of done.
Quick Start
You never drive docket by hand — your coding agent does. You sign law, glance at status, and rule on residue; the agent stages, imports, implements, and proves. So the quickest start is watching that split play out for real:
→ The hands-on tutorial builds a tiny task CLI
under docket end to end — prototype, blind round-trip, a leak becoming
law, TDD against PENDING-HARNESS, a broken clause refusing to go
green, and the one human verdict. Every transcript in it is from a
real run played against Claude agents. 20–30 minutes to replay with
your own agent.
The short version of who does what:
- Your agent runs the loop: stage the contract,
docket import(the door writes the law),docket tasks --next, implement,docket check --all,docket file. - You glance and rule:
docket status,docket verdict,docket amend— signature, judgment, and law changes stay human.
(The repo's own live example is .contracts/docket.contract.yaml —
docket governing itself.)
Install
Two roads, same destination: both end with the agent skill wired into
your repo (.agents/skills/docket/ as real files, plus the
.claude/skills/docket link) and the tool itself one uvx away.
Road 1 — uv (Python side). The package carries the skill;
docket init materializes it:
uvx --from docket-ledger docket init
(The PyPI distribution is docket-ledger — PyPI prohibits the bare
name — but the tool you get is plain docket.)
Until the PyPI release — or against the private repo — point uvx at the
source; uv clones through the system git, so gh's credential helper
(gh auth setup-git) or SSH keys authenticate it:
uvx --from git+https://github.com/pyros-projects/docket.git docket init
Without any credentials, use a local checkout:
uvx --from /path/to/docket docket init — the skill asks for that path
when the other routes fail.
Road 2 — the skills CLI (Node side):
npx skills pyros-projects/docket
Inside this repo:
uv sync
uv run docket --version
Supported: Linux and macOS, with Python ≥ 3.12, git, and bash on PATH (acceptance commands run through bash — see the trust model below). On Windows, use WSL.
The contract file
Law is YAML: one contract, monotonically numbered clauses, each with exactly one RFC-2119 obligation, a born-checkable acceptance, and provenance anchors. The full schema-by-example lives in concepts/01.
contract: ops
rev: 1
source: "compiled from the on-call SLA §4"
signed: []
intents:
- id: I-001
statement: >
Incidents stay survivable: detection fast, recovery rehearsed,
the rest judged by a human.
clauses:
- id: OPS-001
implements: I-001
obligation: >
Alerting MUST page within the contracted latency budget.
acceptance:
metric: "scripts/alert-latency.sh"
threshold: "p95 < 60s"
anchors:
- sla: "on-call SLA §4.2"
scope:
applies_to: [alerting/**]
- id: OPS-002
implements: I-001
obligation: >
The restore drill MUST exit clean from a cold backup.
acceptance:
command: "scripts/restore-drill.sh"
expect: drill restores the reference backup end to end
expect_exit: 0
expect_stdout: '^restore: OK$'
anchors:
- incident: "INC-2041 postmortem"
- id: OPS-003
implements: I-001
obligation: >
pyro MUST verdict the runbook-quality residue the proxies do
not cover.
acceptance:
verdict: human
authority: pyro
anchors:
- sla: "on-call SLA §6"
Three things the door will teach you quickly: a command: acceptance
needs a structured expectation (expect_exit, and/or expect_stdout /
expect_stderr regexes) — prose-only expect: is admitted but can
never go green; a clause's scope.applies_to doubles as its evidence
slice (files, not directories — declare dir/**); and anchors carry
provenance (surface, decision, incident, regulation, sla,
compat, test, policy, legacy, regulation-section).
Commands
| Command | What it does |
|---|---|
docket import <file> |
Admit a contract through the Accord. Atomic: any refusal writes nothing. |
docket check [CLAUSE] | --all |
Run acceptance, record evidence, derive state. The blocking gate: exits non-zero while any active mechanical clause lacks current green proof. |
docket status [--json] |
The glance — derived state of every clause; --json adds record stems per clause for machine consumers. |
docket tasks [--next --json] |
Derived to-do view: clauses minus admissible evidence. |
docket file <clause> --bundle <json> |
File an evidence bundle (append-only, bound to the slice state at filing). |
docket verdict <clause> --bundle <stem> --accept|--reject <type> --by <who> |
The authority rules on a filed bundle. Verdicts hold human clauses; they never substitute for mechanical proof. |
docket amend <clause> --obligation <text> --by <who> |
Change the law on the record: door re-run over the amended contract, rev bump, amendment history the validity floor reads. |
docket audit |
Coverage views — incompleteness made inspectable. |
docket init |
Install the agent skill into this repo (.agents/skills/docket/ + the .claude/skills link) — the uvx twin of npx skills. |
The bundle docket file takes is JSON with five required keys; evidence
entries are objects with at least a string kind and ref (a stuck
claim additionally needs stuck_on):
{
"clause": "OPS-002",
"claim": "satisfied",
"filed_by": "claude-loop#7",
"rev_at_filing": 1,
"evidence": [
{"kind": "test", "ref": "tests/test_restore.py::test_cold_backup", "result": "PASS"},
{"kind": "trace", "ref": "loop transcript #18", "note": "3 iterations, stop=contract-green"}
]
}
Docket binds the slice's content state at filing time itself — the filer's own claims never stand in for it.
How state derives
Evidence is admissible for a clause only if it passes four checks: the
amendment floor (V1), the clause's normative digest (V2), its
acceptance digest (V3), and its subject slice manifest (V4). Failing
only V4 is stale — proven against a prior state of the slice, visible
in history, never silently reused. A mechanical clause is holding iff
its latest admissible check is green; a human clause holds on a current
accepted verdict for an admissible bundle. Everything else fails the
gate.
→ Why and what · Schema and door policy · Surfaces · v0 scope and falsifier
Does the thesis hold?
The kernel's one question — does a contract outlive the changes that
satisfy it? — was answered on a preregistered bench frozen before
the mechanism existed: after a change touching one clause's slice, the
untouched clauses derived holding on exactly their original evidence
records; 11 of 12 injection rows matched the frozen predictions, and
the one mismatch is recorded rather than edited away. The repo also
governs itself: its own YAGNI contract (.contracts/docket.contract.yaml)
gates every change, and was watched refusing a seeded violation before
the first governed change landed.
→ Bench run record · Verdict (DC-0006)
Trust model
Admitted contract YAML is trusted executable code: docket check
runs acceptance commands via bash with the caller's full privileges.
Import is schema admission through the Accord — not authentication and
not a safety review. signed: entries are unverified declarations;
docket verifies no signatures and ships no cryptography. Only import
and check contracts from sources you have reviewed locally.
Repository notes
The courtroom surfaces sketched in the concept docs (docket review,
docket sign) were cut by DC-0003 and stay cut. The agent-facing skill lives in
skills/docket/ — installable with
npx skills pyros-projects/docket; the two producer methodologies
(surface-first, contract-first) are its references. Agent operational memory lives in
memory/; decisions worth reading start at
memory/decisions/DC-0001 and end, currently, at DC-0006.
Metadata
Release files for docket-ledger 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| docket_ledger-0.1.2.tar.gz | 84.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| docket_ledger-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 181.4 kB
Release files / docket_ledger-0.1.2.tar.gz
| Download URL | docket_ledger-0.1.2.tar.gz |
|---|---|
| Size | 84.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a9a52b02bbb6c422dd28a7dc35329a14332ee0c9a25432bff2a1acd42eae80bd
|
|
BLAKE2b-256 checksum How to use checksums |
1ce967d998c3fbbc3e786896ab7c5d88558aad1cdd052244583698b453aeed2c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / docket_ledger-0.1.2-py3-none-any.whl
| Download URL | docket_ledger-0.1.2-py3-none-any.whl |
|---|---|
| Size | 96.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
689ebd54474f71910422aab05479a0cbf0baf84964945c41990cb499db1a274e
|
|
BLAKE2b-256 checksum How to use checksums |
72d791d0d8cf6dcc51d5b9cd0ec5d8d6af3df8fa268df88c612c2741d42c4428
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|