Claude Code plugin that captures agent activity as OpenTelemetry traces — tool calls, LLM invocations, token usage, and errors.
/plugin install dash0@claude-plugins-official
If you get "Plugin not found in marketplace", the official marketplace may not be registered yet. Run
/plugin marketplace add anthropics/claude-plugins-officialfirst, then retry the install.
/plugin marketplace add dash0hq/claude-marketplace
/plugin install dash0-agent-plugin@dash0
The plugin is registered as
dash0in the official marketplace anddash0-agent-pluginin the Dash0 marketplace. Both install the same plugin; do not enable both at once or hooks will fire twice.
In environments without interactive access (containers, CI, scripts), use the CLI:
git config --global url."https://github.com/".insteadOf "git@github.com:"
claude plugin marketplace add dash0hq/claude-marketplace --scope user
claude plugin install dash0-agent-plugin@dash0 --scope userNote: Claude Code downloads marketplace plugins via SSH by default. If SSH keys are not configured for GitHub, the
git configline above forces HTTPS. This is required in Docker containers, CI runners, or any environment without SSH access to GitHub.
After installing, configure credentials using one of these options:
Option A: Config file (recommended)
Create a config file at one of these locations:
| Location | Scope |
|---|---|
.claude/dash0-agent-plugin.local.md |
Project-level (current directory) |
~/.claude/dash0-agent-plugin.local.md |
User-level (all projects) |
Example:
---
otlp_url: "https://ingress.us1.dash0.com"
auth_token: "your-dash0-auth-token"
dataset: "default"
---Precedence order (highest to lowest):
/plugin → ConfigureUI settings- Project-level config file
- User-level config file
- Environment variables (
DASH0_*)
Option B: Plugin UI
Run /plugin → Installed → dash0 → Configure and enter your credentials. Then run /reload-plugins to apply.
If credentials are missing, you'll see on session start:
dash0: telemetry is not active — configure the plugin to start sending data.
# Test locally without marketplace
claude --plugin-dir /path/to/dash0-agent-plugin
# Build the binary locally (instead of downloading from GitHub Releases)
go build -o ~/.claude/plugins/data/dash0-agent-plugin-inline/bin/on-event-0.1.0-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/') ./cmd/on-event/The plugin registers a hook for every supported Claude Code event. Each event's payload is written as a single JSON line (with a timestamp field added) to:
~/.claude/plugins/data/dash0-agent-plugin/events.jsonl
| Category | Events |
|---|---|
| Session | SessionStart, SessionEnd |
| Turn | UserPromptSubmit, Stop, StopFailure |
| Tool | PreToolUse, PostToolUse, PostToolUseFailure |
| Permission | PermissionRequest, PermissionDenied |
| Subagent | SubagentStart, SubagentStop |
| Task | TaskCreated, TaskCompleted, TeammateIdle |
| Config | ConfigChange, CwdChanged, FileChanged, InstructionsLoaded |
| Compaction | PreCompact, PostCompact |
| Elicitation | Elicitation, ElicitationResult |
| Notification | Notification |
The plugin emits OpenTelemetry spans following GenAI semantic conventions. Key attributes:
Resource attributes (on all spans):
| Attribute | Description |
|---|---|
service.name |
Agent name (configurable via AGENT_NAME, defaults to claude-code) |
gen_ai.provider.name |
LLM provider |
Span attributes (on all spans):
| Attribute | Description |
|---|---|
dash0.gen_ai.vcs.repository.name |
Git repository name |
dash0.gen_ai.vcs.ref.head.name |
Git branch |
dash0.gen_ai.vcs.repository.url.full |
Full repository URL |
user.name |
Real name or SHA-256 hash depending on privacy setting |
Span attributes (LLM / chat spans):
| Attribute | Description |
|---|---|
gen_ai.conversation.id |
Session identifier |
gen_ai.conversation.name |
Session title |
gen_ai.request.model |
Model used |
gen_ai.usage.input_tokens |
Input tokens consumed |
gen_ai.usage.output_tokens |
Output tokens produced |
gen_ai.usage.cache_read_input_tokens |
Tokens read from prompt cache |
gen_ai.usage.cache_creation_input_tokens |
Tokens written to prompt cache |
Span attributes (tool spans):
| Attribute | Description |
|---|---|
gen_ai.tool.name |
Tool name (e.g. Bash, Read, mcp__server__tool) |
gen_ai.tool.type |
Always function for Claude Code tools |
gen_ai.tool.call.arguments |
Tool input (omitted when OMIT_IO=true, truncated to 16KB otherwise) |
gen_ai.tool.call.result |
Tool output (omitted when OMIT_IO=true, truncated to 16KB otherwise) |
By default, the plugin anonymizes telemetry:
| Setting | Default | Behavior |
|---|---|---|
OMIT_USER_INFO |
true |
user.name is emitted as a SHA-256 hash (stable per-user grouping without revealing identity). user.email is omitted. |
OMIT_IO |
true |
Prompt content and tool call inputs/outputs are stripped from spans. |
What is always collected (regardless of settings): tool names, token counts, durations, model names, session structure, error status, VCS repository/branch info.
What is omitted by default: real user name, email, prompt text, tool call arguments and responses.
To opt in to full data collection, set either option to "false" via /plugin → Installed → dash0-agent-plugin → Configure.
The plugin declares its configuration via Claude Code's userConfig mechanism. Values are entered in the Configure UI described in First-time setup above. Claude Code stores non-sensitive values in ~/.claude/settings.json under pluginConfigs[<plugin>@<marketplace>].options; sensitive values go to the OS keychain (or ~/.claude/.credentials.json as a fallback). The plugin's hook subprocess receives them as CLAUDE_PLUGIN_OPTION_<KEY> environment variables.
| Option | Description | Required | Sensitive |
|---|---|---|---|
OTLP_URL |
Dash0 OTLP endpoint URL (e.g. https://ingress.us1.dash0.com:4318) |
Yes | No |
AUTH_TOKEN |
Dash0 authentication token | Yes | Yes (stored in keychain) |
DATASET |
Dash0 dataset name | No | No |
AGENT_NAME |
Used as service.name and gen_ai.agent.name resource attributes (defaults to claude-code) |
No | No |
After changing any value via Configure, run /reload-plugins to apply it to the current session.
For non-sensitive options, the plugin falls back to DASH0_* environment variables when the userConfig value is not set. This is useful for --plugin-dir development or CI.
Note:
AUTH_TOKENhas no env var fallback — it must be configured via/plugin → Configure(stored in the OS keychain). This prevents the token from leaking into tool-spawned shell environments where other tools (e.g. Dash0 CLI) might pick it up.
| Variable | Description |
|---|---|
DASH0_OTLP_URL |
Dash0 OTLP endpoint URL — must include scheme (e.g. https://ingress.us1.dash0.com) |
DASH0_DATASET |
Dash0 dataset |
DASH0_AGENT_NAME |
Agent name |
DASH0_OMIT_USER_INFO |
Anonymize user identity (default: true). When true, user.name is emitted as a hash and user.email is omitted. Set to false to include real identity. |
DASH0_OMIT_IO |
Omit prompts and tool I/O (default: true). When true, prompt content and tool call inputs/outputs are stripped from spans. Set to false to include full content. |
DASH0_DEBUG |
Print OTel payloads to stderr for local debugging (true/false) |
DASH0_DEBUG_FILE |
Also write debug output to this file path (e.g. /tmp/dash0-debug.log) |
You can configure the plugin via a markdown file with YAML frontmatter. The plugin checks two locations:
- Project-level:
.claude/dash0-agent-plugin.local.md(in current directory) - Global:
~/.claude/dash0-agent-plugin.local.md(user home)
Project-level config takes precedence over global config.
Global config (recommended for personal use)
Create ~/.claude/dash0-agent-plugin.local.md to configure the plugin once for all projects:
---
otlp_url: "https://ingress.us1.dash0.com"
auth_token: "your-dash0-auth-token"
dataset: "default"
agent_name: "claude-code"
omit_io: true
omit_user_info: true
---Project-level config
Create .claude/dash0-agent-plugin.local.md in a project directory for project-specific overrides (e.g. a different dataset per repo):
---
enabled: true
otlp_url: "https://ingress.us1.dash0.com"
auth_token: "your-dash0-auth-token"
dataset: "my-project-dataset"
agent_name: "my-coding-agent"
omit_io: false
omit_user_info: false
---Config file options
| Option | Description | Default |
|---|---|---|
enabled |
Enable/disable the plugin for this project | true |
otlp_url |
Dash0 OTLP endpoint URL | — |
auth_token |
Dash0 authentication token | — |
dataset |
Dash0 dataset name | — |
agent_name |
Agent name (used as service.name) |
claude-code |
omit_io |
Omit prompt content and tool I/O | true |
omit_user_info |
Anonymize user identity | true |
Set enabled: false to disable the plugin for a single project without uninstalling it.
The config file sets environment variables for the hook subprocess, so it acts as a fallback after /plugin → Configure values and before DASH0_* environment variables.
Set DASH0_DEBUG=true to print all OTel payloads to stderr. Works with or without an OTLP endpoint configured — useful for verifying what telemetry the plugin produces.
DASH0_DEBUG=true claude --debug --plugin-dir /path/to/dash0-agent-pluginTo write debug output to a file (useful for tailing in a separate terminal without --debug):
DASH0_DEBUG=true DASH0_DEBUG_FILE=/tmp/dash0-debug.log claude --plugin-dir /path/to/dash0-agent-plugin
# In another terminal:
tail -f /tmp/dash0-debug.logOutput is prefixed with [dash0:trace] or [dash0:log] for filtering:
[dash0:trace] {"resourceSpans":[...]}
[dash0:log] {"resourceLogs":[...]}
No spans in Dash0 after install. The plugin was likely installed but not configured, or configured but not reloaded. Check:
- Look for a
dash0:message in the Claude Code UI on session start:dash0: telemetry is not active— OTLP URL is not configured. Set it via/plugin → Configureor in the config file.dash0: connectivity check failed— URL is set but connection failed (e.g., invalid auth token returns 401).
- If you've configured via
/plugin → Configurebut spans still don't appear, run/reload-plugins. Saved values are not picked up by an already-running session until reload.
More verbose debugging. Run Claude Code with --debug to see plugin error messages:
DASH0_OTLP_URL="https://ingress.us1.dash0.com:4318" \
DASH0_AUTH_TOKEN="your-token" \
claude --debug --plugin-dir /path/to/dash0-agent-plugin 2>&1 | grep "on-event:\|dash0:"Plugin errors are prefixed with on-event: or dash0: in the output.
Releases are automated with GoReleaser via GitHub Actions. To create a new release:
git tag v0.1.0
git push --tagsThis triggers the release workflow which cross-compiles binaries for darwin/linux × amd64/arm64 and publishes them to GitHub Releases. The on-event.sh script downloads the matching binary on first run.