Security & privacy
We don’t see your code or your prompts.
Not “we promise not to look”. The pipeline is built so that content is never emitted, never accepted and never stored. This page shows you exactly what we receive, byte for byte, and how each guarantee is enforced.
Never collected, under any setting
Prompts
What developers type to the agent
Responses
What the model writes back
Source code
Files read, diffs, generated code
Tool inputs
Arguments passed to tools
Shell commands
Anything the agent runs
File paths
Including the working directory
Credentials
Stripped from repo URLs before sending
API keys
Your provider key never touches us
What we receive
Two kinds of request. Here they are, unedited.
1 · Usage metrics POST /v1/metrics
Standard OpenTelemetry metrics emitted by the coding agent itself, every 60 seconds. Each data point is a number plus a few labels. This is one cost data point; token, session and line-count metrics have the same shape.
| Metric | Unit | Meaning |
|---|---|---|
| cost.usage | USD | Estimated cost of each request |
| token.usage | tokens | Input, output and cache token counts |
| session.count | count | Sessions started |
| lines_of_code.count | count | Lines added / removed (a number, not the lines) |
| commit.count | count | Commits created |
| pull_request.count | count | Pull requests opened |
| code_edit_tool.decision | count | Edits accepted vs rejected |
| active_time.total | seconds | Active time |
{
"resourceMetrics": [{
"resource": { "attributes": [
{ "key": "service.name", "value": { "stringValue": "claude-code" } }
]},
"scopeMetrics": [{
"metrics": [{
"name": "claude_code.cost.usage",
"unit": "USD",
"sum": {
"aggregationTemporality": 1,
"dataPoints": [{
"asDouble": 0.4127,
"startTimeUnixNano": "1760693952000000000",
"timeUnixNano": "1760694012000000000",
"attributes": [
{ "key": "session.id", "value": { "stringValue": "6f1c2a9e-4b7d-…" } },
{ "key": "user.email", "value": { "stringValue": "[email protected]" } },
{ "key": "model", "value": { "stringValue": "<model-id>" } },
{ "key": "vcs.repository.url.full",
"value": { "stringValue": "https://github.com/acme/checkout-api" } }
]
}]
}
}]
}]
}]
}2 · Session context POST /v1/context
Sent by our open-source hook when a session starts or the working directory changes. It lets us attach branch and ticket to the spend, so you get cost per PR and per ticket. The hook runs in the background, has a 10-second timeout, and always exits cleanly — it can’t slow down or break a session.
- repo_url — credentials like user:token@, query strings and fragments are stripped first; local-path and file:// remotes are never sent
- branch — empty in a repo without commits or on a detached HEAD
- ticket — the first ABC-123 pattern in the branch name, if any
- cwd — not sent
{
"session_id": "6f1c2a9e-4b7d-4e0a-9c55-0d2f8e1b7a43",
"event": "SessionStart",
"repo_url": "https://github.com/acme/checkout-api.git",
"branch": "KST-482-rate-limits",
"ticket": "KST-482",
"at": "2026-10-17T09:41:12Z"
}The attribute allowlist
Every metric attribute not on this list is dropped at ingest, before queueing. If a future agent version starts emitting a new attribute, we ignore it until we’ve reviewed it.
- session.id
- user.email
- user.account_uuid
- organization.id
- model
- type
- query_source
- agent.name
- skill.name
- decision
- start_type
- vcs.repository.url.full
- vcs.repository.name
- vcs.owner.name
- vcs.provider.name
- team.id
- app.version
- terminal.type
How it’s enforced
Ten controls, in plain language
- 01
Exporters switched off
The installer sets OTEL_LOGS_EXPORTER=none and OTEL_TRACES_EXPORTER=none. Logs and traces are the only OpenTelemetry signals that can carry content; with them off, it is never emitted. The content flags (user prompts, tool details, raw API bodies) are never touched and stay at their default: off.
- 02
Endpoints that refuse to read
/v1/logs and /v1/traces exist only so a misconfigured exporter doesn’t retry forever. They return 200 and drop the request body without parsing or storing it.
- 03
Attribute allowlist
On /v1/metrics, only metrics named claude_code.* are accepted and every data point is filtered against a fixed list of 18 attribute keys. Anything else is discarded before it reaches a queue or a database. An integration test asserts that a non-allowlisted attribute can never be stored.
- 04
No working directory
The hook reads the working directory locally to ask git for the remote and branch — and sends neither the path nor anything inside it. Usernames and folder structures never leave the machine.
- 05
Write-only ingest tokens
Tokens look like sbt_ing_ + 32 random bytes. We store only a SHA-256 hash. A token can send data but cannot read anything — a leaked token exposes nothing. Revoke it from the dashboard in one click; requests are rate-limited per token.
- 06
Tenant isolation in the database
Every table carrying an org_id is protected by Postgres row-level security, set per request. The application’s database role cannot bypass it.
- 07
Pseudonymous mode
In anonymous mode developer emails are stored as an HMAC-SHA256 with a per-org salt, and the dashboard shows “Dev #4” instead of a name. Repository URLs can be hashed too.
- 08
EU hosting & retention
Data is stored and processed in the EU (Germany/Finland). Default retention is 13 months, configurable per org. Deleting an org permanently deletes its data after a 7-day grace period. Encrypted daily backups.
- 09
Provider keys, isolated
If you choose to reconcile against your provider’s cost API, the admin key is envelope-encrypted and only an isolated sync worker can decrypt it — and only call usage and cost endpoints. The web app has no access. You’ll only ever see its last four characters.
- 10
Dashboard hardening
TOTP two-factor auth, HttpOnly + SameSite session cookies, strict CSP, and an audit log of who viewed or changed what.
Verify it yourself
The installer and hook are MIT-licensed. Read them, or point the exporter at your own OpenTelemetry collector for a day and inspect every byte before switching it to us. Org-wide installs use managed settings, which also stop anyone from redirecting the data somewhere else.