microsoft/copilot-otel-metrics
Set up GitHub Copilot OpenTelemetry capture: configure the VS Code export settings, generate a local Grafana stack and dashboard, or generate the Azure collector, infrastructure, and dashboard for an organization.
npx skills add https://github.com/microsoft/hve-core --skill copilot-otel-metrics
Take the user from "I want Copilot telemetry" to telemetry they can query. Do the work for them where doing it is safe and reversible, and walk them through it where it is not.
Done means export is enabled in the settings file that actually resolves, a backend is receiving data, a dashboard exists for that backend, and the user has confirmed data landed by querying the store rather than by trusting an HTTP 200.
Modes are independent. A user may run one, several, or all. Local capture and organization capture are separate journeys, not stages of the same one.
| Mode | Use when the user wants to | Consent gate | Reference |
|--------------------|-----------------------------------------------------|------------------------------------------------------------|------------------------------------------------------------------|
| local-setup | Turn on Copilot's OTel export on this machine | Show the exact settings diff and write only after approval | references/local-setup.md |
| local-stack | Get a backend on this machine to receive it | Write the files, then hand over the command; never run it | references/local-stack.md |
| org-distribution | Push OTel settings to a fleet of developers | Nothing is applied; draft the configuration and explain it | references/org-distribution.md |
| azure-capture | Collect a fleet's telemetry into Azure and chart it | Write the templates, then hand over the deploy commands | references/azure-capture.md |
references/verification.md is shared by every mode. Read it before telling anyone their telemetry works.
When the request names a goal rather than a mode, pick the mode that reaches the goal and say which one was picked. "Set up Copilot metrics" with no other context means local-setup followed by local-stack. Confirm before assuming the organization path, because it spends money and places a shared write credential on every workstation.
Raise this before anyone enables export, in every mode.
github.copilot.chat.otel.captureContent defaults to false and is documented as controlling whether input and output messages, system instructions, and tool definitions reach span attributes. A false value does not mean the store holds no prompt text. With that setting disabled, this stack observed six attributes populated in plaintext on spans:
copilot_chat.user_request, gen_ai.input.messages, gen_ai.output.messages, gen_ai.tool.call.arguments, gen_ai.tool.call.result, and gen_ai.system_instructions.
A seventh, copilot_chat.reasoning_content, was present but marked [encrypted].
So treat any Copilot telemetry store as holding prompt content regardless of the setting, and treat the endpoint and the backing volume as sensitive. That exposure carries a Medium residual rating in SECURITY.md; it is a decision the user owns and cannot make if this skill describes the setting instead of the observed behavior.
Where sources disagree, prefer the stricter one. Microsoft's published Azure guidance enables captureContent: true without comment, while the VS Code setting description marks it Contains potentially sensitive data.
Every setting name, metric name, and API version here is a snapshot of one build. The extension moves faster than the skill, and a wrong name fails silently: Prometheus returns an empty result, Grafana renders an empty panel, and nothing errors.
contributes.configuration in the Copilot Chat extension's package.json, or open the Settings UI and filter on otel. Do not settle a settings question from documentation, including this document.copilot-chat 0.59.2026072702 declares 11 github.copilot.chat.otel.* settings, all scope: application. Re-check the count before relying on it.local-setup: which VS Code build is in use, since stable and Insiders have separate global settings files.org-distribution: which distribution channel the organization already uses.azure-capture: subscription, tenant, region, resource naming, and who may hold the ingestion credential. Never guess these.docker, az, terraform, and any generated script. The line is drawn by toolchain and by whose credentials the command uses, not by whether the command mutates anything: terraform plan and docker ps are the user's too. The one carve-out is a read-only query against a local telemetry endpoint, which is how verification works. This is the single statement of the rule; the references point here rather than restating it.copilot-otel/ directory inside the user's current workspace. When that workspace is a git repository, say so before writing: the generated files will show in git status and can be committed and pushed, so offer a .gitignore entry or a path outside the repository. Overwriting a path git already tracks, or writing anywhere outside the workspace, needs its own explicit confirmation.settings.json. Preserve every other key and every comment; that file is JSONC and the user's own.settings.json cannot be identified with confidence, rather than writing to a guessed path.Read the references. Copy or adapt the seeds. Offer the helpers to the user with the exact command, resolved to an absolute path so it works from whatever directory their shell is in.
| Path | Use |
|--------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|
| references/local-setup.md | Read for the settings procedure, the profile pitfall, the diff-and-confirm write, and the paste alternative |
| references/local-stack.md | Read for the local backend, the generated compose contract, and the helper inventory |
| references/org-distribution.md | Read for managed-settings channels, precedence, and the agent-host split |
| references/azure-capture.md | Read for the Azure data path, the product and cost comparison, and the generated templates |
| references/verification.md | Read for proving data landed, the false-positive pitfalls, and metric enumeration |
| examples/compose.yaml | Copy as the seed for a generated local stack |
| examples/dashboards/copilot-otel.json | Copy as the seed for a generated local PromQL dashboard |
| examples/dashboards/copilot-otel-azure.json | Copy as the seed for a generated Azure KQL dashboard |
| examples/azure/ | Copy as the seed for the collector configuration and infrastructure templates |
| examples/verify.py | Offer to the user as a stored-signal check they run themselves |
| examples/inspect_metrics.py | Offer to the user to enumerate the metric surface their build emits |
| examples/baseline.py | Offer to the user to separate real telemetry from residue |
| examples/validate_dashboard.py | Offer to the user for a local PromQL or TraceQL dashboard only; it has no Azure Monitor path and it overwrites by uid |
| examples/README.md, examples/azure/README.md | Written for the user, not part of the agent's reading path. Point the user at them rather than summarizing them |
Take microsoft/copilot-otel-metrics from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.