Preflight Checklist
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_request events and the metrics. Masking one event type hides nothing.
- It breaks exactly the event designed for skill analytics.
skill_activated is the only signal carrying invocation_trigger and skill.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.name on skill_activated for user-defined skills — consistent with api_request events 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 to OTEL_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.name on the skill_activated event (custom_skill) vs the api_request event and cost.usage/token.usage metrics (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_DETAILS and OTEL_LOG_USER_PROMPTS unset
Preflight Checklist
What's Wrong?
With telemetry enabled and default privacy settings (
OTEL_LOG_TOOL_DETAILSunset), theskill.nameattribute is masked onclaude_code.skill_activatedevents for user-defined skills — but the same export, in the same default configuration, carries the exact skill name verbatim onclaude_code.api_requestevents and on thecost.usage/token.usagemetrics.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_activatedevent — masked:claude_code.api_requestevent, same session, same default settings — verbatim:claude_code.cost.usage/claude_code.token.usagemetrics — verbatim:This makes the masking the worst of both worlds:
api_requestevents and the metrics. Masking one event type hides nothing.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=projectSettingsskills are masked identically touserSettingsones. 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_activatedcarried verbatimskill.name(plusplugin.name/marketplace.name) up to v2.1.112, and becamecustom_skillsomewhere 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 aroundskill_activated).What Should Happen?
Either of these would resolve it; the first matches pre-2.1.126 behaviour:
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.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
{ "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" } }.claude/skills/<name>/SKILL.md.claude -p "/<name>"and capture the OTLP payloads.skill.nameon theskill_activatedevent (custom_skill) vs theapi_requestevent andcost.usage/token.usagemetrics (verbatim skill name).Environment
OTEL_LOG_TOOL_DETAILSandOTEL_LOG_USER_PROMPTSunset