Skip to main content

bellbook (Python)

Python bindings for Bellbook: validate tamper-evident, replay-verifiable records of agent activity offline, from Python.

This is a thin PyO3 wrapper over the Rust bellbook crate, which stays the single source of truth for canonicalization, verification, and the conformance vectors. It is not a reimplementation. (The independent from-scratch validator under conformance/python/ in the repository is a separate thing: a deliberate second implementation that exists to cross-check the specification.)

Status

Validation, reading, and writing (issue #13).

Validate

validate(bytes) -> Report reaches the same Clean / Tainted / Invalid decision as the bellbook validate CLI, over the same core.

import bellbook

report = bellbook.validate(open("receipt.json", "rb").read())

print(report.status)          # "clean" | "tainted" | "invalid"
print(report.spec_version)    # "0.3"
print(report.record_count)
print(report.head_hash)       # lowercase hex; compare against an anchored head
print(report.rules_hash)      # compare against rules you trust
print(report.retracted, report.tainted)
print(report.standing)        # {"compromised": [...], "unsound": [...], "restorations": {...}}
print(report)                 # the full human-readable report (same as the CLI)

Validation never raises for a bad receipt: an unparseable or failing receipt returns a Report with status == "invalid" and a problem or reason set. As with the CLI, Clean is relative to the rules embedded in the receipt - compare rules_hash against a rule set you trust.

Read

read(bytes) -> Receipt parses a receipt for inspection. Reading does not verify - call validate for the decision.

import json

receipt = bellbook.read(open("receipt.json", "rb").read())

print(receipt.spec_version, len(receipt))
for r in receipt.records:
    print(r.kind, r.time, r.author_id, r.author_type, r.evidence)
    for ref in r.refs:
        print("  ", ref["type"], "->", ref["target"])
    payload = json.loads(r.payload_json)

A Record exposes id, kind, time, author_id, author_type, signed, evidence, schema, refs, and payload_json. The enum-valued fields (kind, author_type, evidence, and each ref's type) are the record's Rust variant names, e.g. "Candidate", "Provider", "Reported", "Use". read raises ValueError on bytes that are not a parseable receipt.

Write

Writer(log_dir, rules) records evolution to a persistent, single-writer log. It holds the same exclusive lock and runs the same replay-on-commit the Rust LogWriter does. rules is a JSON string: the verifier rules the log is committed under, the same object a receipt embeds under rules.

default_rules(authors, max_context=200, admins=None, reaffirmers=None) builds that string for you - the Python counterpart to bellbook rules init - so you never hand-author a rules object. authors maps an actor id to a role (user, provider, system, executor, or verifier, case-insensitive). admins lists actors allowed to retract records they did not author; reaffirmers, when given, restricts reaffirming selections to the listed actors. Both must also appear in authors:

import bellbook

rules_json = bellbook.default_rules({"agent": "provider", "evaluator": "provider"})
w = bellbook.Writer("./mylog", rules_json)

c0 = w.candidate(author="agent", git_tree="a1b2...")            # a Root candidate
e0 = w.evaluate(author="agent", candidate=c0.id, criterion="builds", passed=True)
s0 = w.select(author="agent", objective="ship it",
              consider=[c0.id], choose=[c0.id], uses_eval=[e0.id])

print(c0.id, c0.accepted, c0.reason)   # each commit returns a Commit

# Export and verify in the same process:
report = bellbook.validate(w.receipt())
assert report.status == "clean"

Each of candidate, evaluate, select, and retract commits one record and returns a Commit (id, accepted, result, reason). A record is durably committed whether accepted or rejected - a rejected record is evidence a proposal was refused - so accepted may be False without an exception. Statically-knowable payload violations (an unregistered author, a score scale above 12, an upgrade whose tree differs from its target) raise ValueError before anything is written.

  • candidate(author, git_tree, *, git_commit=None, algo="sha1", note=None, continues=None, parent=None, derives_from=None, upgrades=None, manifest=None)
    • basis is exactly one of continues (with parent), derives_from (a list of record ids), or upgrades; omit all three for a Root. manifest (a directory path) binds the source by a canonical manifest hash instead of a reported tree. A derives_from member may be a candidate or an evaluation: a repair motivated by an evaluation names it there alongside the candidate it derives from (derives_from=[sound_parent.id, failing_eval.id]), and because Cause carries intent, not taint, retracting that evaluation later does not taint the repair.
  • evaluate(author, candidate, criterion, *, passed=False, failed=False, score=None, scale=None, procedure=None, uses=None) - exactly one of passed, failed, or a score (with scale, a decimal exponent 0-12).
  • select(author, objective, consider, *, choose=None, uses_eval=None, none=False, replaces=None, rationale=None) - exactly one of choose (with uses_eval) or none=True; replaces reaffirms a prior selection. consider, choose, and uses_eval are lists of record ids.

Retract

retract(author, target, reason) asserts a committed record's content is wrong. The target stays in the log; its id enters the retracted set, its epistemic dependents become tainted, and the receipt reports Tainted from then on - permanently. A later reaffirming selection (one that replaces the unsound one on surviving evidence) restores the line's standing, but never turns the receipt Clean again: the episode is part of history, and that is the point.

r = w.retract(author="evaluator", target=e0.id,
              reason="benchmark harness measured the wrong thing")
assert r.accepted
assert bellbook.validate(w.receipt()).status == "tainted"

Retraction is ownership-bound (SPEC section 2): it is accepted only when author is the target's author, or is listed in the rules' admin_retraction_actors (set via default_rules(..., admins=[...])). An Executor may never author a retraction, so Executor-authored records are retractable only through an admin actor. A Verdict or a Retraction cannot be retracted. As with the other verbs, a rejected retraction is still durably committed with accepted == False and the verifier's reason.

The writer is deliberately single-writer (SPEC 5.1): it holds an exclusive lock for the log directory, so a second Writer on the same directory raises. Other useful members: w.head (current head, hex), w.records (the committed records, as Records), len(w), and w.receipt() (portable receipt bytes).

Build from source

pip install maturin
maturin develop            # build and install into the current venv
pytest bindings/python/tests

Prebuilt wheels (Linux, macOS, Windows) are published to PyPI, so pip install bellbook needs no Rust toolchain; the steps above are for local development against the working tree.

Licensed under MIT OR Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bellbook-0.6.0.tar.gz (27.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

bellbook-0.6.0-cp39-abi3-win_amd64.whl (751.0 kB view details)

Uploaded CPython 3.9+Windows x86-64

bellbook-0.6.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (933.1 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

bellbook-0.6.0-cp39-abi3-macosx_11_0_arm64.whl (825.0 kB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

File details

Details for the file bellbook-0.6.0.tar.gz.

File metadata

  • Download URL: bellbook-0.6.0.tar.gz
  • Upload date:
  • Size: 27.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bellbook-0.6.0.tar.gz
Algorithm Hash digest
SHA256 4cf519a9b76a5bc76b4707a09ed40ec547f0a99ffe5a0fc72caad2285115ef4e
MD5 449af12bdce52d6a80de1da3f27f6be0
BLAKE2b-256 f2075f7f9c910f2eb19e767c5b6bf84b97fe27e8fcb0e0d2dfd8c6ea09db6782

See more details on using hashes here.

Provenance

The following attestation bundles were made for bellbook-0.6.0.tar.gz:

Publisher: publish-pypi.yml on bellbook-ai/bellbook

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bellbook-0.6.0-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: bellbook-0.6.0-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 751.0 kB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bellbook-0.6.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 6003f5054e9113d7fb41a21b678928aa164680a4862aa26d59d02e519de5350f
MD5 f17fe7e01f80e7d7bc3ee9056df75e19
BLAKE2b-256 a4c3a441ce7fb7749f5dba39cf33eb1c6b8ed63a989b7b788c5055f06ef1b172

See more details on using hashes here.

Provenance

The following attestation bundles were made for bellbook-0.6.0-cp39-abi3-win_amd64.whl:

Publisher: publish-pypi.yml on bellbook-ai/bellbook

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bellbook-0.6.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for bellbook-0.6.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5171fec0207b846188fbd538cd1443344e8c9fc333ee17687b6d4386fab71487
MD5 83736cec1af3702b21a178686bda7277
BLAKE2b-256 2c0c659248661353612a516e3c2c70b2390cb47a92b42d81d0ddbf8fd4831f1c

See more details on using hashes here.

Provenance

The following attestation bundles were made for bellbook-0.6.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish-pypi.yml on bellbook-ai/bellbook

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bellbook-0.6.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for bellbook-0.6.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3f46aee2a14d19869ca7a4458b614c7ce299f26157d8ae6d932517c35f5818f5
MD5 a14ff64b9c29a94fe5e2dc9f8b6659cf
BLAKE2b-256 cb19b0356f25625fe664a1c797eb64fe289c702d95710c8f1a1c6f6a4f13a584

See more details on using hashes here.

Provenance

The following attestation bundles were made for bellbook-0.6.0-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: publish-pypi.yml on bellbook-ai/bellbook

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.6.0 This release

4 files

0.5.0

4 files

0.4.0

4 files

0.3.0

4 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