Skip to main content

witness-log (Python)

Python bindings for witness-log-core and witness-log-network, built with PyO3/maturin. Same wire format as the Rust crates and the same guarantees: see the root README.md and THREAT_MODEL.md before using this for anything real. Ships type stubs (py.typed).

Install

pip install witness-log

abi3 wheels for Linux x86_64/aarch64 (glibc and musl), macOS x86_64/arm64 and Windows x86_64, Python ≥ 3.9; the same files with SHA256SUMS are on the GitHub release. To build from source: pip install maturin && maturin build --release in this directory.

Quickstart: an agent loop

import witness_log

log = witness_log.open("agent.jsonl")        # create, or resume if it exists

@witness_log.step(log)                       # one line per tool
def transfer_funds(amount_usd: int) -> dict:
    return {"status": "ok", "tx_id": "tx_7ac31"}

transfer_funds(250)                          # two leaves: intent, then result
log.sync()                                   # fsync when you need durability

pii = log.append_memory(b"contact: alice@example.com")
log.forget(pii)        # right-to-be-forgotten: the salt is erased from agent.jsonl.salts
                       # and a marker leaf appended; every earlier proof is unchanged.

dossier = log.to_dossier_json()              # the bundle anyone can verify offline
report = witness_log.verify_dossier_json(dossier, 0.66, log.identity_pubkey_hex())
log.close()

witness_log.open(path, identity_seed=None) creates path with a new identity (or identity_seed, 32 bytes you keep) and resumes it on every later run. The journal is two files, agent.jsonl and agent.jsonl.salts, both 0600; the first line of the journal holds the identity private key, so protect and back up both like key material. A process killed while holding the journal leaves agent.jsonl.lock; on Linux resume clears it when the recorded PID is gone, elsewhere call JournaledLog.force_unlock(path) once you are sure nothing else has it open.

Any dossier produced here verifies with the Rust CLI unmodified:

witness-log verify dossier.json --identity <hex> --directory witnesses.json

That cross-language round trip is what the wire format (spec/SPEC.md) and conformance corpus (/corpus/) exist to guarantee.

Getting WITNESSED

A dossier with no independent cosignatures verifies as unanchored (or consistent_unwitnessed with a directory). To reach witnessed, at least two witnesses with distinct operator_org values in the verifier's directory must cosign the head:

w = witness_log.Witnesser(log, "trusted.json", "agent.jsonl")   # background thread
w.request()                         # never blocks, never raises
if w.flush(timeout=30):             # bounded wait for the current head
    report = witness_log.verify_dossier_json(w.dossier(), 0.66, log.identity_pubkey_hex(),
                                             open("trusted.json").read())
print(w.status())                   # witnessed_size, cosignatures, last_error (structured)

Witnesser follows 409 resyncs, honours Retry-After, backs off when witnesses are down, keeps its state in <journal>.witnesses.json (the CLI's file and format) and refuses to submit a journal that contradicts a head witnesses already cosigned. await w.aflush() in asyncio code; witness_log.submit_round(...) for one synchronous round. The protocol primitives underneath are add_checkpoint_body(old_size) and dossier_from_responses(...) (and their _at(size, ...) forms).

Console scripts

command what it is needs
witness-log-mcp the MCP server (eleven tools) witness-log[mcp]
witness-log-mcp-proxy --name git --journal git.wlog -- mcp-server-git wraps any stdio MCP server and records every tools/call as salted hashes (MCP proxy) stdlib
witness-log-hook / witness-log-hookd a hook for Claude Code (and any host that pipes a JSON event) plus the Unix-socket daemon that holds the journal (Hooks) stdlib

Identity from the environment

Set WITNESS_LOG_IDENTITY_SEED_ENV to the name of an environment variable that holds the identity seed as 64 hex characters, and every witness_log.open() without a seed argument (the package, the MCP server, the proxy, the hook daemon) seals the journal: the header holds only the public key and the seed stays in your secrets manager. Without it the default is still an unsealed journal, which is a key file: 0600, back it up like one, and move to the environment variable before anything leaves a laptop.

export AGENT_KEY=$(python -c 'import os; print(os.urandom(32).hex())')
export WITNESS_LOG_IDENTITY_SEED_ENV=AGENT_KEY

Disclosure

A leaf commits to SHA256(bucket_pad(payload) || salt || index) (SPEC §8). log.disclose(i) returns {"index", "leaf", "payload_hash", "salt"} and, when the journal was opened with store_payloads=True, "payload"; a third party checks it with witness_log.verify_disclosure(leaf, payload, salt_hex) or recomputes witness_log.payload_hash(payload, salt, index). After forget(i) there is nothing to disclose. store_payloads=True keeps payloads in <journal>.payloads (0600), which forget(i) zero-overwrites and rewrites.

Extras

extra gives you
witness-log[mcp] the MCP server: witness-log-mcp (stdio), eleven tools including submit_to_witnesses and audit_this_session
witness-log[langchain] witness_log.integrations.langchain.WitnessLogCallbackHandler
witness-log[openai-agents] witness_log.integrations.openai_agents.WitnessLogHooks
witness-log[crewai] witness_log.integrations.crewai.witness_crewai

Running a witness

WitnessService.new(key_name, seed, state_path, open_enrollment=True) is a witness you can mount in any web framework: hand it the body of each POST /add-checkpoint and send back what it returns. Create its state once with WitnessService.create_state(path); the state file is bound to the witness key and persisted before any cosignature leaves the process. examples/live-network/py_witness.py is a complete 60-line server.

API surface

Everything is typed in python/witness_log/_core.pyi.

witness_log.open(path, identity_seed=None, *, seal=False, store_payloads=False, session="new") JournaledLog: create or resume. session="reuse" returns the object this process already has open; store_payloads keeps an erasable payload sidecar for disclose.
witness_log.step(log, name=None, *, record_result=True, sync=False) Decorator: intent leaf before the call, result (or error) leaf after. Sync and async.
witness_log.canonical_json(value) RFC 8785 (JCS) bytes: the byte form step hashes, reproducible from any JCS library. sorted_json(value) is the pre-0.4.0 encoding.
log.disclose(i) / witness_log.verify_disclosure(leaf, payload, salt_hex) / witness_log.payload_hash(payload, salt, index) SPEC §8 disclosure: hand out one leaf's salt (and payload) and let anyone check it.
log.submit(directory, want=None, min=None, timeout=10) / await log.asubmit(...) One witnessing round, blocking: {"dossier", "verdict", "cosignatures", "contacted", "tree_size", "outcomes"}.
witness_log.identity_seed_from_env() The seed WITNESS_LOG_IDENTITY_SEED_ENV points at, or None.
JournaledLog.create(path, seed) / .create_ephemeral(path) / .resume(path) Explicit constructors; resume returns (log, dropped_trailing_lines).
.append_intent/.append_result/.append_memory(bytes) New leaf index.
.append_handoff_sent/.append_handoff_received(state, counterparty_hex) SPEC §3.1 cross-log binding.
.forget(i) / .can_forget(i) Redaction; works for leaves from earlier sessions.
.salt_hex(i) / .leaf_json(i) / .payload(i) / .enable_payload_store(path=None) / .payload_store_path() / .path() The pieces disclose is built from.
.checkpoint() / .to_dossier_json() / .leaves_json() JSON, SPEC §6 / §9 / §2.
.inclusion_proof(i) → (tree_size, root_hex, path) Check offline with verify_inclusion(...).
.add_checkpoint_body(old_size) / .dossier_from_responses(...) Witness protocol client; _at(size, ...) forms pin an earlier head; .root_hex_at(size).
Witnesser(log, directory, path) / submit_round(log, directory, state_path) Background / one-shot witnessing (see above).
.sync() / .close() / context manager Durability; releasing the lock.
JournaledLog.force_unlock(path) After a crash, when resume cannot tell the holder is gone.
WitnessLog The in-memory core (snapshots, no salt persistence).
WitnessService A tlog-witness witness.
verify_dossier_json(dossier, threshold, identity=None, directory_json=None) The CLI's verifier; report JSON with verdict, identity_pinned, internally_consistent, quorum.
verify_inclusion(leaf_hash_hex, index, tree_size, path, root_hex) RFC 6962 inclusion check.
select_diverse_witnesses(directory_json, subject_pubkey, want) / select_witnesses(...) Pick operator-diverse witnesses from a directory (object or bare list).
witness_entry_independent(...) / witness_entry_project_operated(...) Build directory entries.

Errors: WitnessLogError (base), SignatureError, ContinuityError, MalformedError; I/O failures raise OSError; bad arguments raise ValueError/TypeError. Payloads are bytes.

This crate is intentionally thin: it does not reimplement any serialization logic; every JSON shape here is the Rust crates' own serde output, so it stays in lockstep with spec/SPEC.md by construction.

Metadata

Release files for witness-log 0.4.2

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

Source distribution (sdist)

Source distribution for witness-log 0.4.2
File Size Uploaded
witness_log-0.4.2.tar.gz 354.9 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for witness-log 0.4.2
File
witness_log-0.4.2-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
witness_log-0.4.2-cp39-abi3-musllinux_1_2_x86_64.whl CPython 3.9 abi3 Linux musl 1.2+ x86-64 Details
witness_log-0.4.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
witness_log-0.4.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details
witness_log-0.4.2-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
witness_log-0.4.2-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 5.2 MB

Release files / witness_log-0.4.2.tar.gz

Download URL witness_log-0.4.2.tar.gz
Size 354.9 kB
Tags Source
SHA-256 checksum
How to use checksums
381b57300fea67a293031f674d7fdca6638cb6313e2657f99b390b5595695516
BLAKE2b-256 checksum
How to use checksums
bfd70417a77c778e799165f9c5d7279ea0b14b873057d5c558920a6baa77481d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / witness_log-0.4.2-cp39-abi3-win_amd64.whl

Download URL witness_log-0.4.2-cp39-abi3-win_amd64.whl
Size 744.4 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
47285d7df3228d83ede0e32f1010ad8dfef7f19f94dd9ad59d56b212cb96363b
BLAKE2b-256 checksum
How to use checksums
530b931eabc5a849b24f47e4792a3e6fe81486ac527a3930bcc24df0be2da02e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / witness_log-0.4.2-cp39-abi3-musllinux_1_2_x86_64.whl

Download URL witness_log-0.4.2-cp39-abi3-musllinux_1_2_x86_64.whl
Size 1.0 MB
Tags CPython 3.9 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
408a0abd54b4e79d360e3050fbd1692898730a8fe79872310f79a031b34a3124
BLAKE2b-256 checksum
How to use checksums
6fbfda546e8066568b120f64065df0623ba23192d62542d48f411f874299c20b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / witness_log-0.4.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL witness_log-0.4.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 808.6 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
3a2e469d0af2c11cbe8c59590bcb22c963c2de2177b332e06b75d6240a262b51
BLAKE2b-256 checksum
How to use checksums
6565fb363604a6e20b6d1ba789d6a43febd62cc9ae34a2b5b1adba612f66af7f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / witness_log-0.4.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL witness_log-0.4.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 752.9 kB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
ff15f1b2a2338af94d1cc5005de084b86168cf8f6f5bc55e557c8f9c1cda2f4f
BLAKE2b-256 checksum
How to use checksums
29d8c5c09c5653e5bff4655148ff3c74fbd7333adb8c1b6c8a42ab3cfb45c893
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / witness_log-0.4.2-cp39-abi3-macosx_11_0_arm64.whl

Download URL witness_log-0.4.2-cp39-abi3-macosx_11_0_arm64.whl
Size 725.8 kB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
2dfee39d6e5d6b2f354fdb6bbb988fc1e46458f99c13af12a8054681285b8715
BLAKE2b-256 checksum
How to use checksums
040a8f54b46a757476389adc6f0e848eaf78597cbc190e018b317184b37bd80d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / witness_log-0.4.2-cp39-abi3-macosx_10_12_x86_64.whl

Download URL witness_log-0.4.2-cp39-abi3-macosx_10_12_x86_64.whl
Size 778.6 kB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
3f6a948183ac5bfb5ea5c0ebc227322da3e42c6d1fab516d250242c906db360a
BLAKE2b-256 checksum
How to use checksums
9de8dce8302893be0761ab0a1789f200f90020396e31f35ed735d80837cf6482
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.2 This release

7 release files

0.4.1

7 release files

0.4.0

7 release files

0.3.6

7 release files

0.3.5

7 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