[Bug] OTel: skill_activated masks skill.name to "custom_skill" while api_request events and cost/token metrics export it verbatim (regression since ~2.1.126)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet (closest prior report, #58674, was closed by the stale bot without resolution — details below)
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
With telemetry enabled and default privacy settings (OTEL_LOG_TOOL_DETAILS unset), the skill.name attribute is masked on claude_code.skill_activated events for user-defined skills — but the same export, in the same default configuration, carries the exact skill name verbatim on claude_code.api_request events and on the cost.usage/token.usage metrics.
Verified on v2.1.207 by capturing raw OTLP payloads (protoc --decode_raw) from a skill committed to project settings. All three records are from one session:
claude_code.skill_activated event — masked:
1: "skill.name" → "custom_skill"
1: "invocation_trigger" → "user-slash"
1: "skill.source" → "projectSettings"
claude_code.api_request event, same session, same default settings — verbatim:
1: "skill.name" → "wield-mask-probe"
claude_code.cost.usage / claude_code.token.usage metrics — verbatim:
1: "skill.name" → "wield-mask-probe"
This makes the masking the worst of both worlds:
- It provides no privacy. Anyone with access to the telemetry backend already sees the real skill name on
api_requestevents and the metrics. Masking one event type hides nothing. - It breaks exactly the event designed for skill analytics.
skill_activatedis the only signal carryinginvocation_triggerandskill.source, and it's the one place the name is redacted — so per-skill adoption analysis (which skills does the team actually invoke, and how) can't use it.
Also verified: skill.source=projectSettings skills are masked identically to userSettings ones. The monitoring docs don't say whether repo-committed project skills were meant to be treated differently.
The only unmask is OTEL_LOG_TOOL_DETAILS=1 (verified working on v2.1.207), but that is documented to also export tool parameters — a much bigger privacy surface than skill names. For teams doing direct OTLP export (no collector to strip attributes), that trade is not acceptable just to recover a name that the rest of the export already includes.
History — this appears to be a regression
#58674 reported this same behaviour and included payload evidence that skill_activated carried verbatim skill.name (plus plugin.name/marketplace.name) up to v2.1.112, and became custom_skill somewhere around the v2.1.126 rewrite ("skill_activated now fires for user-typed slash commands"). That issue was closed by the stale bot as NOT_PLANNED without a decision. Related: #50631 (skillOverrides ignored for project settings), #55187 (monitoring docs gaps around skill_activated).
What Should Happen?
Either of these would resolve it; the first matches pre-2.1.126 behaviour:
- Restore verbatim
skill.nameonskill_activatedfor user-defined skills — consistent withapi_requestevents and the metrics, which already export it at default settings. If the masking is intentional, it should at least be consistent across signals, and the intent documented. - If a control is preferred, make it scoped rather than all-or-nothing — e.g. a managed-settings option to opt user-defined (or specifically repo-committed
projectSettings) skills into verbatim event reporting without coupling it toOTEL_LOG_TOOL_DETAILS's tool-parameter export. An org that deploys telemetry via managed settings owns the skills committed to its own repos; their names are not sensitive to that org's own backend.
Steps to Reproduce
- Point telemetry at a local OTLP listener via project settings env:
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318"
}
}
- Add any skill under the project's
.claude/skills/<name>/SKILL.md. - Run
claude -p "/<name>"and capture the OTLP payloads. - Compare
skill.nameon theskill_activatedevent (custom_skill) vs theapi_requestevent andcost.usage/token.usagemetrics (verbatim skill name).
Environment
- Claude Code v2.1.207
- macOS (darwin 25.5.0), arm64
- Export: OTLP http/protobuf, direct (no collector);
OTEL_LOG_TOOL_DETAILSandOTEL_LOG_USER_PROMPTSunset
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗