v0.1.2 released · Apache 2.0

Prove what your AI agent actually did.

Tamra is a tamper-evident evidence ledger for AI agents. It seals every LLM call, tool call, and human approval into a cryptographic hash chain you can hand to an auditor — who can verify it offline, without trusting you.

Self-hosted on your own Postgres. Signed with your own keys. No cloud, no API key, no per-event cost.

One Maven dependency No code changes to your agent ~20µs per call EU AI Act Art. 12, 14 & 19
SEQ 4473 · APPROVAL prev 91cc4e…2d70 hash f04a71…b6c8 SEQ 4474 · TOOL_CALL prev f04a71…b6c8 hash 2af8b1…9e34 SEQ 4475 · LLM_CALL prev 2af8b1…9e34 hash c61d07…8a5f SEQ 4476 · CHECKPOINT ✓ prev c61d07…8a5f ed25519 5e93da…c07b Every entry seals the one before it. Change any byte and every hash after it stops matching.

The problem

Your agent logs prove nothing.

A row in a database is mutable by design. Anyone with write access — an engineer, a script, an attacker — can change what your agent "did" after the fact, and leave no trace. So when it matters most, your logs are just claims.

A customer disputes a decision

They say your agent promised a refund. You say it didn't. Both of you are pointing at a table that either side could have edited.

A regulator asks for records

EU AI Act Article 12 requires automatic logging over a high-risk system's lifetime. Exporting a CSV proves you have data, not that it's unaltered.

Something goes wrong at 3am

You need to know exactly which tool the agent called, with what arguments, and whether a human approved it — and you need that answer to hold up later.

The fix isn't better logging — it's a log that can't lie. Here's how Tamra builds one.

How Tamra works

Capture. Seal. Prove.

Three moving parts, and you only ever touch the first one.

1

Capture

A Spring AI advisor records every LLM_CALL and TOOL_CALL automatically — no changes to your agent code. Human sign-offs go in through the HumanApprovalRecorder API.

~20µs on the calling thread. Writes happen on a background thread.

2

Seal

Each event is canonicalised (RFC 8785), hashed with SHA-256, and linked to the hash of the event before it. Every hour, the chain head is signed with an Ed25519 key that never leaves your infrastructure.

Append-only Postgres table, guarded by database triggers.

3

Prove

Export a date range as a signed .tamrapatra bundle: events, checkpoints, your public key, compliance mappings, and an HTML report. Your auditor verifies it on their own laptop.

Offline verification needs nothing but OpenSSL.

By default Tamra stores hashes only — not your raw prompts or tool arguments. You can prove an event happened and hasn't changed without the ledger ever holding sensitive content. Turn on full-payload when you need the text itself.

See it catch a tamper

Edit the database directly. Tamra still notices.

This is the part that matters. Someone with full database access changes one event — exactly the scenario ordinary logs can't survive. Here's what happens next.

a real 500-event ledger
$ tamra verify
✓ Chain VALID
  events:        500
  head sequence: 499
  head hash:     834b6373a932008ea91524fd928b88348f5c96fd4dcf9935bbb7bea76b9a5119

# tamper with event #250 as a Postgres superuser — past the append-only trigger

$ tamra verify
✗ Chain BROKEN at sequence 250
  reason: content hash mismatch: the event has been modified since it was sealed

No diff tool, no backup to compare against — the ledger detects its own wound and names the exact sequence where it happened. To hide the edit, a tamperer would have to recompute every hash from 250 onward and forge an Ed25519 signature with a key that never left your infrastructure.

verify exits 0 when the chain is clean and 1 on a break — so you can wire it into CI or a cron job and get paged the moment a record changes.

Why it's called Tamra

India solved this problem a thousand years ago.

When an ancient Indian king granted land, the record wasn't written on palm leaf — it was engraved into copper plates called tamrapatras (tamra = copper, patra = document).

Copper was chosen for one reason: you cannot quietly change it. It doesn't rot, and re-engraving leaves scars anyone can see. Plates were often riveted together under a seal, so no page could be added or removed. If a claim was ever challenged, the holder produced the plate.

A thousand years on — long after the issuing kingdom ceased to exist — those plates are still legible, and still carry the evidence of whether anyone tampered with them. The kingdom's authority expired. The record's didn't.

That's the whole idea behind Tamra: evidence that outlives the trust you placed in whoever produced it. We just swapped the copper for a hash chain.

And it's not only a metaphor — the evidence bundle Tamra exports for your auditor is literally a .tamrapatra file.
c. 1100 CE COPPER PLATE engraving leaves scars SEQ 4476 prev c61d07… hash 5e93da… ed25519 signed .tamrapatra 2026 CE HASH CHAIN edits break the chain

Quickstart

One dependency. No code changes.

If you're on Spring Boot 3.4 and Spring AI 1.0, capture starts the moment the app boots.

pom.xml
<dependency>
  <groupId>dev.tamra</groupId>
  <artifactId>tamra-spring-boot-starter</artifactId>
  <version>0.1.2</version>
</dependency>
application.yml
tamra:
  keystore:
    path: .tamra/keystore     # your Ed25519 signing key
  capture:
    full-payload: false      # hash-only by default — keeps prompts out of the ledger
  checkpoint:
    interval: 1h
terminal
# the CLI ships as a signed jar on the GitHub release — grab it, then alias for readability
$ curl -LO https://github.com/tamra-dev/tamra-agent-ledger/releases/latest/download/tamra.jar
$ alias tamra='java -jar tamra.jar'

# 1. generate the signing key you control
$ tamra keygen --keystore .tamra/keystore

# 2. run your agent as usual — events are captured automatically

# 3. export a signed evidence bundle for a date range
$ tamra export --from 2026-06-01 --to 2026-07-01 --edict eu-ai-act \
    --out my-evidence.tamrapatra --keystore .tamra/keystore
✓ Wrote my-evidence.tamrapatra
  events:   500 (sequence 0 to 499)
  edict:    eu-ai-act v0.1
  signed:   checkpoint over the segment head (Ed25519)

# 4. anyone can verify it offline — no database, no Tamra server
$ tamra verify --bundle my-evidence.tamrapatra
✓ Signatures verified (Ed25519)
  edict:      eu-ai-act v0.1 (EU AI Act)
  signer key: 2095…d69a  # compare against the operator's key out of band
✓ Chain VALID  — 500 events, head sequence 499

Scope

What works today — and what doesn't.

v0.1.2 is an early open release, and the MVP is deliberately narrow: one framework, one database, one regulation. Here's exactly where the edges are.

AreaTodayStatus
FrameworksSpring Boot 3.4.x + Spring AI 1.0.xShipped
StoragePostgreSQL 15+ (append-only, Flyway)Shipped
Compliance mappingEU AI ActShipped
SignaturesEd25519, keys you holdShipped
Other frameworksLangChain4j, Python, MCP gatewayPlanned
Other standardsISO 42001, SOC 2, DPDPPlanned
Streaming captureChatClient.stream(), tool loopsPlanned
Post-quantumML-DSA signaturesPlanned
Dashboard / ClickHouseUI and alternate backendPlanned
Java
21
Overhead
~20µs / call
License
Apache 2.0
Cost per event
Zero

Start proving it.

Tamra is fully open source and self-hosted. There is no account to create, no key to request, and nothing phones home.

A copper plate for your agent.