Circuit breaker for AI agents. Predict what should happen, compare against reality, and block the next mutation when they diverge.
Project description
Expectation Ledger
A circuit breaker for AI agents: predict what should happen, compare against what did, and block the next mutation when they diverge.
Expectation Ledger is a zero-dependency Python library that runs inside an AI agent's control loop. Before each action the agent records what it expects; after the action, the result is classified against that prediction; when a high-stakes action contradicts its prediction, a circuit breaker opens and blocks further mutations until a verification step passes.
Most agent safeguards are perimeter controls — ask a human first, or run it in a sandbox. Both limit what an agent can reach. Neither stops an agent from compounding a mistake inside the boundary it was already allowed to operate in, because the agent doesn't know its last action failed. Expectation Ledger closes that gap, in-process, with no model retraining, no prompt engineering, and no external service.
This is not "AI safety" in the alignment sense. It's engineering safety, in the reliability sense — the same principle as a circuit breaker in your house: when something goes wrong, stop the current before it does more damage.
pip install expectation-ledger
How it works
┌──────────────┐ ┌───────────────┐ ┌──────────────┐
│ 1. PREDICT │ ──▶ │ 2. ACT │ ──▶ │ 3. COMPARE │
│ Derive what │ │ Run handler, │ │ Classified │
│ should happen │ │ get result │ │ vs expected │
└──────────────┘ └───────────────┘ └──────┬───────┘
│
┌──────────────▼──────────────┐
│ 4. ENFORCE │
│ Low severity → log/continue │
│ High severity → open breaker│
│ Breaker open → block mutate │
│ Verify pass → close breaker│
└─────────────────────────────┘
Four concepts, zero dependencies:
| Concept | What it is |
|---|---|
| Prediction | What the agent expects to happen — an invariant + success evidence + known failure modes |
| PredictionOutcome | What actually happened — classified as matched, contradicted, or unknown |
| PolicyRule | What to do for each severity × stakes combination (continue, log, board, force-verify) |
| BreakerState | An open/closed circuit breaker — blocks new mutations until verified safe |
Quick start
from expectation_ledger import (
Prediction,
BreakerState,
compare_prediction,
update_breaker,
breaker_blocks,
)
# 1. Before acting: state what you expect
prediction = Prediction(
prediction_id="apply-config-1",
transition="apply_config:nginx",
expected="config file is written and nginx reload succeeds",
invariant="existing unrelated config files are unchanged",
success_evidence="handler returns ok=True with verification status",
failure_modes=["permission denied", "syntax error", "reload failed"],
)
# 2. Act — your agent does something here...
result = {"ok": False, "status": "syntax_error", "error": "unexpected '}' on line 12"}
# 3. Compare
stakes = "high"
outcome = compare_prediction(prediction, result, stakes)
# outcome.result → "contradicted", outcome.severity → "high"
# 4. Enforce
breaker = BreakerState()
breaker = update_breaker(breaker, "apply_config", "nginx", [outcome], None)
# breaker.state → "open"
# 5. Breaker blocks the next mutation
if breaker_blocks(breaker, "apply_config", {"apply_config", "deploy"}):
print("blocked — must verify before mutating again")
# 6. After verification passes, breaker closes
verify_result = {"ok": True, "status": "syntax_check_passed"}
verify_outcome = compare_prediction(
Prediction("verify-1", "verify:dashboard", "syntax check passes", "", "", []),
verify_result,
"high",
)
breaker = update_breaker(breaker, "verify", "nginx", [verify_outcome], None)
# breaker.state → "closed" — agent can mutate again
How it compares
| Capability | Expectation Ledger | Prompt-based guardrails | External approval | Sandbox |
|---|---|---|---|---|
| Runs in-process (no network, no service) | ✓ | ✓ | ✗ | ✗ |
| Structured pass/fail comparison | ✓ | ✗ | — | — |
| Severity routing (low/medium/high) | ✓ | — | — | — |
| Self-blocking (agent stops itself on failure) | ✓ | ✗ | ✗ | — |
| Verified recovery path | ✓ | — | — | — |
| Audit trail (every prediction/outcome recorded) | ✓ | ✗ | ✓ | — |
| Framework-agnostic | ✓ | ✓ | ✓ | ✗ |
Expectation Ledger vs. prompt-based guardrails
Prompt-based guardrails ("think step by step," "verify before answering") are cheap and easy but have no enforcement mechanism — the model can ignore them under pressure or in long contexts. Expectation Ledger is structural: it compares structured output against structured predictions, and the breaker is code, not prose.
Expectation Ledger vs. external approval
Asking a human to approve every action works for low-frequency changes but doesn't scale to an agent that runs dozens of operations per minute. Expectation Ledger is designed for agents that already have operator approval for the category of work they're doing — it catches the unexpected failures inside approved operations, not the decision to operate at all.
Expectation Ledger vs. sandboxing
Sandboxes prevent an agent from reaching beyond a boundary. Expectation Ledger prevents an agent from compounding a mistake inside the boundary. They're complementary — a sandbox limits blast radius; Expectation Ledger stops the agent from chaining errors within that radius.
Using it with your agent
Expectation Ledger is not a service. It's a library you import and call at two points in your agent's control loop:
- Before acting: call your prediction source to generate
Predictionobjects - After acting: call
compare_prediction(), thenevaluate_policy(), thenupdate_breaker()
Two thin adapters ship in the box:
- Hermes —
expectation_ledger.adapters.hermes.build_ledger_context_block()andledger_response_frame_overlay()for response frame integration - OpenClaw / generic —
expectation_ledger.adapters.openclaw.build_context_packet()for pre-model context assembly
For a worked example of wiring Expectation Ledger into a Hermes engineering control loop, see examples/hermes_integration.py.
Expectation Ledger is also available as part of the Memorant suite, where it works alongside Memorant (trusted long-term claims) and Context Tuner (compression audit) for end-to-end agent memory governance. See Memorant and Hermes Context Tuner.
FAQ
What is Expectation Ledger?
Expectation Ledger is an open-source Python library that adds a circuit breaker to an AI agent's control loop. The agent predicts what an action should do, compares the actual result against that prediction, and blocks further mutations when a high-stakes action contradicts what was expected.
How is this different from prompt-based guardrails?
Prompt instructions like "verify before answering" have no enforcement mechanism — a model can ignore them under pressure or in a long context. Expectation Ledger compares structured output against structured predictions, and the breaker is code rather than prose.
Does it replace human approval or sandboxing?
No — it's complementary. A sandbox limits how far an agent can reach; human approval gates whether it acts at all. Expectation Ledger catches unexpected failures inside operations that were already approved, and stops the agent from chaining errors after one.
What is a circuit breaker in this context?
The same pattern used in distributed systems (Hystrix, resilience4j): when an operation fails in a way that suggests further attempts will also fail, the breaker opens and blocks subsequent calls until a health check passes. Here the failure signal is a prediction that was contradicted, and the health check is a verification step.
Does it require an LLM call, a network connection, or a service?
No. Expectation Ledger is a pure-Python library with zero dependencies. It makes no network calls and invokes no model.
Which agent frameworks does it work with?
It's framework-agnostic — two functions called at two points in any control loop. Thin adapters for Hermes and OpenClaw ship in the box; anything else uses the core API directly.
Is Expectation Ledger production-ready?
No. It's alpha (v0.1.0-alpha.x). Core types, severity routing, the policy table, breaker logic, and framework adapters are implemented and tested. Frequency-based prediction sources, similar-prediction retrieval, and breaker persistence are still to come.
Project status
Alpha (v0.1.0-alpha.x). Core types, severity routing, policy table, breaker logic, and framework adapters are implemented and tested. Future work includes frequency-based prediction sources, kNN retrieval for similar-prediction lookup, and breaker persistence backends.
License
Apache License 2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file expectation_ledger-0.1.0a1.tar.gz.
File metadata
- Download URL: expectation_ledger-0.1.0a1.tar.gz
- Upload date:
- Size: 17.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2876b07c809aadf667785b3589f3d9eced9228e0ac597e4ba6491a7665f405b0
|
|
| MD5 |
5bcf3945ee46eeb15ef228b1cd7ee4b1
|
|
| BLAKE2b-256 |
5b55ce679292781b05421444a754fb833b46dbe04db7b04506a871e403162716
|
File details
Details for the file expectation_ledger-0.1.0a1-py3-none-any.whl.
File metadata
- Download URL: expectation_ledger-0.1.0a1-py3-none-any.whl
- Upload date:
- Size: 15.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04fd44492e2aba73ee24a0c59908bc1254a89f5c9d890a9ee06f7df148f9965d
|
|
| MD5 |
6304a5d287758d366ed594624dfc0070
|
|
| BLAKE2b-256 |
8c6c94dee50cb718b80d33599730effc33e6a51ab9e21b362a98e7a22c87e3a0
|