> ## Documentation Index
> Fetch the complete documentation index at: https://docs.asymptotelabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Claude Code

> Asymptote support details for Claude Code endpoint telemetry

## Runtime overview

Asymptote supports Claude Code through local OpenTelemetry export to Asymptote's localhost collector, optional hook telemetry for richer lifecycle and tool activity, and local session-file sync for historical backfill.

## Prerequisites

Before enabling Claude Code telemetry, make sure:

* Claude Code is installed and available as the `claude` executable for the user or managed endpoint.
* `beacon endpoint install` has run so the local collector, endpoint config, and runtime log path exist.
* The install includes the `claude` harness, either through automatic runtime discovery or an explicit `--harness claude` value.
* Your team has reviewed content handling and destination access for prompt telemetry.

## Collection paths

Claude Code exports OTLP telemetry to the local Asymptote collector. Asymptote writes normalized [endpoint events](/concepts/core-concepts#endpoint-event) to the configured runtime JSONL log and makes them available in the local dashboard.

The OTLP export carries prompts, tool calls, commands, approvals, and token usage, but not session boundaries, file reads and diffs, or subagent lifecycle. Those come from Claude Code hooks. When the `claude` harness is selected, `beacon endpoint install` and `repair` install the user-level hooks together with OTLP settings.

```bash title="Inspect or remove Claude Code hooks" theme={null}
beacon endpoint hooks status --harness claude
beacon endpoint hooks uninstall --harness claude
```

User-level hooks are written to `~/.claude/settings.json`. Project-level hooks are written to `./.claude/settings.json`:

```bash title="User-level hooks are written to ~/.claude/settings.json. Project-level hooks are written to ./.claude/settings.json" theme={null}
beacon endpoint hooks install --harness claude --level project
```

For backfill, Asymptote can also read Claude Code's committed JSONL session files under `~/.claude/projects`:

```bash title="Sync Claude Code session files" theme={null}
beacon endpoint claude status
beacon endpoint claude sync
```

The sync path is local and offline. It appends mapped events to the runtime log with `harness.collection_method=poll`, so it can recover historical sessions or sessions that ran before hooks were installed, but it cannot hold, approve, deny, or delay tool calls. Use `beacon endpoint claude sync --print` to preview mapped events without writing the runtime log or advancing the cursor.

## Claude Code Cloud Agents

Asymptote also supports proof-of-concept telemetry capture from Claude Code
cloud agents. The cloud setup path installs ephemeral Beacon hooks inside the
Claude cloud sandbox, writes `/tmp/beacon/runtime.jsonl`, and uploads the
session log to customer-managed Google Cloud Storage.

Start with [Claude Code Cloud Agents](/runtimes/claude-code-cloud-agents) when you want to
test Claude Code cloud agent telemetry without deploying Asymptote Managed.

<Warning>
  The self-serve GCS path passes a scoped service-account credential to the
  Claude Code cloud environment. Use it for evaluation and prototypes. For
  production enterprise deployments, use [Asymptote Managed](/deployment/managed)
  or contact Asymptote about secure forwarding in your own customer-managed
  infrastructure.
</Warning>

## Discovery and status

Asymptote detects Claude Code through the `claude` executable and Claude settings paths. Use `beacon endpoint discover` or `beacon endpoint status` to confirm that Claude Code is present and configured for local telemetry. Use `beacon endpoint claude status` to inspect local session files and how far the sync cursor has read.

## Install or configuration support

`beacon endpoint install` configures Claude telemetry settings so Claude Code sends OTLP data to the local collector. It enables detailed tool logging so tool-result events include inputs such as Bash commands, file paths, URLs, search patterns, and MCP server/tool arguments. Claude bounds or truncates some input values.

`beacon endpoint hooks install --harness claude` adds Asymptote-managed Claude Code hooks while preserving existing Claude settings and non-Asymptote hooks. Install, repair, and uninstall preserve non-Asymptote `command`, `http`, `prompt`, and `agent` hook entries verbatim, including fields Asymptote does not interpret such as URLs and headers.

### Model context from API bodies

Some context Claude Code gives the model appears only in API-body logs (`OTEL_LOG_RAW_API_BODIES`). Those logs also carry the system prompt, the whole conversation, tool definitions, and tool results on every model call, so Beacon leaves them off unless you opt in:

```bash title="Record model context Claude Code reports only in API bodies" theme={null}
beacon endpoint install --claude-capture-model-context
```

With the flag, install and repair set `OTEL_LOG_RAW_API_BODIES=1` in `~/.claude/settings.json`, and the choice is recorded as `claude_capture_model_context` in Beacon's `config.json`. Without it, install or repair removes an inline `1` or `true` setting, so a repair without the flag turns capture off. Neither touches `0` or `file:<dir>`. `beacon ci exec` does not set the variable; a CI job opts in by setting `OTEL_LOG_RAW_API_BODIES=1` in its own environment.

The collector filters API bodies in its `claude_api_body` processor before every destination, including the local runtime log, Falcon, and Splunk HEC. With capture on, it keeps only the WebFetch and MCP context described below. With capture off, it drops every body, so turning `OTEL_LOG_RAW_API_BODIES` on yourself sends Beacon nothing it keeps. Install stops with an error if the collector binary it would use is too old to have this processor.

#### Fetched web pages

Claude Code's WebFetch tool sends the fetched page to a separate summarizer model call; the main model receives only the summary. With model-context capture on, Beacon keeps only the text of that summarizer request's user messages: the fetched page and summarizer prompt. It removes the raw body fields and forwards that text as a `WebFetch` tool result, redacted and capped at 2048 characters. Threat rules read it through the same retained tool-result text field as fetched pages from other runtimes.

#### MCP tool descriptions

Every Claude Code model request carries the MCP tool definitions the model sees. With model-context capture on, Beacon keeps only each MCP tool's name and description, redacted and capped at 4096 characters. Each tool is listed once per session, and again only if its description changes, as an `mcp.tool_listed` event. This is an advertisement, not a tool call, so it is never counted as MCP activity.

## Telemetry coverage

| Area | Support |
| - | - |
| Prompt telemetry | Supported when emitted through Claude Code OTLP or hooks |
| Turn identity | Supported. Claude Code's `prompt.id` is kept as `prompt.id` on OTLP events; hook events after the prompt read the same id from the session transcript, and `beacon endpoint claude sync` reads it from `promptId` |
| Command, tool, and file telemetry | Supported through Claude Code OTLP with detailed tool inputs enabled. Command output requires hooks |
| Token usage and cost | Supported through OTLP token and cost metrics, with per-model and per-session attribution |
| Hook lifecycle and tool telemetry | Optional through `beacon endpoint hooks install --harness claude` |
| Historical session sync | Supported through `beacon endpoint claude sync`; marked as poll collection |
| Claude Code cloud agent sessions | Supported through cloud sandbox hooks with GCS upload |
| Model-visible skill listings | Supported through Claude transcript `attachment.type=skill_listing`, one part per skill in `gen_ai.system_instructions`, with the skills named in `system_context`; invoked skill file bodies remain excluded |
| Model-visible MCP tool descriptions | Opt-in with `--claude-capture-model-context`. One `mcp.tool_listed` per MCP tool per session; see [MCP tool descriptions](#mcp-tool-descriptions) |
| Local JSONL and dashboard | Supported |
| MDM deployment | Supported through the system-mode package or MDM-managed settings |

Claude Code hooks cover `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `Stop`, `SubagentStart`, `SubagentStop`, `PermissionRequest`, and `SessionEnd`. Pre-tool matching includes common Claude tools such as `Bash`, `Edit`, `Write`, `MultiEdit`, `Read`, `Glob`, `Grep`, `WebFetch`, `WebSearch`, `Agent`, and `mcp__.*`.

## Normalized OTLP events

Beacon maps Claude Code's OTLP logs into canonical endpoint actions instead of
treating every unrecognized record as a tool invocation:

* `user_prompt` becomes `prompt.submitted`.
* A successful or failed `Bash` `tool_result` becomes `command.executed`, with
  the decoded command in `command.command` and the reported duration in
  `command.duration_ms`.
* `Read` results become `file.read`; `Write`, `Edit`, and `NotebookEdit` results
  become `file.modified`, with the decoded path in `file.path`.
* Accepted and rejected `tool_decision` records become `approval.allowed` and
  `approval.denied`. Bash decisions also retain the full command when Claude
  provides it.
* API requests, assistant responses, hooks, plugins, skills, compaction, and
  other ordinary lifecycle records become session activity. API and internal
  errors become `session.error`; refusals and permission-mode changes become
  `session.status`.
* MCP server connection lifecycle records become `mcp.connection`, not
  `mcp.tool_invoked`.

Claude reports tool success and duration but does not provide an exact process
exit status, so Beacon does not invent `command.exit_code`. The original OTLP
attributes remain under `raw.attributes`, subject to the configured redaction
and event-size controls. Future full-body `claude_code.*` lifecycle records
default to `session.activity` until Beacon assigns a more specific mapping.

Optional hooks add detail that OTLP does not report. A pre-tool hook can appear
as `tool.invoked`, and the Bash post-tool hook records the command's output in
`command.output`. For a successful command, Claude reports stdout and stderr
separately, so Beacon stores stdout first and stderr after it. When a command
exits with a non-zero status, Beacon also records the exit code in
`command.exit_code` and sets the event's severity to `high`. Output is redacted
and size-limited like other retained content.

Detailed tool inputs can contain sensitive command arguments, paths, URLs, search terms, and MCP request data. Beacon sends this telemetry only to the configured local collector during normal endpoint execution; apply the same access, retention, and redaction controls used for other retained prompt and tool data.

## Session-file sync

`beacon endpoint claude sync` reads committed Claude Code transcripts after Claude has written them. The cursor is stored in Beacon endpoint state, not in Claude's directory, and tracks files by line so scheduled runs do not re-append the same records. A partly written trailing record is left for the next sweep.

Claude Code writes one streamed API response as several transcript lines, one per content block, and every line carries a copy of the response's usage. The sync emits one `token.usage` event per response, not per line, and corrects later sweeps when a response was split across files or sweeps.

When Claude Code records an `attachment` whose type is `skill_listing`, sync emits `session.context` with one `text` part per skill in `gen_ai.system_instructions`, plus a `system_context` block naming each skill. Rules match the text as `e.gen_ai.system_instructions_text`. This is the model-visible skill index, not an operator prompt, so it is never written to `prompt` or `gen_ai.input`.

Run `beacon endpoint claude sync --watch`, or schedule one-shot sweeps, if you want the poll path to stay current. The live OTLP and hook paths remain the real-time integrations; the poll path is for backfill and catch-up.

### Large backfills and log rotation

A large first sync stops before rotation would delete output written by that
sweep. Remaining session cursors stay pending for the next run, and JSON output
reports `events_retained`, `events_rotated_out`, `retention_limited`, and
`sessions_pending`.

To increase the rotation window for one backfill:

```bash theme={null}
beacon endpoint claude sync --rotate-bytes 1073741824
```

The archive count remains five, live hooks and the collector continue using
their configured rotation size, and later sweeps can rotate output from earlier
sweeps. Ship or copy logs between sweeps when every backfilled event must be
retained.

## Deployment notes

For MDM deployments, use the signed and notarized macOS `.pkg` so endpoint events land in `/var/log/beacon-agent/runtime.jsonl`. The package installs the endpoint agent under `/opt/beacon`, creates system endpoint configuration, and loads the local collector LaunchDaemon.

If a system collector is running while the CLI is reading the default per-user log, `beacon endpoint status` and the local dashboard surface a runtime-log source warning so you can tell where OTLP events are being written.

## Related

<Columns cols={2}>
  <Card title="Supported agent harnesses" icon="list-check" href="/runtimes">
    Return to the runtime support overview.
  </Card>

  <Card title="Agent harness integration model" icon="plug" href="/runtimes/integration-model">
    See how Asymptote discovers and configures supported runtimes.
  </Card>

  <Card title="Runtime hooks" icon="plug" href="/cli/hooks">
    Install, inspect, and uninstall Claude Code hook telemetry.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.