Repository navigation
Concepts Containment
Some dangers only show as a pattern across calls: reading secrets and then sending data out, or deleting things very fast. Detection lets a policy describe such patterns, and containment decides what happens when one trips: an alert, a hold that hands every next step to a person, or a quarantine that stops the run. This is experimental. Configuration and operator commands: incidents.
sequences:
- id: TK-Q001
steps: [secrets_access, egress] # rule ids or labels, in order
scope: session
window: 600 # seconds from the first step
limits:
- id: TK-L002
match: destructive # a rule id, a label, or * for every call
count: true # or sum: {field: cents, currency_field: currency}
max: 30
window: 60
scope: session
respond:
- {trigger: TK-Q001, mode: enforce, action: hold}
- {trigger: executed_against_policy, mode: enforce, action: quarantine}
- {trigger: denied_calls, mode: enforce, action: notify, max: 5, window: 300}-
Sequences are steps in order within a window, for example a call labelled
secrets_accessfollowed by one labelledegress. - Counts and sums fire when calls matching a rule or label pass a maximum in a window, such as more than 300 calls a minute or a total payment amount.
-
Built-in triggers include
executed_against_policy, repeated denials, provenance holds and network traffic no call explains (from the egress observer). What a kernel sensor reports (processes, file writes, connections) opens no incident:tracekit analyze --v2checks it against the calls after the run (what was asked, said and done). - Scopes are the run, the session (a run and its sub-agents), the owner or the principal.
-
Modes are
off,shadow(record what would have happened) andenforce. The server pack ships its detections in shadow mode.
Detection is a pure function of the signed records, run by the signer's single writer as each record is written. It reads the rule ids and labels each decision already carries, and runs no new regular expressions. Replaying the records, backtesting a policy, and the verifier therefore all reach the same incidents.
Only calls that actually ran count: allowed calls, flagged calls, and asks whose approval was consumed. Denied calls and unused asks don't. A tool of unknown class matches every step, so an unmapped tool can't slip between steps.
If the signer can't vouch for what came before (a restart that lost the detector's state) and the policy enforces a
hold or quarantine, the decision's run is held under a detector_unavailable incident: detection fails closed.
| Action | What happens |
|---|---|
notify |
An alert goes to the incident webhook. Nothing is blocked |
hold |
The run's live approvals expire, and every later call becomes ask TK-HOLD, answerable only by a person (never an agent approver, the run's owner, principal or requester). The call that triggered the hold is decided again, held. With no person approvers configured, a hold becomes a quarantine |
quarantine |
Permanent. Calls are denied (TK-QUARANTINE), approvals can't be consumed, the LLM gateway stops forwarding the run's model requests, and the run closes |
suspend |
An operator action only (tracekit signer incidents suspend): blocks an identity entirely. A policy can't trigger it |
Cooldown inheritance. For cooldown_s (default one hour) after a hold or quarantine, new runs of the same owner
and principal, and child runs of a held run, start held or quarantined too. Starting a fresh run doesn't escape
containment.
Each trigger opens a signed incident.opened record with the trigger, the rules, the scope, the records it cites, the
mode and what it did (or, in shadow mode, would have done). Updates and resolutions are signed too. Per-run and
per-tenant caps stop a noisy pattern from flooding the log.
The webhook outbox sends incidents as OCSF 1.3 findings or Slack messages. Each OCSF body carries an HMAC signature, so a receiver can tell real alerts from forged ones (a Slack webhook's URL is its secret). Incident alerts are delivered at least once: the outbox only moves past an alert after a successful response, and retries with backoff for as long as it takes (a 4xx refusal other than 408 or 429 skips the batch). Setup: webhooks.
An operator could claim a run was contained when it wasn't. The verifier recomputes run-scope incidents from the
records and the bundled policy snapshot, and checks that a hold was followed by run.held, that nothing was allowed
after a hold without a person's approval citing the incident, and that only denials followed a quarantine. An allow
after a hold fails verification, in both verifiers. Session-, owner- and principal-scope incidents span other runs, so
the verifier counts them as stated by the signer.
A hold or quarantine is always recorded. It is enforced for certain only where the signer controls execution: the tool executor, the MCP gateway and the LLM gateway (T2). On in-process paths (T1), the adapter obeys the signer's answers, but an agent that bypasses its adapter isn't stopped, only recorded as far as any layer sees it.
Incidents · webhooks · detection:
tracekit/signer/detect.py
Previous: Approvals · All concepts · Next: Capture and completeness
Generated from docs/ at v1.4.2. 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
- Hermes Agent
- 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
- Tracekit for auditors
- 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
- A production bucket
- Completeness and tamper evidence
- Detection and containment
- Network coverage: an egress observer
- Guardrails: allow, deny, or ask a person
- MCP tools, gated and recorded
- A production volume
- Prompt injection held by provenance
- Why: which input caused the action
Help