Conversion¶
Convert Claude Code plugins to other AI coding tools.
Targets¶
| Target | Output |
|---|---|
codex |
installable Codex packages and local marketplaces under .ai-config/codex/marketplaces/ |
cursor |
.cursor/ skills, commands, hooks, and MCP config |
opencode |
.opencode/ skills plus opencode.json / opencode.lsp.json |
pi |
.pi/ project or .pi/agent/ user skills, prompts, and extensions |
ai-config convert ./my-plugin --target codex
ai-config convert ./my-plugin --dry-run
ai-config convert ./my-plugin --target all --report ./report.json
Codex packages (breaking in 0.6.0)¶
The codex target no longer writes loose .codex/skills, prompts, hooks, or MCP tables. It emits
one self-contained package and local marketplace for each source plugin:
.ai-config/codex/marketplaces/ai-config-my-plugin/
├── .agents/plugins/marketplace.json
└── plugins/my-plugin/
├── .codex-plugin/plugin.json
├── skills/
│ ├── my-skill/SKILL.md
│ └── command-my-command/SKILL.md
└── hooks/hooks.json
The package manifest contains supported MCP server declarations. Referenced hook support scripts
are copied into the package, and ${CLAUDE_PLUGIN_ROOT} becomes Codex's ${PLUGIN_ROOT}.
Target-native files under targets/codex/ are copied into the package root.
ai-config convert only generates package sources. A configured ai-config sync also registers
each generated local marketplace and installs or refreshes the plugin through codex plugin.
Codex owns its installed cache and enablement in CODEX_HOME; ai-config does not imitate that
layout or rewrite unrelated Codex settings.
Migration from 0.5.x¶
- Remove
commands_as_skillsfrom conversion config and--commands-as-skillsfrom scripts. Commands now always become package skills. Commands with Claude argument variables are reported as degraded. - Run
ai-config sync --dry-run, thenai-config sync --force-convert. - Confirm the generated package with
ai-config doctor --target codex <output-dir>andcodex plugin list --json. - Review old
.codex/skills,.codex/prompts,.codex/hooks.json, and generated MCP entries. Doctor reports possible stale output, but ai-config does not delete it because it cannot prove whether a loose file is user-authored. - Remove only legacy files you recognize as old ai-config output.
Each generated marketplace name is ai-config-<normalized-plugin> and each installed selector is
<normalized-plugin>@ai-config-<normalized-plugin>. The normalized identity from the source
manifest is used consistently for package paths, both manifests, ownership, Codex CLI selectors,
and drift checks. Two configured sources that normalize to the same identity fail before files or
runtime state change.
Source package versions must be valid SemVer 2.0.0 values such as 1.2.3 or 1.2.3-rc.1.
Same-version content refreshes are allowed, upgrades are applied, and ownership/runtime downgrades
fail closed with a remediation message. ai-config records only owned entries in
.ai-config/codex/ownership.json. Removal and update are limited to that state. A collision with an
unrelated marketplace or plugin fails without mutation.
Sync-driven conversion¶
version: 1
targets:
- type: claude
config:
marketplaces:
my-plugins:
source: github
repo: myorg/my-plugins
plugins:
- id: my-tool@my-plugins
scope: user
enabled: true
conversion:
enabled: true
targets: [codex, cursor]
scope: user
scope selects the default output root (~ for user, the current project for project). A custom
output_dir overrides it. Codex package paths remain under that root's .ai-config/codex/ tree.
Component mapping¶
| Component | Codex | Cursor | OpenCode | Pi |
|---|---|---|---|---|
| Skills | package-local native skill | skill | skill | skill |
| Commands | package skill; degraded with Claude variables | command | command | prompt template |
| Hooks | supported command hooks in package | hooks config | unsupported | extension emulation |
| MCP | package manifest mcpServers |
.cursor/mcp.json |
opencode.json |
unsupported |
| LSP | unsupported | unsupported | opencode.lsp.json |
unsupported |
| Agents | unsupported | unsupported | unsupported | unsupported |
Reports classify each component independently as native, transform, emulate, fallback/degraded, or unsupported. One target's mapping never changes another target's report.
Target-native files¶
Put hand-written files under targets/<target>/. They are copied into the target's natural output
root and override a generated file at the same path. For Codex, the natural root is the generated
plugin package—not shared .codex config.
Options¶
| Option | Description |
|---|---|
-t, --target |
repeatable codex, cursor, opencode, pi, or all |
-o, --output |
output root |
--scope |
user or project default output root |
--dry-run |
report package/files without writing or invoking lifecycle commands |
--best-effort |
continue other target conversion after component errors |
--format |
summary, markdown, or json |
--report, --report-format |
write JSON or Markdown report |
Validation and cache¶
ai-config doctor --target codex ./output-dir
ai-config doctor --target all ./output-dir
ai-config sync --force-convert
Sync hashes plugin source, conversion settings, and owned generated marketplace bytes. A cache hit
is accepted only while the package and marketplace still exist without symlinks and match the saved
fingerprint, so normal sync repairs deleted or tampered output. Dry-run and JSON output distinguish
planned, completed, and failed actions. status --config ... --json exits non-zero when lifecycle
planning finds a non-no-op action or an inspection error.
Configured sources are tracked separately as desired, temporarily unavailable, or disabled. A
temporarily unavailable source retains prior ownership; a disabled/removed source is cleaned up.
Removing or disabling the Codex target also reconciles prior owned roots, including a prior custom
output_dir recorded in the conversion cache.
Every Codex subprocess has a finite timeout. On POSIX, each command starts in a separate process group; after a bounded SIGTERM grace period, timeout cleanup inspects and kills any remaining group even when the direct child exited first, then performs a bounded reap of the direct child. Non-POSIX platforms receive direct-child timeout cleanup only; ai-config 0.6.0 does not claim descendant cleanup there. The adapter accepts only the validated Codex 0.144.x JSON contract: malformed, partial, duplicate, inconsistent, or unknown version responses fail closed. Lifecycle failures retain ownership for retry, sanitize child output, name the exact stage and command, include remediation, and report completed and failed actions.