Skip to main content

docket

The test suite was how CI governed code; the contract is how humans govern agents.

Python Tests Kernel verdict


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 --all exits non-zero for every active mechanical clause lacking current green proof — unproven and pending-harness included. 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

A sample flow (the ops contract is illustrative; the repo's own live example is .contracts/docket.contract.yaml):

$ uv run docket import ops.contract.yaml
DOCKET IMPORT — ops rev 1
source: compiled from the on-call SLA
signed: NONE — unsigned law (import is schema admission, not authentication)
admitted: 3
refused: 0
→ .contracts/ops.contract.yaml

$ uv run docket check --all
OPS-001 alert latency MUST stay under ......... green
OPS-002 restore drill MUST pass quarterly ..... green
OPS-003 pyro MUST verdict the runbook residue . verdict: human — route to the authority

$ uv run docket status
DOCKET — ops                                    rev 1 (0 amendments)
  OPS-001 alert latency MUST stay   1 check      ✔ holding
  ...

The loop an agent runs: docket tasks --next --json to pick work, docket file <clause> --bundle <json> to file evidence, docket check to prove it. The loop the human runs: docket status to glance, docket verdict to rule on residue, docket amend to change the law on the record.

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.


Crafted with Readme Craft

Metadata

Release files for docket-ledger 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for docket-ledger 0.1.0
File Size Uploaded
docket_ledger-0.1.0.tar.gz 83.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for docket-ledger 0.1.0
File Interpreter ABI Platform
docket_ledger-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 179.3 kB

Release files / docket_ledger-0.1.0.tar.gz

Download URL docket_ledger-0.1.0.tar.gz
Size 83.5 kB
Tags Source
SHA-256 checksum
How to use checksums
7e2c7d46d186d9dfc1bfe41a43380a8ca4f04b55fab698cc20c30ba63cb4df8d
BLAKE2b-256 checksum
How to use checksums
001b289e48e8a48a5ed5bb42aee1a7bf6c13835d0caf48549ab8b229b34ba9bd
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.0-py3-none-any.whl

Download URL docket_ledger-0.1.0-py3-none-any.whl
Size 95.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0bee3f97c42e387cb411b26c5e4fb4ee6794e73afee75f84f9fddf34edd68460
BLAKE2b-256 checksum
How to use checksums
6f3408950069000337b5e80ba3870dcea358c7ad775e24c263a157186056213d
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 history Release notifications | RSS feed

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page