Repository navigation
Auditor Guide
You are checking an operator's evidence about its agents. The operator gives you bundles; everything you trust has to come from somewhere else. That is the point of the format: a bundle carries no code and no trust configuration, and the verifier pins its own (format v2, invariant I9 in the threat model). Which requirements of the EU AI Act, ISO/IEC 42001, the NIST AI RMF and OWASP's lists this evidence bears on, and what it doesn't cover: compliance mapping.
Install Tracekit yourself, from PyPI or a source checkout you have reviewed, at a version you pin:
pip install 'tracekit-ai==<version>'
tracekit --versionNever run a verifier, script or trust file the operator ships with the evidence. Verifying a v2 bundle needs no network access.
trust.json pins the log key, the witnesses and the algorithms (format v2):
{"logs": ["tracekit.example.org/log/1+1a2b3c4d+AZ..."],
"witnesses": [{"vkey": "witness.example.org/w1+257cc7f1+BG...", "class": "public"}],
"algs": ["ed25519"],
"witnesses_required": 1}| Entry | Where to get it |
|---|---|
logs |
The operator's log vkey (tracekit signer vkey on their side). Get it once, through a channel you can hold them to (a signed letter, a contract annex, a published page you archive), and keep your copy. Cross-check it against the copy each witness registered for that log (the witness network's logs list). |
witnesses |
Each witness's cosignature vkey, from the witness's operator, not from the signer's config. |
class |
Your judgement of who runs each witness: public (a witness network), customer (you or another customer), tracekit, or operator (the party being audited). Only non-operator witnesses count toward witnessed. |
witnesses_required |
How many pinned cosignatures a checkpoint must carry. Set it to at least 1 for an audit. |
rekor (optional) |
Sigstore's trusted_root from Sigstore's TUF repository, the signer's Rekor publishing key (rekor.pub) from the operator, and its class. See witnesses. |
analyzers (optional) |
The identities (scheme:subject, such as uid:1004 or mtls:spiffe://acme/analyzer) whose signed findings you take as independent: the operator's analyzer, never the agent's identity. Only a finding by a pinned author reads independent; see verdicts. |
tracekit signer trust -o trust.json writes a trust config from a signer's own config. It is a convenience for the
operator; as an auditor, check every key in it against your own sources before using it.
Ask for the runs you sample, and for the tenant's run-set, which shows that no run was left out:
tracekit export --v2 --config signer.yaml --run <run id> -o run.tkb # one run
tracekit export --v2 --config signer.yaml --run-set --tenant <tenant> -o run-set.tkb # the registry from size 0 to its
# latest checkpoint, with every
# run finalised in itThe operator runs these after the next checkpoint covers the records. A run-set bundle holds the tenant's registry salt, so it lets you test guessed run ids against that tenant's leaves (only that tenant's).
tracekit verify run.tkb --trust trust.json --strict
tracekit verify run-set.tkb --trust trust.json --strict --json > run-set.report.jsonExit 0 is clean, 1 failed, 2 unusable, 3 warnings under --strict. For a bundle whose log continues a v1 ledger, add
--v1-ledger ledger.jsonl --v1-key signer.pub to check the format bridge.
A second verifier. The TypeScript verifier was written from the format spec, not from the Python code, and is tested to reach the same verdicts (implementations). Running both, from two sources you obtained yourself, means a bug in one doesn't decide your audit:
npx --package ./cygnuxlabs-tracekit-<version>.tgz tracekit verify run.tkb --trust trust.json --strict # the .tgz from the GitHub releaseIt needs only Node ≥ 20.12. Where it can't check something the bundle relies on (an SLH-DSA checkpoint line, a Rekor
anchor, a certified record key) it says UNVERIFIABLE and names it; use the Python verifier for those.
In a browser. The release's verify.html is the TypeScript verifier as one page whose Content Security Policy lets
it load and send nothing, so a bundle checked there never leaves your machine. Check your copy against the release
first, gh attestation verify verify.html --repo Cygnux-Labs/Tracekit, then open it and drop in the bundle and your
trust config. Without the trust config it still finds changed records, but never says VERIFIED
(verdicts).
A verifier older than the bundle says UNVERIFIABLE (needs tracekit >= x) and, from 1.4.0, the commands that verify
it (verdicts). A not interpreted warning means the records carry
an ext name your verifier doesn't check: they verified, but for what the name says use the version the line names.
Verdicts explains every line. For an audit, look at least at:
-
Integrity:VERIFIED, notVERIFIED TO HEAD n (open), for runs that should be finished. -
Assurance:witnessed, with cosignatures from witnesses you classed as independent, at times inside the window.devorlocalmeans nothing outside the operator vouches for the checkpoint. -
run-set: COMPLETE, and nokey retirements not proven completeon theAssuranceline (akeyswarning when the bundle's key records show a retired key). -
gaps: signed gap, tamper and mismatch records (an edited checkpoint, a refused approval binding, calls the client numbered that never arrived). -
isolation:separate-user(or a remote signer) for production runs;same-useris a dev signer. -
coverage,tiersandfail-open classes: how much of what the agent did the evidence can speak for. -
policy,break-glass approvalsandapprovals: self: calls that ran against policy and who approved what.
Records never hold a plain hash of what the agent sent, only an HMAC commitment under a per-record salt (format v2). To check that some arguments you were given (from the application's own logs, say) are the ones a decision was made on:
-
Note the record's
seq(for example apolicy.decision), and ask the operator to reveal its salt:tracekit signer reveal --record 1234 --config signer.yaml {"seq": 1234, "type": "policy.decision", "salt": "9f…"}Only the owner of the signer's keys can run this. One salt opens one record's commitments, nothing else.
-
Recompute the commitment and compare it with the record's
data.args_commitment:import hashlib, hmac from tracekit.format.canon import canonical digest = "sha256:" + hashlib.sha256(canonical({"tool": tool, "args": args})).hexdigest() commitment = "hmac-sha256:" + hmac.new(bytes.fromhex(salt), digest.encode(), "sha256").hexdigest() assert commitment == record["event"]["data"]["args_commitment"]
argsare the arguments as JSON values; forargs_source: rawparse the raw text first (strict JSON). Atool.result'soutput.hashcommits the same way to"sha256:" + hex(SHA-256(JCS(value))), where value holds the call'sresultanderrorfields as the signer redacted them, so it matches the original only when nothing was redacted (output.redacted: false).
A match shows those were the arguments; a mismatch shows they were not. Without the salt, a commitment says nothing about the content, and guessing it is not feasible.
Generated from docs/ at v1.4.1. Edit the docs in the repository, not here.
Get started
- Quickstart: the v2 signer
- Quickstarts
- Quickstart: Claude Agent SDK
- Quickstart: a custom agent
- Quickstart: LangChain and LangGraph
- Quickstart: MCP client
- Quickstart: OpenAI Agents SDK
- Coding agents other than Claude Code
- tracekit doctor
- Walkthrough: Tracekit end to end
How it works
- How Tracekit works
- Overview
- The life of a tool call
- The evidence format
- Verification and assurance
- Witnesses and monitoring
- Policy
- Approvals
- Detection and containment
- Capture and completeness
- Custody
- Provenance and tracekit why
- Deployment and isolation
- Storage, durability and performance
- Integrations
- Security model
- Architecture
- tracekit why: architecture
Integrations
- Integrations
- Adapters
- OpenTelemetry
- Remote clients
- Kubernetes agent-sandbox
- agentgateway
- agentsh and Tracekit
- Browser Use
- Claude Agent SDK
- Claude Code's sandbox
- Codex's sandbox
- CrewAI
- Docker MCP Gateway
- E2B
- Falco
- Gemini CLI's sandbox
- Google ADK
- Haystack
- LangChain v1
- LiteLLM
- LlamaIndex
- MCP client
- microsandbox
- Microsoft Agent Framework
- OpenAI Agents SDK
- NVIDIA OpenShell
- Pydantic AI
- sandbox-runtime's proxy on its own
- Strands Agents
- Tetragon
- Vercel AI SDK
- Wassette
Policy and approvals
- Policy reference
- Approvals
- Findings
- Reading the model's reasoning
- Incidents and containment
- Webhooks
Deploy and operate
- Deploying the signer
- The signer as a container
- The signer on Kubernetes
- The compose stack
- Identity
- Tool executor
- MCP gateway
- LLM gateway
- Egress observation
- Witnesses
- Log monitor
- Record-key issuer
- Signer observability
- Viewer
- tracekit why: causal investigation and replay
- Migrating
- Platforms
Verify the evidence
- Reading a v2 verify report
- Evidence format v2
- Auditor guide
- Sample evidence bundle
- Signing
- What Tracekit guarantees
Security and privacy
- Threat model: the v2 signer
- Threat model: the v1 laptop signer
- HTTP security checklist
- Threat-model review packet
- Privacy
- Known limits and trade-offs
- What's stable
Compliance
- Compliance mapping
- EU AI Act
- ISO/IEC 42001
- NIST AI RMF and the Generative AI Profile
- OWASP Top 10 lists for LLM and agentic applications
Evaluation
Demos
- Demos
- Agent approvers within bounds
- Completeness and tamper evidence
- Detection and containment
- Network coverage: an egress observer
- Guardrails: allow, deny, or ask a person
- MCP tools, gated and recorded
- Prompt injection held by provenance
- Why: which input caused the action
Help