On this page
Codex Skill Mirror Pattern
When a repository already treats `.agents/skills/` as the canonical skill source, the clean Codex integration is not "replace it with `.codex/skills/`" or "symlink the whole folder wholesale." A mirror layer with selective adapters preserves the canonical source while giving Codex what it needs.
When a repository already treats .agents/skills/ as the canonical skill source, the clean Codex integration is not “replace it with .codex/skills/” or “symlink the whole folder wholesale.” Both shortcuts have failure modes that surface only after install, when the skills look like they work but quietly misbehave. The stable pattern is six steps:
- Keep
.agents/skills/as the canonical skill source. - Add a repo-local
.codex/skills/mirror. - Mirror portable skills as symlinks.
- Write real Codex adapters only for skills whose runtime assumptions do not transfer cleanly.
- Sync the repo-local mirror into
~/.codex/skills/one skill at a time. - Disable the Claude-native
.agents/skills/{name}/SKILL.mdin Codex config when a same-name real Codex adapter exists.
Why direct symlinking is not enough
Claude-native skills often assume runtime features that do not exist in Codex with the same names or semantics, such as AskUserQuestion, TodoWrite, slash-skill chaining, or Claude-specific tool names like WebSearch and WebFetch.
A raw directory symlink from .agents/skills/ into ~/.codex/skills/ makes skills discoverable, but it does not make them seamless. The result is a hybrid failure mode:
- portable markdown-only skills appear to work
- high-friction workflow skills are discoverable but operationally misleading
- Codex-specific fixes drift away from the canonical Claude skill if edited in place
The mirror-with-adapters layout
Introduce a mirror-with-adapters layer owned by the target runtime:
.agents/skills/ # canonical Claude source
├── check-symlinks/
├── task-starter/
└── wrap/
.codex/skills/ # repo-local Codex mirror
├── check-symlinks -> ../../.agents/skills/check-symlinks
├── task-starter/ # real Codex adapter
└── wrap/ # real Codex adapter
~/.codex/skills/ # global Codex runtime home
├── check-symlinks -> 3b/.codex/skills/check-symlinks
├── task-starter -> 3b/.codex/skills/task-starter
└── wrap -> 3b/.codex/skills/wrap The adapter write boundary
When a mirrored Codex skill path is still a symlink into .agents/skills/, editing SKILL.md at the Codex path edits the Claude source too. That means the transition from “portable mirror” to “real Codex adapter” has an explicit first step:
- remove or replace the mirrored symlink at
.codex/skills/{name} - create a real directory at that path
- write the Codex-owned
SKILL.mdthere
In git, this migration appears as delete the old symlink + add real files under the same path. That is the correct shape of the change, not a sign that the mirror is broken.
When to write a real adapter
Only create a real adapter when the original skill depends on runtime-specific behavior. Examples from the 3B rollout:
task-starterneeded Codex-side translation forAskUserQuestion,EnterPlanMode/ExitPlanMode, and inline slash-skill invocation.wrapneeded translation forTodoWrite,AskUserQuestion, and nested slash-skill chaining.- Simpler instruction-driven skills stayed as direct symlinks.
Adapter sync discipline
Once a skill becomes a real Codex adapter, keep it intentionally compact:
- Sync against the upstream Claude
metadata.version. - Preserve only the Codex runtime translations that change execution semantics.
- Port only the decision-critical upstream deltas needed to maintain contract parity.
- Avoid copying the full Claude skill body unless the target runtime truly needs a full fork.
Escalation to a portable plugin
When the workflow contains reusable domain logic (state models, scorers, prompt assets, provider protocol), adapter-only mirroring becomes too thin. Promote the extracted system into:
- a runtime-agnostic core package
- a thin runtime/plugin wrapper
- tests that import the extracted package directly
This keeps the cross-agent logic reusable while containing runtime-specific boot steps, update flows, and downstream pipeline coupling inside the wrapper layer.
Why this layering works
Canonical source stays single
Claude-first workflow logic remains anchored in .agents/skills/, so the existing 3B ecosystem and connected repos do not need to change.
Target runtime owns its compatibility layer
Codex-specific adaptations live under .codex/skills/, where they can evolve without polluting the Claude source with tool-specific conditionals.
Discovery and execution are separated cleanly
Repo-local mirrors solve what Codex can discover. Adapters solve what Codex can execute cleanly. Treating those as separate problems avoids both over-duplication and false seamlessness.
Codex can also discover .agents/skills/ directly from the repository. That is useful for portable pass-through skills but confusing when a real same-name adapter exists under .codex/skills/. In that case, disable only the Claude-native source SKILL.md in ~/.codex/config.toml via [[skills.config]]; leave the .codex/skills/ adapter enabled.
Global install stays reversible
A sync script that links repo-local skills into ~/.codex/skills/ one by one keeps the global Codex home additive. It avoids clobbering built-in/system skills and avoids replacing the entire global skills directory with a repository-owned tree.
When this fits
The pattern fits when:
- A repository already has a mature skill system in another agent’s format.
- The source skill tree is canonical and should remain canonical.
- Some skills are tool-agnostic, but a few high-value workflows are not.
- You want Codex discovery to feel native without rewriting the full skill library up front.
It does not fit when the target runtime should become the new source of truth immediately, when every skill is deeply runtime-specific (so a mirror would mostly become wrappers), or when you need cross-agent parity for connected external repos rather than just the hub repository.
Practical takeaway
Discovery compatibility and execution compatibility are different problems. Mirror portable skills with symlinks; adapt only the ones with real runtime mismatch. Promote a mirrored skill into a real adapter before editing it, or the write lands in Claude’s canonical source. Keep adapters compact and synced by upstream metadata.version plus decision-critical deltas, not by full clone. When adapter translation stops being enough, split the reusable logic into a portable core package and keep the runtime/plugin layer thin.