Metadata-Version: 2.4
Name: attestroot
Version: 0.1.0
Summary: Local-first, tamper-evident evidence layer for AI agent activity — hash-chained capture sealed into an RFC 6962 Merkle commitment.
Author-email: Abhijeet Verma <hello@attestroot.com>
License-Expression: MIT
Project-URL: Homepage, https://attestroot.com
Project-URL: Published standard, https://doi.org/10.5281/zenodo.21387486
Project-URL: Reference implementation, https://github.com/MaqAnquor/incident-ledger
Project-URL: Live demo, https://huggingface.co/spaces/docwagon/prove-your-agent-log
Keywords: ai-audit,audit-trail,tamper-evident,hash-chain,merkle-tree,rfc6962,ed25519,ai-governance,ai-agents,compliance,evidence,claude-code,observability
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Legal Industry
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: System :: Logging
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: fast
Requires-Dist: cryptography>=42; extra == "fast"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Dynamic: license-file

# attestroot

Local-first, tamper-evident evidence for AI agent activity.

Captures what an AI agent did, hash-chains it, seals it into an RFC 6962 Merkle
commitment, and produces a bundle anyone can verify — on a clean machine, with no
dependencies, without our software and without contacting us.

**Status: pre-release.** M0 and M1 are functionally complete and pass their exit
tests. Nothing is published to PyPI yet.

---

## What it claims, and what it does not

It attests that **a record existed at a given time and has not been altered
since**.

It does **not** prove the record is a truthful account of what the agent did. A
party controlling its own capture could record something false, and it would seal
and verify perfectly. Integrity and existence-in-time is a real, checkable
property — it is simply not the same property as truth.

That distinction is enforced in code, not just in wording: every adapter declares
its own blind spots, and evidence lacking independent ground truth is capped at a
lower grade with the reason recorded.

## Current state

| Component | Status |
|---|---|
| RFC 6962 Merkle tree | ✅ verified against the spec, incl. a path-length guard most implementations omit |
| Ed25519 (RFC 8032) | ✅ pure-Python, all official vectors pass; uses `cryptography` when present |
| Hash-chained ledger | ✅ 0.47 ms/append, names the exact sequence number where a chain breaks |
| Capture hook | ✅ fail-open, p99 0.68 ms, exits 0 on every hostile input tested |
| Adapter contract | ✅ capability manifest drives grade ceilings mechanically |
| Claude Code adapter | ✅ validated against a real 442-tool-call session |
| Seal / bundle / verify | ✅ end-to-end, 9/9 tamper attacks detected |
| Conformance suite | ✅ 8 cases, all passing — clean, resumed, compacted, crashed, gapped, concurrent, subagent, malformed |
| Grader (D0–D4) | ✅ deterministic, 11/11 fixture bundles match the hand-computed rubric |
| Standalone verifier | ✅ one file, no dependencies, output identical to the CLI |
| Countersignature | ⬜ M3 — nothing is live |

## Exit test

The M0 gate was *"seal a real 50-turn session; verify in a clean container."*

```
session      real Claude Code transcript — 1661 lines, 442 tool calls, 1 compaction
captured     442 events @ 0.75 ms
bundle       2103 leaves, 447 members, 7.7 MB
gaps         0  (every ground-truth tool_use id matched a captured one)
clean room   13/13 checks pass — no dependencies, no signing key, no local state
tampering    9/9 attacks detected
```

`scripts/clean_room_verify.sh` runs it. Where Docker is unavailable it builds a
hermetic room with `python3 -I -S`, which is stricter on the dependency question
than a container: site-packages is unreachable, so `cryptography` cannot be
imported even when installed, forcing the pure-Python signature path.

## Try it

```bash
PYTHONPATH=src python3 -m attestroot.cli init
PYTHONPATH=src python3 -m attestroot.cli status
PYTHONPATH=src python3 -m attestroot.cli seal <session-id>
PYTHONPATH=src python3 -m attestroot.cli verify <bundle> --offline-bundle
PYTHONPATH=src python3 -m attestroot.cli grade <bundle>
PYTHONPATH=src python3 -m attestroot.cli conformance
```

## Verifying without installing anything

`dist/attestroot_verify.py` is a single file with no dependencies. Email it
alongside the bundle:

```bash
python3 attestroot_verify.py evidence.arbundle
```

It produces byte-identical output to `attestroot verify`, and prints its own
SHA-256 at build time so a recipient can check the copy they were sent against
the one published here.

This exists because "clone the repo and set PYTHONPATH" is already too much
friction for someone who was emailed an evidence file and has thirty minutes.
Evidence nobody checks is decoration.

## Adapters

An adapter is a translator from a source's native events to canonical W Events.
It declares what it can see in a capability manifest, and **the grader acts on
that declaration**: an adapter reporting `has_ground_truth: false` caps the grade
at D1 with the reason recorded, because completeness cannot be evaluated without
an independent record to diff against.

Adding one means implementing the contract in `adapters/base.py` and submitting
conformance fixtures with the change. **An adapter is certified only when its
suite passes** — including a check that its declared capabilities match what its
output can actually support. Claiming ground truth while producing none fails.

## Design constraints

These are load-bearing, not preferences:

- **Fail-open capture.** The hook never blocks or slows the agent. Every failure
  path writes a gap record and exits 0. A bug in evidence collection must not
  stop someone's work.
- **No network in the free path.** Ever. Not for telemetry, not for time.
- **Store raw.** Payloads are persisted verbatim and interpreted at read time.
  Tool schemas change; today's normalisation is tomorrow's lost evidence.
- **Zero dependencies for verification.** An auditor must be able to verify on a
  machine where they cannot install anything.
- **Gaps are a feature.** Missing captures are detected by diffing against the
  source's own record, never from self-reported gap records — otherwise hiding a
  gap is as easy as not writing one.

## Built on

[incident-ledger](https://github.com/MaqAnquor/incident-ledger) — the append-only
hash-chained evidence log this extends to agent activity.
`pip install incident-ledger`

## Published standard

- [Implementing Agentic-AI Accountability](https://doi.org/10.5281/zenodo.21387486)
  — five evidence principles crosswalked to the IMDA MGF, EU AI Act, NIST AI RMF
  and ISO/IEC 42001, with the D0–D4 evidentiary maturity lens · CC BY 4.0
- [incident-ledger](https://doi.org/10.5281/zenodo.21387488) · MIT

Tamper-evident logging, deterministic replay and evidence-maturity grading are
cited prior art, not claims of this work. Hash chains and Merkle trees are 1979
and 1991 public cryptography.

## Not supported

Windows. Paths, file locking and fsync semantics differ enough that half-support
would be worse than none. WSL works.

---

MIT · [attestroot.com](https://attestroot.com) · AVATROX TECHNOLOGY PRIVATE LIMITED
