v1.2.0See what's new in this release

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
TRACEKITVIEW
▶RUN coding-agent·7c4b · POLICY acme-1 ← server.yaml · SEQ 1
LIVECHAIN ✓ 2 SIGNED RECORDS09:41:08
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
SIGNED EVENT · SHA-256 OF ITS CANONICAL JSON
{
 "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

  1. #0 run.registeredprev → hash
  2. #1 policy.decisionprev → hash
click a row for its signed record

Interactive demo · simulated run · resets on reloadHashes are real SHA-256 over canonical JSON, computed in your browser.
Works with the agents you already runAll integrations
  • Claude Code
  • OpenAI Agents SDK
  • LangGraph
  • Claude Agent SDK
  • MCP
  • CrewAIexp
  • Vercel AI SDKexp
  • Cursorexp
Built on open standardsRead the format
  • Ed25519record signatures
  • RFC 6962Merkle tree log
  • RFC 8785canonical JSON
  • C2SPsigned checkpoints
  • tlog-cosignatureindependent witnesses
  • MITopen source
What it does

Tracekit checks every action before it runs. Then it signs a record that anyone can check.

System
Agents you runAgents you buildClaude CodeCodex · CursorGemini CLIand moreYour appPython · TypeScriptToolsShellDatabasePaymentsEmail · HTTPPOLICYALLOW · DENY · ASKRecords ↓Proof ↑TracekitDECIDES · SIGNS · CHAINSPeopleAPPROVES WHAT'S HELDSigned logHASH-CHAINEDCHECKPOINTEDWITNESSED.tkbVERIFY ANYWHERE

Agents you run

  • Claude Code
  • Codex · Cursor
  • Gemini CLI and more

Agents you build

  • Your app Python · TypeScript
CALLS ↓

Tracekit

DECIDES · SIGNS · CHAINS

POLICYallowdenyask

ALLOWED ↓
HELD ↓

Tools

  • Shell
  • Database
  • Payments
  • Email · HTTP

People

Approves what's held

RECORDS ↓ · PROOF ↑

Signed log

HASH-CHAINED · CHECKPOINTED · WITNESSED

.tkb → verify anywhere

Hover a partillustrative

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.

Tracekit/Every action

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.

HOLD · waits for a personTOOL CALLSReadqueryBashHOLDissue_refundReadDENYBashqueryHOLDsend_emailReadDENYqueryDENIEDtracekit signer
Hover to slow timedecided 7 · denied 1 · held 1
  1. 01 / 03
    HOLD · waits for a personTOOL CALLSReadqueryBashHOLDissue_refundReadDENYBashqueryHOLDsend_emailReadDENYqueryDENIEDtracekit 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
  2. 02 / 03
    HELD CALLSAPPROVER · CLI · WEB · SLACKissue_refundamount=4000order=1042args sha256:9f2c…APPROVEDAPPROVERRUNonce, as approvedTK-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
  3. 03 / 03
    seq 0run.start✓agent support-deskhash a41f0c…prev 000000…seq 1policy.decision✓allow Readhash 7c2e9a…prev a41f0c…seq 2tool.result✓ok · 3 rowshash 3b8d41…prev 7c2e9a…seq 3approval.consumed✓issue_refundhash f0619e…prev 3b8d41…seq 4policy.decision✓deny Bashhash 9e4c27…prev f0619e…seq 5run.end✓status okhash 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
TRACEKIT/AGENTS YOU BUILD

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.

  1. 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.

  2. 02

    A run per conversation. On a long-running server, each conversation gets its own run. You can export and verify each one separately.

  3. 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.

Python · TypeScript · 4 stable integrationsQuickstarts
server.py
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-ai
$tracekit last
OpenAI Agents SDK·LangGraph·Claude Agent SDK·MCP·CrewAIexp·Browser Useexp·Vercel AI SDKexp
TRACEKIT/SEE EVERY RUN

See what every run did. And why it ended the way it did.

tracekit view opens every run on your machine.

Viewer tour

tracekit view · open source · demo data

  1. 01Runs

    Each run and its result.

    Each run shows whether it verified, its calls and any gaps.

    tracekit view: two runs marked VERIFIED, each with its calls, blocked calls, held calls and gaps, beside the tape of signed records.
    1. Every run, and how many verified.
    2. Calls, blocked, held for a person, and signed gaps.
    Runs and the tape
  2. 02Decisions

    Each decision and its rule.

    What was allowed, blocked or held, and which rule decided it.

    tracekit view: a BLOCK row selected on the tape; the detail panel shows the decision DENY to BLOCKED and the rules TK-D003 force push and TK-F004.
    1. A denied call, blocked before it ran.
    2. The decision, and the rule that made it.
    Policy reference
  3. 03Approvals

    Who approved what.

    Each approval is tied to the exact arguments it covered.

    tracekit view: a run's review with integrity VERIFIED and its calls allowed, flagged, denied and held; the tape has an Approvals filter.
    1. One filter for every hold, approval and rejection.
    2. Each run's review counts the calls held for a person.
    How approvals work
  4. 04Whyexperimental

    Find the cause.

    Replay the run without each suspect input and see what changes.

    tracekit view: the run's data flow with confirmed causes in red, and candidate causes tested by replay, two of them PRIMARY CAUSE.
    1. A confirmed cause, drawn in red to the call it changed.
    2. Replayed without it, the email went out 0% of the time, not 90%.
    How why works
  5. 05Proof

    Export and verify.

    A run exports to one .tkb file that anyone can check offline.

    tracekit view: a signed run's graph, five tool calls in run order with their signed decisions, under the header CHAIN, 19 signed records.
    1. 19 signed records, from the runs that verified.
    2. Verified by the same check anyone can run on the .tkb, offline.
    The .tkb format
tracekit view: two runs marked VERIFIED, each with its calls, blocked calls, held calls and gaps, beside the tape of signed records.

tracekit view · open source · demo data

TRACEKIT/GOVERN

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 reference
version: '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

Signer outage3 calls · recorded as one signed gap

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.

WitnessesAssurance: dev

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.

TRACEKIT/PLAYGROUND

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.

Policy playground
Policy packserver.yaml

server-hosted agents · unmapped tools ask

Pick a call1 of 11
The callread-only
tool create_refundclass payment
{ "charge": "ch_3PzX9kL2", "amount": 4000000, "currency": "usd" }

Refund $40,000 to a customer: ask under the server pack, rules TK-M001, TK-M002.

Decision · server.yaml
ASK
held
2 rules matched·strictest wins: deny › ask › flag › allow
  1. toolcreate_refund
  2. classpayment
  3. fieldsamount · currency
  4. rulesTK-M001 TK-M002
  • TK-M001asksending moneyserver-comms.yaml
  • TK-M002askmoving moneyserver-comms.yaml
What happens next

Held for a person. The approval is bound to these exact arguments and can be used once.

Signed recordillustrative · decision, rule ids, policy hash and engine are real
{"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:…"}}}
↑ ↓ step through calls · interactive demodecided by the real engine · re2@1.1.20251105 · tracekit f382c79
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.

This call, as the policy reads it
tool: create_refund
class: payment
fields:
  amount: 4000000
  currency: "usd"
The matching rules, verbatim
server-comms.yamlTK-M001
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.
server-comms.yamlTK-M002
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

Before you install

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 basis
Can 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.

Choose a deployment
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 prove
Can 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.

How tracekit why finds the cause
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 behaviour
Do 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 pricing
Get Tracekit

Try 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

Get Tracekit

  1. 1Install
    $pip install tracekit-ai
  2. 2Connect its hooks to a local signer
    $tracekit init --dev --v2
  3. 3Run Claude Code as usual, then check the run
    $tracekit last
Runs on your machine. No account and no API key. GitHubDocs

Tracekit Enterprise for your team · Early access