Aesop Kernel

System blueprint

How Aesop works

The shape, and why each part exists. Written so another engineer can build the same shape.

Factual sentences here are traced to rows in SOURCES.md. The source is public at github.com/matt82198/aesop. To run it, go to the guide.

  1. The shape
  2. The receipts loop
  3. Signed receipts
  4. The event store
  5. Crash-only lanes
  6. Gates
  7. Stage lanes
  8. What ships
  9. Patterns to take
  10. Limits and status

01 / The shape

A kernel that runs the loop. You fill in the rest.

Aesop is a kernel. It is not a finished autonomous developer, and it does not know your repositories, rules, or accounts. It ships the parts that run the loop: dispatch, gates, receipts, merge, watchdog, durable state, and a dashboard.

You supply the rest: the list of repositories, your own rules and memory, an optional directory of fleet state, and your keys and accounts.

The Aesop loop An orchestrator dispatches several stateless lanes, each in its own worktree. Lane output passes through gates, then a signed receipt, then merge. Durable state sits beside the loop and a watchdog backs up and scans fleet work. Orchestrator dispatches the wave Lane stateless, own worktree killed, not repaired Lane stateless, own worktree killed, not repaired Lane stateless, own worktree killed, not repaired Gates pre-push checks, secret scan Signed receipt a gate can check it Merge green PRs only Watchdog backup and scan Durable state git, SQLite, files An iteration counts only when it leaves a receipt a gate can check.
Figure 1. The loop. The orchestrator, gates, receipt and merge are the spine; the watchdog and durable state sit beside it.

Durable state lives in SQLite (WAL mode) and in git-committed files. On a crash, the loop starts over from disk, with restart as the recovery path.

The rest of this page takes the parts one at a time, with the reason each one exists.

Read the blueprint page: Quickstart.

02 / The receipts loop

Reports are claims. Receipts are checkable.

An iteration counts only when it leaves a receipt that a gate can check. A lane that reports success without a receipt a gate can verify has not passed.

  1. Dispatch

    A wave is dispatched through driver/wave_loop.py, and each lane works in its own worktree.

  2. Gate

    The pre-push policy runs its checks, including the secret scan that blocks a push, and runs the receipt step last.

  3. Receipt

    tools/emit_receipt.py signs a record of which local checks ran, and the verifier checks it offline.

  4. Merge

    tools/auto_merge.py merges green PRs in batches and fixes conflicts.

Incidents and trap tests

The generated incident ledger counts 41 incidents across eight classes, 3 of them gate-activation and 1 fake-green. Every class count is marked inferred: the rows were classified from commit subjects because the commits carry no incident-class trailer. tests/test_traps.py reproduces patterns of agent deception, such as a test that skips real validation. The classes the ledger defines:

  • Fake-green. Tests reported green but never ran or skipped real validation.
  • Gate-activation. The pre-push secret or verification gate caught an escape or bypass.
  • Doc-invented. Documentation made unverifiable claims, such as hallucinated counts or proofs.
  • Test-pollution. Test config leaked between shards, or state was not isolated.
  • CI-drift. CI workflow state out of sync, such as missing deps, env setup or tools.

The receipt gate is in a measurement period, so the hosted receipt check is not required yet.

Read the blueprint page: The receipts loop, Receipt format.

03 / Signed receipts

Prove what ran, bound to the exact tree.

The loop runs the checks in a throwaway worktree, signs the result, posts it on the head sha, and has a verifier recompute the tree hash from its own checkout.

Emit

The pre-push policy runs check_emit_receipt last, after every other gate has passed. The emitter signs with Ed25519 or HMAC-SHA256 and posts the receipt on the head sha. The receipt tools are standard library, with cryptography optional for Ed25519.

tools/emit_receipt.py

Verify offline

The verifier recomputes the tree hash from its own checkout and never trusts the number in the receipt. It exits 0 for valid, 1 for invalid and 2 when it cannot evaluate.

tools/verify_receipt.py

What it proves

A passing receipt proves that the key holder ran the named parts on that tree and got those exit codes. It does not prove the parts were run honestly.

tools/verify_receipt.py

Offline verification, shown on a real artifact

The provenance record ships with a signed receipt. It signs the sha256 of docs/PROVENANCE.md, the path of that file, and the version, using an Ed25519 key whose public half is committed under tools/receipt_pubkeys/. To check it offline:

python -I tools/emit_provenance_receipt.py --verify docs/PROVENANCE.receipt.json --subject docs/PROVENANCE.md --keyring tools/receipt_pubkeys

The sha256 is taken after folding CRLF line endings to LF, so a Windows checkout with core.autocrlf verifies the same as a Linux checkout. A VALID result means the content of the file is the content the key holder signed. It does not check the commit shas against the repositories.

Read the blueprint page: Signed receipts, Verify a receipt, Receipt format.

04 / The event store

Append-only and hash-chained, tamper-evident but not tamper-proof.

An event store is an append-only JSON Lines log for one project. Each line records prev, the SHA-256 of the previous line's bytes, so a reader can recompute the chain and find an edited, removed or reordered line. That makes the log tamper-evident under verify. It does not make it tamper-proof: verify checks the store against itself and has no outside anchor.

Store core

Schema 2 is the layout for new stores: one chain spans every day file. A directory with day files and no store.json opens as read-only schema 1.

tools/event_store/store.py

Per-project split

migrate.py splits a frozen single log into per-project schema 2 stores. This site does not claim the migration has been run against live data.

tools/event_store/migrate.py

Projections

The project subcommand renders pending items, rulings and checkpoints across stores. A store with a broken chain is reported and skipped.

tools/event_store/project.py

An append-only guard is a pre-commit hook that refuses a commit that deletes, renames, copies or rewrites an existing event line. It runs only in worktrees where it is installed.

The last line is not anchored: no later line stores its hash, so editing only the final line passes verify.

The kernel's durable state layer is state_store/store.py, an append-only SQLite store in WAL mode.

Three hooks from the author's private repositories show the pattern and are not shipped. checkpoint-before-compact.mjs writes state to disk before context is compacted. handback-ledger.mjs writes lane reports to disk. lane-ledger.mjs records lane actions.

Read the blueprint page: Event store, Per-project stores, Verify an event store.

05 / Crash-only lanes

A lane that fails is killed, never corrected.

Model: lanes are stateless processes. A lane that fails is KILLED, never corrected. LANE-CONTRACT.md, line 5

Workers keep no state of their own, and nothing gets repaired in place. When a lane fails, the orchestrator sends it no correction. The question that follows is what the contract failed to specify, and the answer is to amend the contract and dispatch a fresh lane. Failure changes the contract, never the running agent.

Daemons restart from disk

  • Watchdog. It runs a backup and scan cycle every 150 seconds.
  • Halt switch. If a halt sentinel exists, each cycle logs HALTED and skips its work. Halt status that cannot be read also skips the cycle, which is the fail-closed choice for that switch.
  • Self-heal. When the watchdog heartbeat goes stale, self-heal starts the watchdog again, unless a halt is in effect.
  • Durable state. The event store runs SQLite in WAL mode, and git holds the committed work. The watchdog backs up committed and uncommitted fleet work each cycle.

A resume proof that runs offline

The repository includes a demo that runs the wave engine once without interruption as a control, then runs the same wave stopped at a phase boundary and resumed by a second operator. The claim under test is that both end in the same terminal state. It needs no API keys. The certificate it writes carries the date of the run that produced it and is not a current result.

What this does not claim

  • It does not describe stall detection for individual lanes. The watchdog and self-heal logic covers daemons, not lane runs.
  • It does not claim that a killed lane's partial work is recovered on its own.

Read the blueprint page: Crash-only operation.

06 / Gates

Checks that run before a push.

The pre-push policy holds 23 checks, one of them the secret scan that blocks a push. The receipt step runs last, after every other gate has passed.

Secret scan

Blocks a push when staged files contain secrets.

tools/secret_scan.py

Pre-push policy

Runs the push-time checks. The CLI copies it into the hooks of the repo it scaffolds.

hooks/pre-push-policy.sh

Deny, not rewrite (private)

In the author's private operating setup, a hook denies rather than rewrites a subagent dispatch. It is not shipped.

hooks/force-haiku-subagents.mjs

Claim binding (private)

In the author's private operating setup, a hook requires a same-turn evidence read for a claim that something merged or is green. It is not shipped.

hooks/claim-binding.mjs

CI fix catalog

A CI fix is one red CI run matched to one row of a recurring-failure catalog.

docs/CI-CATALOG.md

Read the blueprint page: Gates and hooks, Claim binding, Install the hook, Gates reference.

07 / Stage lanes

A change reaches CI through a pipeline, never one lane.

Each stage is its own dispatch. A brief names exactly one stage, and a stage does not start until the previous hand-back names its output artifact, by path or sha.

  1. S1 SPEC

    In: a row or a ruling. Out: the failing test path and its red output. May write the test file; must not edit non-test files, commit, or push.

  2. S2 IMPL

    In: the S1 test path and red output. Out: a diff file. Must not edit the test, commit, or push.

  3. S3 GATE

    In: the S2 diff. Out: a gate log file. Read-only: no Edit, Write, commit, push, or baseline update.

  4. S4 SHIP

    In: the S3 PASS and a message file. Out: PR number, head sha, armed state. No code edits, no --no-verify, no manual merge.

  5. S5 REVIEW

    Optional; the orchestrator names it. In: the S4 PR diff and the ruling. Out: a review file. Read-only.

The stage contract is text. No checker in the repository is described as enforcing the stage order, and the dispatch hook that denies a multi-stage brief is not in the public repository, so that rule is contract text only.

Read the blueprint page: Stage lanes, Stage matrix.

08 / What ships and what you define

The kernel runs the loop. You supply the rest.

Aesop ships dispatch, gates, receipts, merge, watchdog, durable state, and a dashboard. You provide the repositories, your brain (rules and memory), an optional machinery directory, keys and accounts, and your domain map.

Some files in the repository are examples that show one way to structure the system and are not in the npm package: the root CLAUDE.md, the machinery map, the first-wave replay in examples/first-wave-baseline/, and LANE-CONTRACT.md.

Read the blueprint page: Quickstart.

09 / Patterns to take

The blueprint, as a checklist.

If you build your own, these are the load-bearing patterns and the reason each one exists.

PatternWhy it exists
Receipts before creditA lane that reports success without a receipt a gate can verify has not passed.
Sign what ran, bind it to the treeThe verifier recomputes the tree hash itself. The receipt still does not prove the parts were run honestly.
Hash-chained, append-only eventsA reader can recompute the chain and find an edited, removed or reordered line.
Stateless lanes, killed not correctedFailure changes the contract, never the running agent.
Gates deny, never rewriteThe author's private hook denies a subagent dispatch rather than rewriting it.
Stage lanesSpec, impl, gate, ship and review are separate dispatches, each handing a named artifact to the next.

Read the blueprint page: Documentation home.

10 / Limits and status

What is not finished.

  • Receipt gate. It is in a measurement period; the hosted check is not required.
  • Event log. Tamper-evident under verify, not tamper-proof.
  • Per-project stores. The tooling ships. The live cutover is not claimed.
  • Dependencies. The root package.json has no dependencies key. The receipt tools are standard library, with cryptography optional for Ed25519.
  • Private parts. The lane dispatch hooks and the claim-binding hook are not shipped.
  • Cost figures. Cost comparisons in older docs rest on a private archive. Treat them as author-reported until the data is published.

This page is a blueprint, written by people still working it out. Build on it. The source is public at github.com/matt82198/aesop.

Read the blueprint page: Provenance and evidence, Security policy.