openai / openai/codex

Symlinked standalone skills inherit plugin namespace from target ancestors

Open
#40,070 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI skills
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

What version of Codex is running?

0.147.0

What platform is your computer?

Darwin 25.5.0 arm64 arm

What issue are you seeing?

A standalone skill installed as a directory symlink under the user skills directory inherits a plugin namespace from an ancestor of the symlink target.

The skill is not installed as part of a Codex plugin, and codex plugin list does not list that plugin. Nevertheless, Codex displays the skill as:

foreign-plugin:demo

instead of:

demo

This affects declarative package managers such as Nix/Home Manager, which normally install files by linking them from an immutable store.

Steps to reproduce

Create this source tree:

source/
├── .claude-plugin/
│   └── plugin.json
└── skills/
    └── demo/
        └── SKILL.md

.claude-plugin/plugin.json:

{
  "name": "foreign-plugin"
}

skills/demo/SKILL.md:

---
name: demo
description: Demonstrate symlinked skill discovery.
---

Then symlink only the individual skill into the Codex user skills directory:

$CODEX_HOME/skills/demo -> source/skills/demo

Restart Codex and inspect the skill selector or run:

codex debug prompt-input "diagnostic"
What did you expect to happen?

Following a symlink for file access should not make an individually installed standalone skill inherit plugin ownership from directories above the symlink target.

Codex should use:

  • the canonical path for reading and deduplication; and
  • the logical discovery path, or explicit plugin installation metadata, for namespace ownership.

The skill should therefore remain demo.

Additional information

Codex canonicalizes the symlinked SKILL.md, treats the canonical target's parent as a namespace root, walks upward outside the configured skills directory, and reads source/.claude-plugin/plugin.json.

Relevant implementation:

  • codex-rs/ext/skills/src/loader/host.rs
    • load_skills_under_root canonicalizes discovered skill paths.
    • When canonicalization changes the path, it adds the target parent to namespace_roots.
  • codex-rs/ext/skills/src/loader/namespace.rs
    • SkillNamespaceResolver walks upward from those roots and applies the nearest manifest name.

The official documentation says Codex supports symlinked skill folders and follows their targets, but it does not document inheriting plugin metadata from ancestors outside the configured skills root:

https://learn.chatgpt.com/codex/build-skills

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in codex-rs/ext/skills/src/loader/host.rs, then read codex-rs/ext/skills/src/loader/namespace.rs to trace canonicalization and namespace resolution. Reproduce the issue with the supplied symlinked skill and codex debug prompt-input "diagnostic". Done means the skill is displayed as demo and does not inherit plugin metadata from an ancestor outside the configured skills directory.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.