[bug][otel]: Plugin Skills injected by SkillsExtension do not emit codex.skill.injected

Open 💬 0 comments Opened Jul 29, 2026 by Kurok1

What version of Codex CLI is running?

codex-cli 0.145.0

The CLI update check reports 0.146.0 as the latest release. The runtime reproduction below is from 0.145.0; I also inspected the rust-v0.146.0 source and the same missing-emission path is still present there.

What subscription do you have?

ChatGPT subscription (exact tier omitted for privacy)

Which model were you using?

gpt-5.6-sol

What platform is your computer?

Darwin 23.6.0 arm64 arm

What terminal emulator and version are you using (if applicable)?

Warp Terminal v0.2026.07.01.09.21.stable_01

Codex doctor report

Relevant redacted excerpt (unrelated local paths, proxy diagnostics, and state-database checks omitted):

{
  "schemaVersion": 1,
  "codexVersion": "0.145.0",
  "checks": {
    "auth.credentials": {
      "status": "ok",
      "details": {
        "stored auth mode": "chatgpt"
      }
    },
    "config.load": {
      "status": "ok",
      "details": {
        "model": "gpt-5.6-sol",
        "model provider": "openai",
        "relevant enabled feature flags": [
          "plugins",
          "remote_plugin",
          "mentions_v2"
        ]
      }
    },
    "runtime.provenance": {
      "status": "ok",
      "details": {
        "platform": "macos-aarch64",
        "version": "0.145.0",
        "install method": "standalone"
      }
    },
    "updates.status": {
      "status": "ok",
      "details": {
        "latest version": "0.146.0",
        "latest version status": "newer version is available"
      }
    }
  }
}

What issue are you seeing?

Plugin-provided Skills are successfully selected and injected into the turn, but the OTLP metrics pipeline does not receive a corresponding codex.skill.injected data point.

This creates a silent telemetry blind spot for plugin Skills. In the same Codex session, ordinary host/system Skills do emit codex.skill.injected, so the metrics exporter and OTLP receiver are working.

Observed session evidence:

2026-07-29T01:32:21.452Z
<skill>
<name>mattpocock-skills:ask-matt</name>
<path>.../plugins/cache/mattpocock/mattpocock-skills/1.2.0/skills/engineering/ask-matt/SKILL.md</path>
...
</skill>

The same day's rollout also records plugin Skill document reads for:

diagnosing-bugs  5
tdd               1
code-review       1

After allowing exporter batching/flush, the received codex.skill.injected aggregation was:

openai-docs       3
golang-patterns   1
mattpocock-skills:*  0

All received rows had status=ok; the host/system Skill rows used invoke_type=implicit. No plugin Skill data point was present, including the explicitly injected mattpocock-skills:ask-matt.

There is no receiver-side prefix filtering: arbitrary skill attribute values are accepted. Other Codex metrics and the two non-plugin Skill counters arrived through the same OTLP/gRPC endpoint.

This appears to be a missing counter call in the newer Skills Extension path:

This is related to, but distinct from, #27659. That issue covers namespaced Skill names being rejected because : was not sanitized. Commit 6c00dc087e4c01312017389483573500001e9fe9 / #34601 added sanitization to the core explicit and implicit paths. The problem here remains after that source-level fix: the Plugin Skills Extension success path does not call the counter at all.

What steps can reproduce the bug?

  1. Configure the Codex metrics exporter:

``toml
[otel]
environment = "dev"
metrics_exporter = { otlp-grpc = { endpoint = "http://127.0.0.1:4317" } }
``

  1. Install or enable a plugin that contributes a namespaced Skill, for example example-plugin:example-skill.
  2. Start a new Codex CLI session and explicitly select/mention that plugin Skill.
  3. Confirm in the rollout JSONL that Codex injected a structured fragment containing:

``xml
<skill>
<name>example-plugin:example-skill</name>
...
</skill>
``

  1. Inspect exported OTLP metrics after the batch interval or process shutdown.
  2. Observe that no codex.skill.injected point exists for the plugin Skill.
  3. In the same session, implicitly invoke a regular host/system Skill by reading its SKILL.md; its codex.skill.injected point is exported normally.

What is the expected behavior?

Every successful Skill injection should increment the documented codex.skill.injected counter, regardless of whether the Skill came from the legacy/core loader or the Plugin Skills Extension.

For a successful explicitly selected plugin Skill, the exported point should include at least:

status=ok
skill=<sanitized namespaced skill name>
invoke_type=explicit

A focused regression test around the SkillsExtension selected-entry/read-main-prompt success path would prevent the extension implementation from bypassing the existing Skill telemetry contract.

Additional information

  • Official metrics documentation describes skill.injected as “Skill injection outcomes by skill”:

https://learn.chatgpt.com/docs/config-file/config-advanced

  • Related but not duplicate:
  • #27659 — invalid-character sanitization for namespaced Skill tags
  • #17132 — proposed PreSkillUse/PostSkillUse lifecycle hooks
  • #35650 — request for additional plugin/marketplace attributes
  • No prompts, tokens, account identifiers, conversation IDs, or absolute local paths are included in this report.

View original on GitHub ↗