Skip to main content

Tamper-evident audit + provenance for AI agents — an offline, zero-dependency, hash-chained append-only ledger. Wrap your agent's tool calls, then prove what it did: any edit, reorder, insertion, or deletion fails verification. Optionally anchor the ledger's RFC 6962 Merkle root to the OmegaEngine transparency log.

Project description

omega-audit

Tamper-evident audit + provenance for AI agents — prove what your agent did, hash-chained, verifiable, auditor-ready.

Wrap your agent's tool calls. Every call is appended to a local, append-only, SHA-256 hash-chained ledger. Later, anyone can recompute the chain and detect any edit, reorder, insertion, or deletion — offline, in one command, with no signup and no trust in us.

  • Zero runtime dependencies. Python's standard library only (hashlib, json, base64). No SDK, no account, no network.
  • Offline and local. The ledger is a plain JSONL file on your disk. You own it.
  • Framework-agnostic. Wrap any callable — sync or async — plain tools, OpenAI/LangChain/LlamaIndex tool defs, MCP handlers.
  • Independently verifiable. omega-audit verify recomputes the whole chain. Break one byte and it fails.
  • Byte-compatible with the TypeScript twin @omegaengine/audit: a ledger written in Python verifies under the TS CLI and vice versa — same bytes, same hashes.
  • Apache-2.0.

Why now

The EU AI Act's record-keeping obligation (Article 12) applies from December 2, 2027 for standalone (Annex III) high-risk AI systems — the EU Digital Omnibus, adopted June 29, 2026, deferred it from the original August 2, 2026 date (embedded Annex I systems follow on August 2, 2028; the Act's transparency obligations — chatbot disclosure, synthetic-content labeling — still apply from August 2, 2026). When it applies, providers must ensure their systems automatically record events (logs) over their lifetime, to a degree appropriate to the system's purpose.

The deadline moved; the ask didn't. Regulators and enterprise buyers already ask for tamper-evident logs — in procurement questionnaires, vendor security reviews, and incident post-mortems — and an audit trail is only convincing if it was accumulating before anyone asked for it. A policy document that says "we log agent actions" is not evidence. Evidence is a log you can hand an auditor that provably has not been altered — and the way to have years of verifiable history when auditors do ask is to start appending now, not to race a deadline.

Append-only, cryptographically hash-chained logs are the well-established way to make an audit trail tamper-evident: each record commits to the one before it, so the chain itself proves nothing was quietly changed after the fact. That's the same construction behind Git commit history and RFC 6962 Certificate Transparency. This package gives you that construction for your agent's actions, in about twenty minutes.

This is honest scope: omega-audit produces tamper-evident local logs — you can detect tampering by recomputing the chain. It is not, by itself, a certification, a signature from us, or proof to a third party who doesn't have your file. For cross-organization, independently-anchored proof, see Anchoring to the transparency log below.


20-minute quickstart

1. Install

pip install omega-audit

2. Wrap a tool

from omega_audit import Ledger, wrap_tool

# One local, append-only ledger file. Offline — no signup, no network.
ledger = Ledger("ledger.jsonl")

# Your existing tool — any callable, sync or async.
def send_email(to: str, subject: str):
    # ... your real implementation ...
    return {"delivered": True}

# Wrap it. Same signature, same return value — it just records every call.
tracked_send_email = wrap_tool(ledger, "send_email", send_email)

tracked_send_email("auditor@example.com", "Q3 evidence")

Each call appends one record: {tool, args, ok, result | error, duration_ms}. Errors are recorded too (with ok=False and the message) and then re-raised unchanged, so wrapping never swallows a failure.

Async tools work the same way — if the wrapped function is a coroutine, the wrapper is too:

import asyncio
from omega_audit import Ledger, wrap_tool

ledger = Ledger("ledger.jsonl")

async def fetch_row(row_id: str):
    # ... await your real async implementation ...
    return {"id": row_id}

tracked = wrap_tool(ledger, "fetch_row", fetch_row)
asyncio.run(tracked("abc"))   # the record is written when the awaited call settles

This composes with agent frameworks: an OpenAI or LangChain tool is just a callable with a schema, so wrap its implementation and register the wrapped version. Nothing about your agent loop changes.

3. Look at the ledger

ledger.jsonl is one JSON object per line — readable, greppable, diffable:

{"seq":0,"ts":"2026-08-02T09:00:00.000Z","action":{"tool":"send_email","args":["auditor@example.com","Q3 evidence"],"ok":true,"result":{"delivered":true},"durationMs":501},"prevHash":"0000000000000000000000000000000000000000000000000000000000000000","hash":"44dab7b4…"}

Every record's hash is sha256(canonical_json({seq, ts, action, prevHash})), and its prevHash is the previous record's hash (the first record links to 64 zeros). That chain is what makes tampering detectable. The field is stored on disk as prevHash (camelCase) so the bytes are identical to the TypeScript twin.

4. Verify it

omega-audit verify ledger.jsonl
✓ 3 records — chain intact & tamper-evident

Exit code 0 when intact, 1 when tampered. Drop it in CI to fail a build if an agent's audit trail was touched.

You can also verify in code:

from omega_audit import verify

result = verify("ledger.jsonl")
# VerifyResult(valid=True, records=3, broken_at=None, reason=None)
# or VerifyResult(valid=False, records=3, broken_at=2, reason="record 2 was edited — …")

See it break: the tamper demo

One command builds a small ledger, tampers a record, and shows verification catch it:

omega-audit demo
omega-audit demo — tamper-evident agent audit in one command

1. An agent runs three tool calls. Each one is appended to a hash-chained ledger:

   #0  search_web  hash=ce4ca688b665…  prev=000000000000…
   #1  read_file  hash=5c7f4ae5891f…  prev=ce4ca688b665…
   #2  send_email  hash=a0c640028849…  prev=5c7f4ae5891f…

2. Verify the untouched ledger:

   $ omega-audit verify ledger.jsonl
   ✓ 3 records — chain intact & tamper-evident

3. Now someone quietly edits record #2 to hide who the email went to:

   before:  send_email → auditor@example.com
   after:   send_email → attacker@evil.example   (hash left unchanged to hide the edit)

4. Verify again — the chain no longer recomputes:

   $ omega-audit verify ledger.jsonl
   ✗ TAMPER DETECTED at record 2: record 2 was edited — its stored hash a0c64002…30cc ≠ the recomputed hash 6e1be9ab…e0ef

That ✗ is the whole point: the record was changed, and verification proved it.
Nothing here touched the network. You can run the same check on your own ledger.

The demo command exits 1 — its whole job is to prove that a tampered ledger fails verification. (The hashes vary run to run because each record's timestamp is real; the chain is self-consistent every time.)


Enforce vs. prove

These are two different jobs, and you want both:

  • A policy layer enforces — it decides, at run time, whether an action is allowed and blocks the ones that aren't.
  • omega-audit proves — it produces the independent, tamper-evident evidence trail of what actually happened, which you can verify after the fact.

Enforcement without evidence is a claim. Evidence without enforcement is a bystander. Run your guardrails to stop bad actions; run omega-audit to prove — to yourself, to an auditor, to a customer — exactly what your agent did and that the record wasn't altered.


Anchor to the transparency log (optional)

Your local ledger is tamper-evident to anyone who has the file. To make it verifiable across organizations — so a customer or auditor who does not have your machine can still confirm the record — you anchor the ledger's root to a public, append-only transparency log.

The record hashing here is byte-compatible with the OmegaEngine platform's canonical JSON + SHA-256 and with the TypeScript twin — a ledger written by this Python package verifies under @omegaengine/audit and vice versa, so it is already in the shape the hosted log expects. OmegaEngine offers, as a hosted backend:

  • Anchoring your ledger root into a public RFC 6962 transparency log for cross-org, independently-checkable proof of inclusion.
  • Long-retention storage to support multi-year record-keeping regimes (for example SEC Rule 17a-4 or HIPAA retention).
  • Auditor exports — signed, verifiable bundles an auditor can check with the open-source @omegaengine/verify tool, no OmegaEngine account required.

The local package is fully useful on its own and stays free and open source. The hosted log is the optional upgrade when "verifiable on my disk" needs to become "verifiable by someone else."

Anchor from the CLI

Anchoring is the one deliberately-online verb. It first verifies the ledger locally (a broken chain is refused — anchoring never manufactures evidence), computes the RFC 6962 Merkle root over the record hashes, and POSTs it to /api/v2/anchor:

export OMEGA_API_KEY="omega_..."          # an org API key (Pro plan or above)
omega-audit anchor ledger.jsonl --api https://omegaengine.ai
✓ anchored ledger 8f3c… — 3 records, root 6828d981e10b… (anchor a1b2c3…)
  sidecar: ledger.jsonl.anchor.json
  This proves the first 3 records of this ledger existed, unaltered, as of 2026-07-15T12:00:00.000Z.
  It does NOT prove completeness (records never written are invisible) nor that the recorded events happened as described.

Each accepted anchor is remembered in a sidecar next to the ledger (ledger.jsonl.anchor.json, byte-compatible with the TypeScript twin's sidecar). The next time you anchor, the sidecar's root is the consistency baseline: if the previously-anchored prefix no longer reproduces its recorded root, the anchor is refused as a fork — a rewrite of history is caught even when the chain still re-verifies. A consistency proof between the old and new sizes is generated locally, verified locally, and submitted alongside.

You can also anchor in code:

from omega_audit import anchor_ledger

result = anchor_ledger("ledger.jsonl", "https://omegaengine.ai")   # reads OMEGA_API_KEY
print(result.merkle_root, result.tree_size, result.anchor_id)

Honest semantics. An accepted anchor proves "this exact prefix of this ledger existed, unaltered, no later than the signed-tree-head timestamp." It does not prove completeness (entries the agent never wrote are invisible to it), does not prove the recorded events happened as described, and says nothing about entries outside the anchored prefix. Until external witnessing of the tree head ships, the timestamp itself is operator-attested. Anchoring requires a Pro-plan (or above) org API key — it is a real gate.


API

Ledger(path: str)
  ledger.append(action) -> dict     # append one record; returns it
  ledger.size() -> int
  ledger.tip_hash() -> str          # hash of the last record (chain tip)

wrap_tool(ledger, name, fn) -> fn   # wrap a named tool (sync or async); records every call
capture(ledger, fn) -> fn           # like wrap_tool, using fn.__name__

verify(path: str) -> VerifyResult
  # VerifyResult(valid, records, broken_at, reason)

read_ledger(path) -> list[dict]     # parse JSONL into records (no chain check)
verify_entries(entries) -> VerifyResult   # verify already-parsed records
canonical_json(value) -> str        # the deterministic serializer used for hashing
sha256_hex(s) -> str

# RFC 6962 Merkle (byte-identical to the TypeScript twin)
merkle_root(hashes: list[str]) -> str
consistency_proof(m: int, hashes: list[str]) -> list[str]
verify_consistency(first, second, first_root, second_root, proof) -> bool
inclusion_proof(index: int, hashes: list[str]) -> list[str]
verify_inclusion(leaf_index, tree_size, leaf_hash_hex, audit_path) -> str | None

# Anchoring (the one online verb; reads OMEGA_API_KEY)
anchor_ledger(path, api_base, ledger_id=None, api_key=None) -> AnchorResult

A ledger entry is a dict {seq, ts, action, prevHash, hash}.


Design partners

We're looking for teams putting agents in front of real users or real money who need to prove what those agents did. If you're wiring agent actions into an audit or compliance story — EU AI Act, financial record-keeping, healthcare — we'd like to build with you. Open an issue on github.com/TheArkhitect/Omegaengine or reach out via omegaengine.ai.


License

Apache-2.0. See the repository root for the full text.

Project details


Download files

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

Source Distribution

omega_audit-0.2.0.tar.gz (25.1 kB view details)

Uploaded Source

Built Distribution

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

omega_audit-0.2.0-py3-none-any.whl (30.5 kB view details)

Uploaded Python 3

File details

Details for the file omega_audit-0.2.0.tar.gz.

File metadata

  • Download URL: omega_audit-0.2.0.tar.gz
  • Upload date:
  • Size: 25.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for omega_audit-0.2.0.tar.gz
Algorithm Hash digest
SHA256 13ed781febbb0bcbc0aecce651591b14db2af5aa067d716ffc00e91f99b8579d
MD5 21a0f8a1a87b4925b621a730f513ebe0
BLAKE2b-256 46d8be2d10777e44add572ef625b63f9893d5055846ef1bc608b9ca6f849fbb0

See more details on using hashes here.

File details

Details for the file omega_audit-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: omega_audit-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 30.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for omega_audit-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e1ece69c914f47607c4472c635f0793f12f86f5c1125f27209b2c58603ab131b
MD5 7d09a05529d884d2f70c7b6c00020b3a
BLAKE2b-256 86231b9b29089b5c50aaa6c673fbd90dec08d034e7947cabc7f39665bec030b6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page