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

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.0
File Size Uploaded
witness_log-0.4.0.tar.gz 343.9 kB Details

Built distributions (wheels)

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

Download URL witness_log-0.4.0.tar.gz
Size 343.9 kB
Tags Source
SHA-256 checksum
How to use checksums
6087d102f196c2d3a7fd5c8522bec336b66b5756bc1ff48466f74f98623c9a4e
BLAKE2b-256 checksum
How to use checksums
ec75d8ecedf1c01f7e48888137d4e48c450498d343f7a7031639e8a5e2ee3dd7
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.0-cp39-abi3-win_amd64.whl

Download URL witness_log-0.4.0-cp39-abi3-win_amd64.whl
Size 737.5 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
4aaed5c5499424e1b33e5839d507a3d2ff146cb8d7f8ec756e557bdc66a67d83
BLAKE2b-256 checksum
How to use checksums
e4949fffc8736b1c83784f33ae4757161d790e55d9f4dbfd157695c584f9f05f
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.0-cp39-abi3-musllinux_1_2_x86_64.whl

Download URL witness_log-0.4.0-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
869fdd1701433db80ec8f4ecebc4fba8b573bb43311450a55b8c26509f871985
BLAKE2b-256 checksum
How to use checksums
5857bb1c4e1e8c715a3c5b0c3b321b8d00c671a4e945092e2ef15fe7b8eafefc
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.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

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

Download URL witness_log-0.4.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 744.8 kB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
3740eff5707a469e5eb667ea37a4d82851520d9b894447fa60bcc6212fef215b
BLAKE2b-256 checksum
How to use checksums
ac801ffdaa0b18752172e7ec70190757fe4c95bb4efeb82daf518b6d6184fa2f
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.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL witness_log-0.4.0-cp39-abi3-macosx_11_0_arm64.whl
Size 719.8 kB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
8705fee24b4e9798fc284025b4aacf308050b194a8b573173b5f84852fb90726
BLAKE2b-256 checksum
How to use checksums
40acd5640a409b4adca1b6118f85b6c01c1000fda1aedb3d221a993615756f84
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.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL witness_log-0.4.0-cp39-abi3-macosx_10_12_x86_64.whl
Size 771.5 kB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
b13cdb71990f0065a54a4126a1778f8d16cca24a44a94f5bf88c8b5c6adfd7af
BLAKE2b-256 checksum
How to use checksums
503216aaa69dcda55a93aba842881a16b4b7891c86970be7b24207ba18c85576
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

0.4.1

7 release files

This release

0.4.0 This release

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