skill.name OTel attribute never populated for non-built-in skills under service.name=claude-code, even with a valid plugin manifest
Title
skill.name OTel attribute is never populated for non-built-in skills when running via the Claude Code CLI, even when the skill is installed through a plugin with a valid .claude-plugin/plugin.json
Summary
The skill.name attribute (documented at https://code.claude.com/docs/en/monitoring-usage, gated by OTEL_LOG_TOOL_DETAILS=1) never resolves to a real value for any non-built-in skill when telemetry is emitted with service.name = claude-code (the CLI) — it is either unset or collapsed to a generic third-party redaction bucket, even for a plugin with a confirmed-working manifest. Built-in/first-party skills (e.g. artifact-design) resolve correctly. This makes it impossible for an org to see which custom/third-party skill was actually used from claude-code-sourced telemetry.
Environment
CLAUDE_CODE_ENABLE_TELEMETRY=1,OTEL_LOGS_EXPORTER=otlp(org-managed settings),OTEL_LOG_TOOL_DETAILS=1set org-wide.- Telemetry destination: an internal Honeycomb environment, receiving OTLP export from Claude Code CLI sessions across the org.
- (Please let us know if you need the exact
claude --versionused in a specific session — happy to pin down a precise repro version on request.)
Evidence
- Grouping all telemetry by
skill.nameandservice.nameover a 7-day window, withinservice.name = claude-codespecifically:
| skill.name | count |
| --- | --- |
| (No value) | ~15,000+ |
| third-party | ~71–80 |
| claude-api | ~12–15 |
| artifact-design | ~2–5 |
| mcp-apps:add-app-to-server | 1 |
The only non-empty values that ever resolve to a real name are confirmed Anthropic-shipped built-ins (claude-api, artifact-design, mcp-apps:add-app-to-server). We can't rule out that most of the (No value) volume is simply telemetry unrelated to any skill invocation at all (plain prompts, tool calls, etc. where skill.name was never applicable) rather than skill invocations that lost even a categorical label. The unambiguous evidence is the third-party bucket: a specific, deliberately-emitted redaction value, never the real skill name, for every one of those ~71–80 records regardless of which skill was actually invoked.
- Filtering directly for a specific, actively-used custom skill by its exact frontmatter
name:returns zero matching records underservice.name = claude-code, despite confirmed real usage of that skill in that window. - To rule out "the skill's plugin lacks a manifest" as the cause: we tested a third-party plugin that has a confirmed working
.claude-plugin/plugin.json— proven by the fact that itsplugin_loadedevent correctly reports realplugin.name/marketplace.namevalues underservice.name = claude-code. That plugin's own skill (frontmattername: autoresearch) still returns zero results when filteringskill.name = autoresearchunderservice.name = claude-code, over the same window theplugin_loadedevents for that same plugin are present. - By contrast, telemetry with
service.name = claude(a different product/client) resolvesskill.namecorrectly and broadly for third-party/custom skills, including the exact one from point 3's underlying repo and several unrelated third-party skills. This suggests the schema/pipeline is capable of carrying this attribute correctly elsewhere, and the gap is specific to the Claude Code CLI client's own telemetry emission.
Why this matters
Orgs deploying Claude Code CLI with custom/marketplace skills have no way to attribute skill usage by name in their observability tooling — only built-in skill usage is visible. This blocks basic usage analytics (which custom skills are actually being used, by whom, how often) for any org relying on OTel/Honeycomb-style dashboards, and isn't documented as a limitation anywhere in the current monitoring-usage docs (which describe skill.name as gated only by OTEL_LOG_TOOL_DETAILS, with no mention of a built-in-only restriction).
Suggested fix / ask
- Confirm whether this is intentional (e.g. a deliberate restriction to avoid unbounded cardinality from arbitrary skill names) or a bug.
- If intentional, document the restriction explicitly in the monitoring-usage docs, since the current docs imply
skill.nameworks for any skill onceOTEL_LOG_TOOL_DETAILS=1is set. - If a bug, requesting that
skill.namepopulate for any skill Claude Code Ioads and invokes, not just first-party/built-in ones — this is the only piece missing to make custom skill usage observable from Claude Code CLI telemetry.
Related
- #80948 investigates
claude_code.plugin_loadedbeing dropped by a startup race (event logger not initialized before plugin load fires). That issue is about a different event/attribute pair (plugin.name/marketplace.nameonplugin_loaded) and doesn't mentionskill.nameat all — this issue is aboutskill.namespecifically, which lives on a different event/metric and is emitted at a different point in the session lifecycle (per invocation, not once at session start). The two may or may not share a root cause; noting the connection since both surfaced from the same investigation. - We previously filed https://github.com/anthropics/claude-code/issues/80340 (SHA-pinned
git-subdirrefs not resolvable by the plugin installer) from the same investigation thread — happy to provide further repro detail or a minimal test plugin if useful.