Continuous bidirectional sync between Claude Code and Codex — round-trip lossless, not a one-shot migrator.
Continuous bidirectional sync — claude → codex and codex → claude , run as often as the two hosts drift; not a one-shot migration. Strict YAML round-trip — Claude lenient YAML and Codex YAML 1.2 strict frontmatter both preserved across repeated syncs without loss or oscillation. Diff-first workflow — status to compare → sync --dry-run to preview → --apply to write. Risk-tagged operations — permissions , hooks , custom commands labeled safe / partial / manual . Backup-on-write — every overwrite snapshotted under .backups/ , FIFO retention (30). Apply ledger — every --apply writes a per-item sha256 attestation (before/after hash, backup path) to ~/.ai-config-sync-manager/ledgers/ . Selector syntax — --include skills:code-writer,instructions --exclude mcp style filtering. Native semantic mapping — Claude Write → Codex sandbox_mode = "workspace-write" , etc. Prose-level token rewriting — Claude-only tokens ( Read , Bash , TaskCreate , headless claude -p ) and Codex-only tokens ( spawn_agent , codex exec ) auto-translate across hosts and round-trip back. Zero runtime dependencies — single ESM file, Node built-ins only. Thin host plugins — /config-manager:* for Claude, config-manager-* for Codex. Visual inventory board — board renders a self-contained HTML page of every skill, agent, hook, and MCP server on both hosts, colored by sync status (in-sync / conflict / one-host-only) and grouped into per-area tabs and by agent harness. Jump to the board →
Claude Code and Codex use the same concepts (instructions / skills / mcp / permissions / hooks) but in different files, formats, and names :
Hand-rolling the sync invites drift, semantic loss, and accidental secret leaks . This CLI keeps the two hosts aligned while preserving host-native meaning.
This tool is built for two hosts in continuous use — where drift accumulates daily and round-trip integrity matters across repeated syncs — not for a one-shot, one-way migration.
One-shot migrators typically copy Claude-only vocabulary (tool names like Read / Bash , prose like Use the Bash tool , in-line Agent({...}) calls) into the generated file as prompt guidance and flag it for manual review. This CLI instead auto-rewrites those tokens to their host equivalents ( Read → workspace-write , TaskCreate → spawn_agent , claude -p → codex exec , …) and round-trips them back when syncing the other direction — so the same content stays correct for both hosts with no manual fix-ups.
npm install -g ai-config-sync-manager ai-config-sync connect # register the plugin for any detected host (Claude / Codex) ai-config-sync status # show drift across global + project scopes ai-config-sync sync # preview changes (--dry-run by default) ai-config-sync sync --apply # apply with automatic backups connect only registers plugins for hosts it actually finds ( ~/.claude for Claude, ~/.codex or ~/.agents for Codex). Hosts that are missing are reported as skipped and no directories are created — install the host first, then rerun connect .
Node.js ≥ 20 Claude Code and/or Codex CLI installed (host plugins are auto-registered by connect when the matching host directory exists) Table of Contents Category Sections Commands Bundled CLI · Host plugin commands · Flags · Board Workflow Selector syntax · Ignore rules · Sync direction · Scopes Safety Safety defaults · Risk levels · Retention Mapping Native mapping · Areas · Paraphrase · Hidden markers · Unsupported Reference Install resolution · Local dev · Gotchas · API surface · What's next Commands Bundled CLI After npm install -g , the same binary is on PATH as ai-config-sync — equivalent to ./bin/ai-config-sync.mjs from a source clone.
ai-config-sync connect ai-config-sync status ai-config-sync status --json ai-config-sync status --scope global ai-config-sync status --scope project ai-config-sync status --include skills:code-writer,instructions --exclude mcp ai-config-sync sync --dry-run ai-config-sync sync --scope project --dry-run ai-config-sync sync --scope global --apply ai-config-sync sync --include instructions,skills:code-writer --exclude mcp --dry-run ai-config-sync sync --from claude --to codex ai-config-sync sync --from codex --to claude ai-config-sync board ai-config-sync board --scope global --no-open ai-config-sync reference ai-config-sync paraphrase Command Purpose connect Detect installed hosts and register the matching plugin status Compare global + project config across both hosts status --json Machine-readable diff sync --dry-run Preview the merge plan without writing sync --apply Apply the plan, snapshot to .backups/ board Render an HTML inventory board of both hosts, colored by sync status reference Emit / persist a self-generated markdown reference paraphrase Line-level override archive for instruction wording Host plugin commands Host Connect Status Sync Paraphrase Claude /config-manager:connect /config-manager:status /config-manager:sync /config-manager:paraphrase Codex config-manager-connect config-manager-status config-manager-sync config-manager-paraphrase Flags Per-subcommand flag reference, mirroring <command> --help output. Shared flags ( --include / --exclude / --scope / --map ) get a one-line summary; full syntax lives in the linked section.
Flag Description -h , --help Show connect help ai-config-sync connect status Flag Description --json Print the full status report as JSON --compact One compact line per diff entry --tree Scope/area/item tree output --scope global|project|all Limit scope (default: all = global + project) --include area[:item][,...] Include selector — see Selector syntax --exclude area[:item][,...] Exclude selector — see Selector syntax -h , --help Show status help ai-config-sync status --scope project --tree --include skills:code-writer board Renders a self-contained HTML inventory board — every skill, agent, hook, and MCP server on both hosts, split into per-area tabs, colored by sync status: green = in sync, red = conflict, blue = Claude only, purple = Codex only, amber = unsupported. Agents are grouped under their harness (subfolder) where they have one. Type in the filter box to narrow rows; click a row for the full description, paths, and status detail. The file is written to ~/.ai-config-sync-manager/board/ with no external requests, so it works offline, and opens in your default browser automatically (pass --no-open to skip). ( Screenshot at the top .)
ai-config-sync board --scope global sync Flag Description --dry-run Preview without writing (default; mutually exclusive with --apply ) --apply Apply with backups --plan-json Print the sync plan as JSON --ledger-json Print the apply ledger as JSON to stdout ( --apply only) --ledger <path> Write the apply ledger JSON to <path> ( --apply only) --from claude|codex Source host (overrides AI_CONFIG_SYNC_HOST ) --to claude|codex Target host (overrides AI_CONFIG_SYNC_HOST ) --scope global|project|all Limit scope (default: all = global + project) --include area[:item][,...] Include selector — see Selector syntax --exclude area[:item][,...] Exclude selector — see Selector syntax -h , --help Show sync help When --from / --to are omitted, direction follows Sync direction .
ai-config-sync sync --scope project --include mcp:notion --apply reference Flag Description --output <path> Write the reference markdown to <path> (parent directories created) -h , --help Show reference help ai-config-sync reference --output ~ /.ai-config-sync-manager/reference.md paraphrase Flag Description --apply Rewrite files + register overrides + persist new map entries (default: dry-run) --register Skip rewriting; only register overrides where the effective map already equates both sides — see Paraphrase --map token=paraphrase[,...] Inline token-to-paraphrase pairs (free-form prose accepted) — see --map syntax --non-interactive Skip TTY prompts for tokens missing from paraphrase-map.json --json Print the result as JSON --scope global|project|all Limit scope (default: all = global + project) --include area[:item][,...] Include selector — see Selector syntax --exclude area[:item][,...] Exclude selector — see Selector syntax -h , --help Show paraphrase help ai-config-sync paraphrase --map " Read=read the file,Write=write to the file " --apply Selector syntax --include narrows the plan first, then --exclude removes matches. Both accept area or area:item syntax; itemized areas ( skills , permissions , hooks , agents , mcp , commands ) accept glob items.
ai-config-sync sync --include skills:code-writer,instructions --exclude mcp --dry-run ai-config-sync sync --include " permissions:Write* " --exclude " permissions:Bash(rm:*) " --dry-run Areas Area Itemized? Apply granularity instructions — file merge skills yes per skill agents yes per agent mcp yes per server permissions yes item-by-item patch hooks yes item-by-item patch commands yes per command plugins yes status only (read-only diff; sync skips this area) Ignore rules Persistent ignore lives at one of:
Each exclude entry is a string selector ( area:item or path glob) or an object whose fields combine with AND. term is a line-level mask — lines containing the substring are removed from both sides before the diff, so the conflict can disappear without hiding unrelated changes.
{ "version" : 1 , "exclude" : [ " skills:legacy-skill " , " permissions:Bash " , " ~/.codex/agents/archive-*.toml " , { "scope" : " global " , "area" : " agents " , "item" : " refactor-* " }, { "area" : " skills " , "host" : " claude " , "path" : " ~/.claude/skills/coderabbit-review " }, { "area" : " skills " , "term" : " .claude/docs/repo-analysis/ " }, { "area" : " agents " , "host" : " claude " , "path" : " ~/.claude/agents/*.md " , "term" : " TODO: do not sync " } ] } The active path and rule count are echoed in status output as Status ignore: <path> rules: [...] (N hidden) .
Trigger Default direction AI_CONFIG_SYNC_HOST=codex (Codex plugin invocation) codex → claude Otherwise (Claude plugin / direct CLI) claude → codex --from <host> --to <host> Explicit override Scopes Scope Path coverage global ~/.claude/** , ~/.codex/** project <cwd>/.claude/** , <cwd>/.codex/** , <cwd>/AGENTS.md , <cwd>/CLAUDE.md default / all global + project Safety defaults Dry-run first — sync defaults to dry-run; --apply is required for any write. Backups on every write — atomic snapshot to .backups/<area>/<host>/<timestamp>/... before overwrite. Apply ledger — every --apply records a per-item sha256 attestation ( before_hash / after_hash , backup_path , plan_hash ) to ~/.ai-config-sync-manager/ledgers/<timestamp>.json ; --ledger <path> copies it elsewhere and --ledger-json prints it to stdout. Risk labels — high-impact entries ( permissions , hooks , custom commands) marked with their risk level in the diff. Strict-vocab guard — host-only tokens (e.g. Codex update_plan ) flagged on cross-host copy. Secret pass-through — MCP env values are copied by default; set AI_CONFIG_SYNC_STRIP_SECRETS=1 to redact. Schema version — baseline state requires schemaVersion: 1 ; unknown versions abort. Risk levels Level Meaning Behavior safe Lossless, deterministic mapping Auto-applied partial Maps to a near-equivalent on the other host Auto-applied with annotation manual No safe automatic equivalent Listed in the plan but always review before --apply Retention Directory Keep Strategy .backups/<area>/<host>/ 30 FIFO (oldest pruned on next write) ~/.config/ai-config-sync/status-details/ 100 FIFO ~/.ai-config-sync-manager/ledgers/ 300 FIFO (oldest pruned on next --apply ) Native mapping (Claude ↔ Codex) Claude Codex permissions.allow: ["Write"] sandbox_mode = "workspace-write" command-like permissions.allow (e.g. Bash(npm:*) ) approval_policy = "on-request" .mcp.json server entries [mcp_servers.<name>] TOML tables hooks.PreToolUse / PostToolUse mapped where a Codex equivalent exists, else manual ~/.claude/skills/<name>/SKILL.md ~/.codex/skills/<nam
Hacker News
news.ycombinator.com