Skip to content
SpendByTeam

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.

MetricUnitMeaning
cost.usageUSDEstimated cost of each request
token.usagetokensInput, output and cache token counts
session.countcountSessions started
lines_of_code.countcountLines added / removed (a number, not the lines)
commit.countcountCommits created
pull_request.countcountPull requests opened
code_edit_tool.decisioncountEdits accepted vs rejected
active_time.totalsecondsActive time
POST /v1/metrics — one data point (abridged resource)json
{
  "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
POST /v1/context — complete bodyjson
{
  "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

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

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

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

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

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

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

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

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

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