Python capture SDK for the Apex Audit service: hash-at-source, tamper-evident audit trails for AI agent decisions.
Project description
apex-audit-sdk (Python)
Capture SDK for the Apex Audit service: tamper-evident, hash-at-source audit trails for AI agent decisions, sealed to a public ledger.
Three lines is all an agent loop needs:
txn = client.open_transaction(name="benefits eligibility review")
txn.log("reasoning", {"rationale": "Income below threshold; criterion B met."})
txn.log("output", {"recommendation": "approve", "confidence": 0.94})
Every entry is hashed on your side before it leaves the process
(sha256 over the RFC 8785 canonical form of
{transaction_id, seq, type, payload, prev_hash}), chained to the previous
entry, and re-verified by the server on receipt. Nobody — including the
service — can silently rewrite what your agent did.
Install
pip install apex-audit-sdk # package name
python -c "import apex_audit" # import name
From this repo (development):
cd packages/sdk-python
python3 -m venv .venv
.venv/bin/python -m pip install -e ".[dev]"
.venv/bin/python -m pytest
Requires Python >= 3.10. Runtime dependencies: httpx, rfc8785.
Quickstart
from apex_audit import AuditClient
client = AuditClient(
api_url="http://localhost:4000",
api_key="...", # sent as Authorization: Bearer <key>
timeout=10.0,
)
txn = client.open_transaction(name="benefits eligibility review")
txn.log("initiation", {"task": "benefits-eligibility-review", "case_ref": "EU-2026-00441"})
txn.log("action", {"tool": "case_management.lookup", "applicant_ref": "APP-99182"})
txn.log("reasoning", {"rationale": "Income below threshold; criterion B met."})
txn.log("output", {"recommendation": "approve", "confidence": 0.94})
txn.request_review() # status -> in_review
txn.record_oversight(decision="approved", reviewer="j.okafor",
note="Consistent with policy 2026/14.")
txn.complete() # status -> complete
sealed = txn.seal() # Merkle root anchored on-ledger
print(sealed["merkle_root"], sealed["anchor_topic_id"])
client.close() # or use: with AuditClient(...) as client: ...
Context-manager style (opens the transaction on enter; nothing automatic on exit — review, completion and sealing stay explicit):
with client.transaction(name="loan pre-screen") as txn:
txn.log("initiation", {...})
...
Entry types are restricted to initiation, action, reasoning,
reference, output, oversight — anything else raises ValueError
before any network call.
Error handling
The service reports errors as {"error": {"code", "message", "details"}},
mapped to exceptions:
from apex_audit import ApexAPIError, ChainConflictError, EntryHashRejectedError
try:
txn.log("action", {"tool": "lookup"})
except ChainConflictError as e: # 409 CHAIN_CONFLICT
# another writer extended the chain, or a previous attempt landed.
print(e.details["expected_seq"], e.details["expected_prev_hash"])
except EntryHashRejectedError as e: # 422 ENTRY_HASH_INVALID
# client/server canonicalisation disagreement — report it, don't retry.
print(e.details["computed_by_server"], e.details["submitted"])
except ApexAPIError as e: # everything else
print(e.code, e.status, e.message, e.details)
The SDK never auto-retries POSTs. Appending an entry is not idempotent:
if a request times out after the server stored it, a blind retry would be
rejected as CHAIN_CONFLICT — and retry loops can mask genuine chain breaks.
On any failure, local seq/prev_hash state is left unchanged so you can
inspect, resynchronise, and retry deliberately.
Payload rules (the number caveat)
Payloads must be plain JSON: dict (string keys) / list / str / int /
float / bool / None. NaN/Infinity, sets, datetimes, bytes, Decimals
etc. raise ValueError with the offending path (e.g. payload.scores[2]).
Integers beyond 2^53 − 1 lose precision once they hit IEEE-754 doubles
(RFC 8785) and Postgres jsonb. The SDK warns (PayloadPrecisionWarning)
and recommends sending such values as strings:
txn.log("action", {"ledger_ref": str(9007199254740993)}) # exact
txn.log("action", {"ledger_ref": 9007199254740993}) # warns; value will round
Verifying later
data = client.get_transaction(txn_id) # transaction + ordered entries
result = client.verify(txn_id) # recompute + compare with ledger anchor
# (404 until the service ships verify, M4)
Hash utilities are exported for independent verification:
from apex_audit import compute_entry_hash, compute_merkle_root, canonicalize, GENESIS_HASH
Full reference: docs/sdk/python.md.
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 apex_audit_sdk-0.1.0.tar.gz.
File metadata
- Download URL: apex_audit_sdk-0.1.0.tar.gz
- Upload date:
- Size: 16.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f97e958d59d1448317c745ccfb06715e522364fbd11a5fa06287fa52b4bb69d
|
|
| MD5 |
e0dc99a9297d63ef365a3b703465b27e
|
|
| BLAKE2b-256 |
b645c9d2d28839661597771bd485bc2e87df2902267d4f0e25c715df1d9d493f
|
File details
Details for the file apex_audit_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: apex_audit_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
feac8bd11fc9a451b67a1828e145e4946b058bbf6548b8f953acfac3d7573200
|
|
| MD5 |
5404bb4f4c26b605aa23936ce9b6aa92
|
|
| BLAKE2b-256 |
b511e043d7ac7d93d8521ef41ee375d41e6abbc2d31e656204ca2de1050a42c0
|