Port Claude Code skill plugins to other agent platforms. Codex is the first
target; the pipeline is target-agnostic (see Adding another target). Works on
any standard Claude plugin, and is tuned for this workspace's *-forge
plugins — registered ones get precise alias maps and cross-plugin reference
rewriting (e.g. code-forge → spec-forge) that a generic converter can't do.
Registered plugins (optional, for precision): spec-forge, code-forge,
apcore-skills, theory-forge, research-forge, hype-forge (see
src/registry.ts). Unregistered plugins convert via a generic auto-derived spec.
These plugins share a structure that off-the-shelf converters mishandle:
- Heavy
@../shared/*.mdcross-skill includes —cc2codexdrops theskills/shared/dir (dangling refs);npx skills/ symlink tools don't transform at all. - A plugin namespace (
spec-forge:) with bare, collision-prone skill names (idea,review,audit) — Codex has no plugin namespace. - Prose cross-references in Claude slash form (
/spec-forge:prd), including references between plugins.
Each Claude plugin becomes a bundle dir whose flat sub-skills Codex discovers via
its recursive **/SKILL.md scan. Codex auto-namespaces by the bundle dir, so
a skill named prd under spec-forge/ is exposed as spec-forge:prd — matching
the Claude form exactly. (Verified with codex debug prompt-input; an explicit
spec-forge- prefix would double up to spec-forge:spec-forge-prd.)
spec-forge/ # orchestrator -> spec-forge:spec-forge
idea/SKILL.md # -> spec-forge:idea
prd/SKILL.md # -> spec-forge:prd (alias: prd-generation -> prd)
...
spec-forge-shared/ # relocated shared refs (only if referenced)
.codex-plugin/plugin.json
Transform passes applied to every .md (SKILL.md + bundled references/):
- Inline external includes —
@../shared/x.mdcontent is inlined (the file won't travel with a flat skill). Trailing section hints are preserved. - Namespace identity — directory and frontmatter
nameare the bare alias (no prefix); Codex supplies the<ns>:namespace from the bundle dir. - Cross-reference rewrite —
/spec-forge:prd→spec-forge:prd(strip the slash; the colon form is the Codex skill name), across all known namespaces (cross-plugin refs included). - Skill-path rewrite —
../skills/review/SKILL.md→spec-forge:review. - Shared-path relocation — prose lazy-load refs (
../shared/x.md, theory-forge style) → a sibling<ns>-shared/dir with depth-aware relative paths (orchestrator / sub-skill / nested ref each differ). - Subagent adaptation —
Task(subagent_type="general-purpose")→ Codex's built-indefaultagent (see Codex Subagents);general-purpose→default,prompt=<X>hints preserved. Codex spawns subagents in isolated threads with summarized results — same semantics as Claude's Task tool, so this is near-lossless. - Instructions merge — frontmatter
instructions:is folded into the body (Codex reads onlyname+descriptionfrom frontmatter). - Tool remap —
AskUserQuestion→ "ask the user directly", etc.
convert exits non-zero if any bundle violates a gate:
- A — no unresolved external
@../include remains. - B — no leftover Claude-style slash ref (
/<ns>:<skill>) remains (the bare<ns>:<skill>colon form is the correct Codex name and is allowed). - C — every skill's directory name equals its frontmatter
name. - D — every relocated
<ns>-shared/...reference resolves on disk.
Non-fatal warnings surface source-side issues the conversion can't fix:
dangling cross-refs (spec-forge:feature), ambiguous cross-plugin bare paths,
and any unadapted Task(...) form (safety net — should be zero).
Beyond the built-in default, the Codex target defines a few tuned agents
(reviewer, spec-author, analyst) emitted as <out>/.codex/agents/*.toml.
adaptSubagents routes a delegation to one of them when its context names a
role skill — via the exact prompt=<X launch prompt> hint, or a :skill /
-skill token in the surrounding lines — otherwise it falls back to default.
install copies these to ~/.codex/agents/. The agent set and the keyword
roleRules live in src/targets.ts and are meant to be edited.
Routing is a best-effort heuristic: a delegation that only inlines a role
description (no skill token) falls back to default, which is still correct —
the prompt itself drives the behaviour; the custom agent only adds tuning.
npm install && npm run build
# convert one or more plugins (gates enforced)
agent-skill-bundler convert ../spec-forge ../code-forge ../apcore-skills --out ./out/codex
# verify a bundle actually loads in Codex (no model call; needs codex installed)
agent-skill-bundler verify ./out/codex/spec-forge
# install a bundle into Codex (symlink; Codex follows it for discovery)
agent-skill-bundler install ./out/codex/spec-forge # -> ~/.agents/skills/spec-forge
agent-skill-bundler install ./out/codex/spec-forge --codex-home /tmp/testIn Codex: restart, then /skills or name a skill, e.g. spec-forge:prd.
- Gates —
convertfails on dangling includes / leftover slash refs / name mismatch / unresolved shared paths. (Output is well-formed.) - Runtime discovery —
agent-skill-bundler verify <bundle>installs into a throwaway HOME and runscodex debug prompt-input(renders the model-visible prompt with no model call, no cost); asserts every expected<ns>:<skill>was discovered. (Codex actually loads them.) - Interactive —
codex→/skills, then invokespec-forge:prdon a real task and watch it run. (End-to-end; this one calls the model.)
npm test runs golden tests (test/fixtures/fixture-forge) for regression
safety on the converter itself.
The core pipeline is target-agnostic; a target is data in src/targets.ts
(skillsDir, toolRemap, expandsAtIncludes). Gemini, for example, natively
expands @ includes and supports namespaced .toml commands, so its target
would set expandsAtIncludes: true and use a different layout emitter.
Works on any standard Claude plugin (.claude-plugin/plugin.json +
skills/<name>/SKILL.md): unregistered plugins convert via a generic
auto-derived spec (empty aliases, SKILL.md-presence skill detection,
own-namespace cross-ref rewriting). Registering a plugin in
src/registry.ts is optional and adds precision — short alias maps (e.g.
prd-generation → prd) and recognition of its namespace inside other
plugins' cross-references. The six *-forge suites are registered.
MIT © tercel