Skills loader ignores symlinked SKILL.md (breaks Nix/Home Manager installs)
What version of Codex CLI is running?
codex-cli 0.98.0 (codex --version)
What subscription do you have?
Unknown (CLI via API token).
Which model were you using?
gpt-5.3-codex (also reproduced with gpt-5.2-codex).
What platform is your computer?
Linux 6.12.68 x86_64 unknown (uname -mprs)
What terminal emulator and version are you using (if applicable)?
Reproduces in non-interactive codex exec; tmux in use: tmux 3.6a.
What issue are you seeing?
Skills whose SKILL.md is a symlink are not discovered/listed.
This breaks Nix/Home Manager style installs where user dotfiles (including skills) are symlinked into the Nix store (e.g. ~/.codex/skills/<name>/SKILL.md -> /nix/store/...).
What steps can reproduce the bug?
mkdir -p ~/.codex/skills/demo
printf '---\nname: demo\ndescription: demo skill\n---\n' > /tmp/demo-skill.md
ln -sf /tmp/demo-skill.md ~/.codex/skills/demo/SKILL.md
codex exec "which skills do you have access to"
What is the expected behavior?
demo should be listed as an available skill.
Additional information
If you replace the symlink with a regular file copy (cp -L ...), the skill is discovered.
Root cause in codex-rs/core/src/skills/loader.rs (discover_skills_under_root()):
- When an entry is a symlink, it calls
fs::metadata(). - It only follows/enqueues the entry if
metadata.is_dir(). - Otherwise it
continues, so symlinks to files (includingSKILL.md) are skipped.
At commit a118494323a46c2e7181fb7b0a7c19178fba6578, this is around lines 393-425.
Suggested fix: in the symlink branch, if the symlink resolves to a file and file_name == "SKILL.md", call parse_skill_file(&path, scope) and push to outcome.skills (same error handling as the non-symlink is_file() path). parse_skill_file() already canonicalizes the path.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗