Let your agents act.Prove every action.
Tracekit checks each tool call your agent makes before it runs. Risky calls wait for a person to approve them. Every decision is signed, so your customers and auditors can check the record for themselves.
Open sourceMIT · v1.2.0- RUNS
- 1
- CALLS
- 1
- FLAGGED
- 0
- BLOCKED
- 0
- HELD
- 0
- APPROVED
- 0
- GAPS
- 0
- HIGH ALERTS
- 0
- SPAN
- 2s
- RECORDS
- 2
1TAPE2 events · newest first
2ALERTS0 total · 0 high
- No alerts yet.
3DETAILpolicy.decision · seq 1
- CALL
- Read
- RUN
- coding-agent·7c4b
- TIME
- 09:41:08
- DECISION
- ALLOW → RUNNING
- RULES
- none matched
- TARGET
- src/billing/refunds.py
{ "seq": 1, "prev_hash": "sha256:2e6692c4f322…", "ts": "2026-10-14T09:41:08.800000Z", "run_id": "7c4b8432ddf29cd6f98eb8c7a009f1e2", "agent_id": "coding-agent", "type": "policy.decision", "data": { "tool": "Read", "target": "src/billing/refunds.py", "decision": "allow", "rule_ids": [], "policy": "acme-1" } }
4CHAINsigner store
- #0 run.registeredprev → hash
0000000000→2e6692c4f3 - #1 policy.decisionprev → hash
2e6692c4f3→a9fb6d9950
- Claude Code
- OpenAI Agents SDK
- LangGraph
- Claude Agent SDK
- MCP
- CrewAIexp
- Vercel AI SDKexp
- Cursorexp
- Ed25519record signatures
- RFC 6962Merkle tree log
- RFC 8785canonical JSON
- C2SPsigned checkpoints
- tlog-cosignatureindependent witnesses
- MITopen source
Tracekit checks every action before it runs. Then it signs a record that anyone can check.
Agents you run
- Claude Code
- Codex · Cursor
- Gemini CLI and more
Agents you build
- Your app Python · TypeScript
Tracekit
DECIDES · SIGNS · CHAINS
POLICYallowdenyask
Tools
- Shell
- Database
- Payments
- Email · HTTP
People
Approves what's held
Signed log
HASH-CHAINED · CHECKPOINTED · WITNESSED
.tkb → verify anywhere
Tracekit
Free and open source. It sits between your agents and their tools.
Tracekit Enterprise
Early access. One control room for approvals, alerts and evidence across your team.
Your agent does the work. Tracekit checks every step.
You don't change your agent. Tracekit checks each tool call before it runs, holds risky ones for a person, and signs what happened.
- 01 / 03
HOLD · waits for a person TOOL CALLS Read query Bash HOLD issue_refund Read DENY Bash query HOLD send_email Read DENY query DENIED tracekit signer Hover to slow timedecided 7 · denied 1 · held 1 Checked before it runs.
Each tool call is checked against your policy first. It is allowed, blocked, or held for a person. A blocked call goes back to the model as a refusal, and the agent carries on.
0.91 msp99 per calldecide + complete, ack-on-write, E9 quick run, macOS, 1,000 calls - 02 / 03
HELD CALLS APPROVER · CLI · WEB · SLACK issue_refund amount= 4000 order=1042 args sha256:9f2c… APPROVED APPROVER RUN once, as approved TK-APPROVAL-MISMATCH Click to approveapproval: used once · ttl 1h Risky calls wait for you.
A refund, a force push or a production delete waits until someone approves it from the command line, Slack or the web. The approval covers those exact arguments and works once.
+1.6%wall time on a real agentOpenAI customer-service demo, 10 conversations, every call recorded - 03 / 03
seq 0 run.start ✓ agent support-desk hash a41f0c… prev 000000… seq 1 policy.decision ✓ allow Read hash 7c2e9a… prev a41f0c… seq 2 tool.result ✓ ok · 3 rows hash 3b8d41… prev 7c2e9a… seq 3 approval.consumed ✓ issue_refund hash f0619e… prev 3b8d41… seq 4 policy.decision ✓ deny Bash hash 9e4c27… prev f0619e… seq 5 run.end ✓ status ok hash 62da1b… prev 9e4c27… Hover to tamperIntegrity: VERIFIED. Signed and chained.
Each record is signed and linked to the one before it. Export a run and anyone can verify it offline, without having to trust you.
1 edit→ Integrity: FAILEDtracekit demo --server: seq 4: hash does not match the event
One line in your agent. Every tool call goes through Tracekit.
Tracekit sits between your agent and its tools. You keep your framework, your prompts and your model provider.
- 01
One line to set up.
tracekit.instrument()finds the frameworks you use and hooks into them: OpenAI Agents SDK, LangGraph, the Claude Agent SDK and MCP. - 02
A run per conversation. On a long-running server, each conversation gets its own run. You can export and verify each one separately.
- 03
Blocked calls come back as answers. When Tracekit blocks a call, the model gets a refusal it can read, and the agent decides what to do next.
import tracekitfrom agents import Agent, Runnerrun = tracekit.instrument("support-desk") # gates and records every tool callagent = Agent(name="support", tools=[lookup_order, issue_refund])conversations = {} # conversation id -> its runasync def respond(cid, message, ctx): if cid not in conversations: conversations[cid] = run.client.run("support-desk", principal=cid) with conversations[cid].current(): # this request records into it result = Runner.run_streamed(agent, message, context=ctx) async for event in result.stream_events(): yield event# when the conversation ends: conversations.pop(cid).close()
pip install tracekit-aitracekit lastSee what every run did. And why it ended the way it did.
tracekit view opens every run on your machine.
01Runs
Each run and its result.
Each run shows whether it verified, its calls and any gaps.

- 1Every run, and how many verified.
- 2Calls, blocked, held for a person, and signed gaps.
02Decisions
Each decision and its rule.
What was allowed, blocked or held, and which rule decided it.

- 1A denied call, blocked before it ran.
- 2The decision, and the rule that made it.
03Approvals
Who approved what.
Each approval is tied to the exact arguments it covered.

- 1One filter for every hold, approval and rejection.
- 2Each run's review counts the calls held for a person.
04Whyexperimental
Find the cause.
Replay the run without each suspect input and see what changes.

- 1A confirmed cause, drawn in red to the call it changed.
- 2Replayed without it, the email went out 0% of the time, not 90%.
05Proof
Export and verify.
A run exports to one .tkb file that anyone can check offline.

- 119 signed records, from the runs that verified.
- 2Verified by the same check anyone can run on the .tkb, offline.

Decide what your agents may do. Tracekit keeps the proof.
Start from ready-made policy packs for shell, SQL, HTTP, cloud CLIs, payments and messaging.
Policy referenceversion: 'acme-1'extends: packs/server.yaml # unmapped tools wait for a persontools: run_shell: shell query_orders: sql issue_refund: paymentask TK-M001 · sending money send_email: email lookup_customer: appuntrusted: [http, mcp]
$ tracekit verify run.tkb --trust trust.json[PASS] manifest — every file is listed with its SHA-256 and nothing else is in the bundle[PASS] checkpoint — tracekit.local/72ba284d… at tree size 12, signed by its pinned log key[PASS] witness quorum — 1 pinned cosignature(s), 1 required[PASS] keys — 1 record key(s) from 1 key record(s)[PASS] signatures — 11 record(s), keys valid at their position[PASS] run chain — run '0a026d8b…' of tenant 'default', contiguous from run_seq 0[PASS] inclusion — first and last records of 1 run(s) are in the checkpointed tree of size 12Integrity: VERIFIED.Assurance: dev; records ed25519; checkpoint Ed25519 only; cosigned ed25519 by witness.demo.tracekit.local …
From a policy line to a signed record.
The policy decides before the call runs. The signed log shows what happened after.
illustrative · real output format
Outages leave a signed gap
If the signer is down, fail-closed tools are blocked. A tool you set to fail open still runs, and the next call writes a signed gap that covers exactly what was missed.
Witnesses you choose experimental
Whoever runs the signer could rewrite its own log. An independent witness and a monitor would show it, and every verify report says which level a bundle reached.
Try a risky call. See what Tracekit decides.
Pick a tool call an agent might make. The verdict comes from Tracekit's real policy engine, using the pack you choose.
server-hosted agents · unmapped tools ask
{ "charge": "ch_3PzX9kL2", "amount": 4000000, "currency": "usd" }Refund $40,000 to a customer: ask under the server pack, rules TK-M001, TK-M002.
- toolcreate_refund
- classpayment
- fieldsamount · currency
- rulesTK-M001 TK-M002
TK-M001asksending moneyserver-comms.yamlTK-M002askmoving moneyserver-comms.yaml
Held for a person. The approval is bound to these exact arguments and can be used once.
{"v": 2, "alg": "ed25519", "kid": "sha256:…", "sig": "…", "event": {"seq": 41, "run_seq": 6, "type": "policy.decision", "prev_hash": "sha256:3f9a…e1c0", "data": {"tool": "create_refund", "decision": "ask", "rule_ids": ["TK-M001", "TK-M002"], "policy_hash": "sha256:19a49eac…5f19", "engine": "re2@1.1.20251105", "args_commitment": "hmac-sha256:…"}}}
How it decides
The policy maps the tool to a class, reads that class's fields from the raw arguments, and matches each rule's pattern against its field. Every matching rule is named; the strictest section wins. The agent can't change the policy or the class.
tool: create_refund class: payment fields: amount: 4000000 currency: "usd"
ask:
- id: TK-M001
class: payment
field: amount
pattern: '.'
reason: sending money
rationale: A payment tool call with an amount moves money; a person confirms the payee and the amount.ask:
- id: TK-M002
tool: '(mcp(:[^/]+/|__.*__))?(transfer_funds|send_(payment|money)|pay_invoice|create_(payment|payout|transfer|refund|charge|payment_intent)|(confirm|capture)_payment_intent|refund_.*)'
pattern: '^'
reason: moving money
rationale: Payouts, transfers, charges and refunds move money even without an amount argument (a full refund), and over MCP too.Decisions were computed offline with the real engine (re2@1.1.20251105) against the packs shipped in Tracekit 1.2.0 (commit f382c79). Rules match raw strings: they make attempts visible. The protection is the signer's isolation, its storage and the witnesses. Policy reference
Common questions.
What Tracekit protects, what it doesn't, and how to check.
Does it slow my agent down?
Barely. On a real agent, the OpenAI customer-service agents demo over 10 conversations, wall time went up 1.6% with every tool call and model response recorded. The signer itself adds 0.91 ms per tool call at p99 (decide and complete, 1,000 calls) in a quick run on macOS with the file store.
Read the numbers and their basisCan the agent turn it off or rewrite the log?
In dev mode, yes: the signer runs as your user, the same user as the agent, so it protects nothing against the agent itself. It still catches mistakes and blocks the obvious attempts, and every dev bundle says isolation: same-user. For real evidence, run the signer where the agent can't reach it: Linux system mode, a container or Kubernetes sidecar, or a central signer over HTTPS. The agent never holds the signing key, and an edited, dropped or reordered record fails verification.
What does a verified bundle prove, and what doesn't it?
It proves the records are the ones the signer signed: none edited, dropped, reordered or added after signing, all in one chain under a checkpoint signed by the key you pinned. It doesn't prove intent: a record says a call was made, not why. And it doesn't prove everything was recorded: an action that crosses no capture layer leaves no record, so the report lists the layers that ran and the signed gaps, and never says "complete".
What it can't proveCan Tracekit read the agent's chain of thought?
Only reasoning text the model's API returns to the agent, never reasoning the provider keeps hidden. And reasoning text is the model's own account of itself, not evidence of why it acted. tracekit why doesn't depend on it: it replays the run without each suspect input and measures what changes. Don't trust what the agent says it was thinking; test what actually caused the action.
What happens when the signer is down?
Every tool class fails closed by default: the call is blocked. A class you set to fail open runs unrecorded, and the run's next call after the outage makes the signer write a signed gap covering exactly the missed calls. The verify report warns on every fail-open class. A gap is signed, never silent.
Outage behaviourDo I need Tracekit Enterprise?
No. The open source release works on its own: the signer, policy, approvals, signed records, export and both verifiers, under the MIT license. Tracekit Enterprise is the hosted control room for teams, in early access. The signer stays in your infrastructure either way.
Plans and pricingTry it on your agent.
About two minutes to your first signed run.
It runs on your machine. No account and no API key.
01 Decides
0.91 msp99 per call
E9 quick · macOS · 1,000 calls
02 Asks
Used once
bound to the exact arguments
03 Signs
+1.6%wall time
real agent · 10 conversations
04 Proves
1 edit→ Integrity: FAILED
tampered copy · tracekit demo --server
01 Decides
0.91 msp99 per call
E9 quick · macOS · 1,000 calls
02 Asks
Used once
bound to the exact arguments
03 Signs
+1.6%wall time
real agent · 10 conversations
04 Proves
1 edit→ Integrity: FAILED
tampered copy · tracekit demo --server
Tracekit Enterprise for your team · Early access