Skip to content

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

  1. Remove commands_as_skills from conversion config and --commands-as-skills from scripts. Commands now always become package skills. Commands with Claude argument variables are reported as degraded.
  2. Run ai-config sync --dry-run, then ai-config sync --force-convert.
  3. Confirm the generated package with ai-config doctor --target codex <output-dir> and codex plugin list --json.
  4. 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.
  5. 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.