# Agent Telemetry

> **Beta, early access.** Flag: `agent_telemetry`. A workspace without access gets `404` from the telemetry routes.

Trailers and footers say an agent wrote a change; telemetry proves it. Zero setup for developers: your admin enables it once for the whole org. This page is for owners, admins and the IT team that manages developer machines.

Claude Code exports OpenTelemetry usage events. With agent telemetry on, those events go to Bumpkit, signed with an ingest key your admin creates. When an event lines up with a commit or pull request from the [GitHub App](/docs/release-gate#the-github-app), the release gets a **verified** authorship signal.

Developers install nothing and change nothing. IT pushes one managed settings file, and every Claude Code session on those machines reports in.

## How it works

1. An owner or admin turns on agent telemetry and creates a named ingest key in Bumpkit.
2. Bumpkit shows a `managed-settings.json` snippet with the endpoint and the key filled in.
3. IT pushes that file to developer machines through device management.
4. Claude Code reads the managed settings at startup and exports usage events to Bumpkit with the key.
5. Events that line up with commits and pull requests from the GitHub App show on the release as a verified signal.

## Set it up

### For admins

Owners and admins open **Settings** and go to **Agent telemetry**.

1. Turn agent telemetry on for the org.
2. Pick the repositories it covers, or leave it on all repositories.
3. Create an ingest key and give it a name, such as `Fleet macOS 2026`. Set an expiry and, optionally, an IP allowlist.
4. Copy the key. Bumpkit shows it once and stores only its hash.
5. Copy the `managed-settings.json` snippet and hand it to IT.
6. Click **Test connection** after IT rolls it out.

Telemetry starts in **Observe only**. Matched events show on releases but never change a gate outcome. Switch to **Counts toward the gate** when you trust the data. See [How it affects the gate](#how-it-affects-the-gate).

### For IT

The snippet sets Claude Code's [OpenTelemetry environment variables](https://code.claude.com/docs/en/monitoring-usage) through the managed `env` key. It looks like this, with your key in place of `bkt_YOUR_KEY`:

```json
{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_LOGS_EXPORTER": "otlp",
    "OTEL_METRICS_EXPORTER": "otlp",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "https://bumpkit.dev/v1/otlp",
    "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": "https://bumpkit.dev/v1/otlp/v1/logs",
    "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "https://bumpkit.dev/v1/otlp/v1/metrics",
    "OTEL_EXPORTER_OTLP_HEADERS": "x-bumpkit-ingest-key=bkt_YOUR_KEY",
    "OTEL_LOG_TOOL_DETAILS": "1",
    "OTEL_METRICS_INCLUDE_REPOSITORY": "true"
  }
}
```

Use the snippet Bumpkit gives you, not a hand-typed copy: it carries the exact endpoint and key.

| Variable | What it does |
|---|---|
| `CLAUDE_CODE_ENABLE_TELEMETRY` | Turns on Claude Code telemetry. Required. |
| `OTEL_LOGS_EXPORTER` | Sends usage events over OTLP |
| `OTEL_METRICS_EXPORTER` | Sends usage metrics over OTLP |
| `OTEL_EXPORTER_OTLP_PROTOCOL` | The OTLP wire format |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | Bumpkit's OTLP endpoint |
| `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` | Where usage events go |
| `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` | Where usage metrics go |
| `OTEL_EXPORTER_OTLP_HEADERS` | The ingest key, in the `x-bumpkit-ingest-key` header |
| `OTEL_LOG_TOOL_DETAILS` | Adds the commit SHA to commit events, so Bumpkit can match them |
| `OTEL_METRICS_INCLUDE_REPOSITORY` | Adds the repository to metrics. Needs Claude Code v2.1.269 or later. |

Deploy it the way you already deploy Claude Code [managed settings](https://code.claude.com/docs/en/managed-settings):

| Delivery | Where it goes |
|---|---|
| macOS file | `/Library/Application Support/ClaudeCode/managed-settings.json` |
| Linux and WSL file | `/etc/claude-code/managed-settings.json` |
| Windows file | `C:\Program Files\ClaudeCode\managed-settings.json` |
| macOS configuration profile (Jamf and similar) | The `com.anthropic.claudecode` managed preferences domain, same keys |
| Windows Group Policy or Intune | The JSON as a `Settings` string value under `HKLM\SOFTWARE\Policies\ClaudeCode` |

If you already ship a `managed-settings.json`, add the `env` entries to it, or drop the snippet into `managed-settings.d/` next to it as its own file, such as `10-bumpkit-telemetry.json`. Claude Code merges that directory into the managed settings.

Managed settings outrank user and project settings, so a developer can't turn the export off or point it elsewhere. Claude Code reads them at startup, so sessions already running pick up the change on their next start.

## Controls

Every control is for owners and admins only. Every change is written to the [audit log](/docs/compliance#audit-log) and goes out through [audit streaming](/docs/compliance#audit-streaming) and the audit event export like every other audit event.

| Control | Options |
|---|---|
| Agent telemetry | On or off for the whole org. Off means Bumpkit stores nothing it receives. |
| Mode | **Observe only** (default): never affects the gate. **Counts toward the gate**: matched events count as verified authorship. |
| Repository scope | All repositories, or the ones you pick. Events for other repositories are not kept. |
| Raw event retention | 1, 7 (default) or 30 days |
| Purge now | Deletes every stored raw event immediately |
| Identity | **Hash email** (default), **Keep email** or **Drop email** |

### Ingest keys

Create as many named keys as you need, for example one per fleet or per office.

- **Shown once.** Bumpkit stores only a hash of each key. Lose it and you create a new one.
- **Expiry.** Each key has an expiry date. An expired key is rejected.
- **Rotation.** Rotate a key to get a new secret under the same name, then push the new snippet.
- **Revocation.** A revoked key is rejected on the next request.
- **Last used.** Each key shows when it was last used and from which IP address.
- **IP allowlist.** Optional. A key with an allowlist rejects requests from any other address.

### Alerts

Bumpkit alerts owners and admins when:

| Alert | When |
|---|---|
| Unused key | A key has sent nothing for the number of days you set |
| Request from outside the allowlist | A key was used from an IP address its allowlist doesn't include |
| Rejection spike | Many requests are being rejected, such as from a revoked key still on machines |

### Monitor it

The **Agent telemetry** settings page shows:

- **Recent events**: the latest events received, with the key, repository and whether they matched
- **Test connection**: confirms Bumpkit is receiving events for a key

## Data

### What Bumpkit receives

Claude Code's OpenTelemetry export: usage events and metrics such as sessions, commits and pull requests created, lines changed, tool decisions, token counts and cost, with attributes such as the session ID, organization ID and the signed-in user's email. See Claude Code's [monitoring docs](https://code.claude.com/docs/en/monitoring-usage) for the full list.

### What Bumpkit keeps

| Data | How long |
|---|---|
| Raw events | Your retention setting: 1, 7 (default) or 30 days, then deleted. **Purge now** deletes them at once. |
| Authorship signals | Kept with the release check |
| User email | Per your identity setting: hashed (default), kept as is, or dropped |

### What Bumpkit never keeps

- **Prompts.** Claude Code doesn't export prompt text unless `OTEL_LOG_USER_PROMPTS` is set. If it is, Bumpkit discards the text.
- **Code.** Bumpkit never stores code, tool input or tool output from telemetry.
- **Anything while telemetry is off.** With the org switch off, Bumpkit stores nothing it receives.
- **Events outside your repository scope.**

See [Data Handling](/docs/data-handling) for everything else Bumpkit stores, and [Security and Compliance](/docs/security-compliance) for how telemetry fits your controls.

## How it affects the gate

An event counts only when it lines up with a commit or pull request from the GitHub App. Other events never count. A commit event lines up by its commit SHA. A commit count lines up with commits in the same repository whose author email belongs to the same person and whose time falls in that export window; the release shows it as, for example, *Claude Code reported 2 commits*. When a session also sends commit events, its commit SHAs are used and its commit counts are not. Commit counts need the identity setting to keep or hash emails, and your git `user.email` must be the email you sign in to Claude with. A commit count is **declared** authorship.

| Mode | Matched events |
|---|---|
| Observe only (default) | Show on the release as a verified signal. The gate outcome is the same as without telemetry. |
| Counts toward the gate | Count as **verified** authorship. [`when: agent`](/docs/release-gate#who-wrote-the-change) rules, including hard blocks, apply to the change. |

Telemetry adds a signal. It never removes one: the signals Bumpkit reads with no setup keep working with telemetry on or off. See [Who wrote the change](/docs/release-gate#who-wrote-the-change).

## Troubleshooting

| Symptom | Fix |
|---|---|
| **Test connection** finds no events | Confirm the managed settings reached the machine: run `/status` in Claude Code and check the managed settings source. Then start a new Claude Code session, since settings load at startup. |
| Requests rejected with an authentication error | The key is revoked, expired or mistyped. Check the key's status in **Agent telemetry**, then push a fresh snippet. |
| Requests rejected from some offices | The key has an IP allowlist that doesn't include those networks. Add the ranges, or use a separate key. |
| Events arrive but nothing is stored | Agent telemetry is off for the org, or the repository is outside its scope. |
| Events arrive but releases show no telemetry signal | The repository isn't connected through the GitHub App, or the commits haven't been pushed yet. |
| Matched events don't change the gate | Telemetry is in **Observe only**. Switch to **Counts toward the gate**. |
| Rejection spike alert | A revoked or rotated key is still on machines. Push the current snippet. |
