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.1

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.1
File Size Uploaded
witness_log-0.4.1.tar.gz 341.2 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for witness-log 0.4.1
File
witness_log-0.4.1-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
witness_log-0.4.1-cp39-abi3-musllinux_1_2_x86_64.whl CPython 3.9 abi3 Linux musl 1.2+ x86-64 Details
witness_log-0.4.1-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.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details
witness_log-0.4.1-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
witness_log-0.4.1-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 5.1 MB

Release files / witness_log-0.4.1.tar.gz

Download URL witness_log-0.4.1.tar.gz
Size 341.2 kB
Tags Source
SHA-256 checksum
How to use checksums
ce074acd5faf4bd9533567ee8ef5dc683322f8ad088e8888a6aa81cc85cacb25
BLAKE2b-256 checksum
How to use checksums
7129ed63745094d5745c6151047e01e547e7b271e5d94c3e080a6bfcfe73a17e
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.1-cp39-abi3-win_amd64.whl

Download URL witness_log-0.4.1-cp39-abi3-win_amd64.whl
Size 740.5 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
f1af572f88e3749946ebedf13998809a8e28a5069eab40b1d54ee4b2490417dc
BLAKE2b-256 checksum
How to use checksums
b8720f6d1f44a5ec891fac6a0f69880dd0a9ac233214031570f6d30a6df8a450
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.1-cp39-abi3-musllinux_1_2_x86_64.whl

Download URL witness_log-0.4.1-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
75673fedb9943fa1d016c1e3a6046826960c39ea500e5dc1625646568a773320
BLAKE2b-256 checksum
How to use checksums
cc23cf3e93cc4e93fa01757ffc33939bca0e091d891eed976ef29213a0cb3246
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.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL witness_log-0.4.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 803.8 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
bef2916df6accf86963c94db11a031041cb49abdabb12985b2464720618a2221
BLAKE2b-256 checksum
How to use checksums
0c4171857e3240b640e2eac0cb4dfa7c89b4c92926899be459d0561778d11f00
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.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL witness_log-0.4.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 748.4 kB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
7ba085db8bb2d74ff1d0b293317caf81de48387ac7f1940379f920f5037c4d73
BLAKE2b-256 checksum
How to use checksums
2f5ed0d35fcfb219e017f738dfa4d154d60390de9fcdb0376d9997dd06d8a6b7
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.1-cp39-abi3-macosx_11_0_arm64.whl

Download URL witness_log-0.4.1-cp39-abi3-macosx_11_0_arm64.whl
Size 723.4 kB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
2c98fdf27873eed0132616e67c0f50f5f99c20b41d2710f3f31c7d7d3e1be685
BLAKE2b-256 checksum
How to use checksums
e76be2901c67ed00ff46d23fb29294767f01f98d1517769ebc64c0242e7c8877
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.1-cp39-abi3-macosx_10_12_x86_64.whl

Download URL witness_log-0.4.1-cp39-abi3-macosx_10_12_x86_64.whl
Size 775.3 kB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
4c29ee87fd2766dc8f55ab2ca296c6ed73dbbebed02106c9910d162fb140b81d
BLAKE2b-256 checksum
How to use checksums
d498dcdbef00731eed2ab2cca0a44b0dc0d95dab3b35d7da496c650b117bc425
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

0.4.2

7 release files

This release

0.4.1 This release

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