{"slug": "show-hn-sync-claude-code-and-codex-configs-with-a-board-that-shows-the-drift", "title": "Show HN: Sync Claude Code and Codex configs, with a board that shows the drift", "summary": "A new open-source CLI tool, ai-config-sync-manager, provides continuous bidirectional sync between Claude Code and Codex configurations, preserving YAML round-trip integrity across repeated syncs. The tool auto-translates host-specific tokens like Claude's Read to Codex's workspace-write and vice versa, and includes a visual inventory board showing drift status. It requires Node.js 20+ and either Claude Code or Codex CLI installed.", "body_md": "**Continuous bidirectional sync between Claude Code and Codex — round-trip lossless, not a one-shot migrator.**\n\n**Continuous bidirectional sync**—`claude → codex`\n\nand`codex → claude`\n\n, 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`\n\nto compare →`sync --dry-run`\n\nto preview →`--apply`\n\nto write.**Risk-tagged operations**—`permissions`\n\n,`hooks`\n\n, custom commands labeled`safe`\n\n/`partial`\n\n/`manual`\n\n.**Backup-on-write**— every overwrite snapshotted under`.backups/`\n\n, FIFO retention (30).**Apply ledger**— every`--apply`\n\nwrites a per-item sha256 attestation (before/after hash, backup path) to`~/.ai-config-sync-manager/ledgers/`\n\n.**Selector syntax**—`--include skills:code-writer,instructions --exclude mcp`\n\nstyle filtering.**Native semantic mapping**— Claude`Write`\n\n→ Codex`sandbox_mode = \"workspace-write\"`\n\n, etc.**Prose-level token rewriting**— Claude-only tokens (`Read`\n\n,`Bash`\n\n,`TaskCreate`\n\n, headless`claude -p`\n\n) and Codex-only tokens (`spawn_agent`\n\n,`codex exec`\n\n) auto-translate across hosts and round-trip back.**Zero runtime dependencies**— single ESM file, Node built-ins only.** Thin host plugins**—`/config-manager:*`\n\nfor Claude,`config-manager-*`\n\nfor Codex.**Visual inventory board**—`board`\n\nrenders 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 →](#board)\n\nClaude Code and Codex use the **same concepts** (instructions / skills / mcp / permissions / hooks) but in **different files, formats, and names**:\n\n| Concept | Claude | Codex |\n|---|---|---|\n| Instructions | `~/.claude/CLAUDE.md` |\n`~/.codex/AGENTS.md` |\n| Skills | `~/.claude/skills/` |\n`~/.codex/skills/` |\n| Settings | `~/.claude/settings.json` |\n`~/.codex/config.toml` |\n| MCP | `~/.claude/.mcp.json` |\n`[mcp_servers.*]` in `config.toml` |\n\nHand-rolling the sync invites **drift, semantic loss, and accidental secret leaks**. This CLI keeps the two hosts aligned while preserving host-native meaning.\n\nThis 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.\n\nOne-shot migrators typically copy Claude-only vocabulary (tool names like `Read`\n\n/ `Bash`\n\n, prose like `Use the Bash tool`\n\n, in-line `Agent({...})`\n\ncalls) 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`\n\n→ `workspace-write`\n\n, `TaskCreate`\n\n→ `spawn_agent`\n\n, `claude -p`\n\n→ `codex exec`\n\n, …) and **round-trips them back** when syncing the other direction — so the same content stays correct for both hosts with no manual fix-ups.\n\n```\nnpm install -g ai-config-sync-manager\nai-config-sync connect           # register the plugin for any detected host (Claude / Codex)\nai-config-sync status            # show drift across global + project scopes\nai-config-sync sync              # preview changes (--dry-run by default)\nai-config-sync sync --apply      # apply with automatic backups\n```\n\n`connect`\n\nonly registers plugins for hosts it actually finds (`~/.claude`\n\nfor Claude, `~/.codex`\n\nor `~/.agents`\n\nfor Codex). Hosts that are missing are reported as `skipped`\n\nand no directories are created — install the host first, then rerun `connect`\n\n.\n\n- Node.js\n**≥ 20** - Claude Code and/or Codex CLI installed (host plugins are auto-registered by\n`connect`\n\nwhen the matching host directory exists)\n\n| Category | Sections |\n|---|---|\nCommands |\n|\n\n**Workflow**[Selector syntax](#selector-syntax)·[Ignore rules](#ignore-rules)·[Sync direction](#sync-direction)·[Scopes](#scopes)** Safety**[Safety defaults](#safety-defaults)·[Risk levels](#risk-levels)·[Retention](#retention)** Mapping**[Native mapping](#native-mapping-claude--codex)·[Areas](#areas)·[Paraphrase](#paraphrase)·[Hidden markers](#hidden-markers)·[Unsupported](#unsupported)**Reference**[Install resolution](#install-resolution)·[Local dev](#local-dev-from-this-repo)·[Gotchas](#gotchas)·[API surface](#api-surface)·[What's next](#whats-next)After `npm install -g`\n\n, the same binary is on PATH as `ai-config-sync`\n\n— equivalent to `./bin/ai-config-sync.mjs`\n\nfrom a source clone.\n\n```\nai-config-sync connect\nai-config-sync status\nai-config-sync status --json\nai-config-sync status --scope global\nai-config-sync status --scope project\nai-config-sync status --include skills:code-writer,instructions --exclude mcp\nai-config-sync sync --dry-run\nai-config-sync sync --scope project --dry-run\nai-config-sync sync --scope global --apply\nai-config-sync sync --include instructions,skills:code-writer --exclude mcp --dry-run\nai-config-sync sync --from claude --to codex\nai-config-sync sync --from codex --to claude\nai-config-sync board\nai-config-sync board --scope global --no-open\nai-config-sync reference\nai-config-sync paraphrase\n```\n\n| Command | Purpose |\n|---|---|\n`connect` |\nDetect installed hosts and register the matching plugin |\n`status` |\nCompare global + project config across both hosts |\n`status --json` |\nMachine-readable diff |\n`sync --dry-run` |\nPreview the merge plan without writing |\n`sync --apply` |\nApply the plan, snapshot to `.backups/` |\n`board` |\nRender an HTML inventory board of both hosts, colored by sync status |\n`reference` |\nEmit / persist a self-generated markdown reference |\n`paraphrase` |\nLine-level override archive for instruction wording |\n\n| Host | Connect | Status | Sync | Paraphrase |\n|---|---|---|---|---|\nClaude |\n`/config-manager:connect` |\n`/config-manager:status` |\n`/config-manager:sync` |\n`/config-manager:paraphrase` |\nCodex |\n`config-manager-connect` |\n`config-manager-status` |\n`config-manager-sync` |\n`config-manager-paraphrase` |\n\nPer-subcommand flag reference, mirroring `<command> --help`\n\noutput. Shared flags (`--include`\n\n/ `--exclude`\n\n/ `--scope`\n\n/ `--map`\n\n) get a one-line summary; full syntax lives in the linked section.\n\n| Flag | Description |\n|---|---|\n`-h` , `--help` |\nShow connect help |\n\n```\nai-config-sync connect\n```\n\n| Flag | Description |\n|---|---|\n`--json` |\nPrint the full status report as JSON |\n`--compact` |\nOne compact line per diff entry |\n`--tree` |\nScope/area/item tree output |\n`--scope global|project|all` |\nLimit scope (default: `all` = global + project) |\n`--include area[:item][,...]` |\nInclude selector — see\n|\n\n`--exclude area[:item][,...]`\n\n[Selector syntax](#selector-syntax)`-h`\n\n, `--help`\n\n```\nai-config-sync status --scope project --tree --include skills:code-writer\n```\n\nRenders 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/`\n\nwith no external requests, so it works offline, and opens in your default browser automatically (pass `--no-open`\n\nto skip). ([Screenshot at the top](#highlights).)\n\n| Flag | Description |\n|---|---|\n`--scope global|project|all` |\nLimit scope (default: `all` = global + project) |\n`--include area[:item][,...]` |\nInclude selector — see\n|\n\n`--exclude area[:item][,...]`\n\n[Selector syntax](#selector-syntax)`--no-open`\n\n`-h`\n\n, `--help`\n\n```\nai-config-sync board --scope global\n```\n\n| Flag | Description |\n|---|---|\n`--dry-run` |\nPreview without writing (default; mutually exclusive with `--apply` ) |\n`--apply` |\nApply with backups |\n`--plan-json` |\nPrint the sync plan as JSON |\n`--ledger-json` |\nPrint the apply ledger as JSON to stdout (`--apply` only) |\n`--ledger <path>` |\nWrite the apply ledger JSON to `<path>` (`--apply` only) |\n`--from claude|codex` |\nSource host (overrides `AI_CONFIG_SYNC_HOST` ) |\n`--to claude|codex` |\nTarget host (overrides `AI_CONFIG_SYNC_HOST` ) |\n`--scope global|project|all` |\nLimit scope (default: `all` = global + project) |\n`--include area[:item][,...]` |\nInclude selector — see\n|\n\n`--exclude area[:item][,...]`\n\n[Selector syntax](#selector-syntax)`-h`\n\n, `--help`\n\nWhen `--from`\n\n/ `--to`\n\nare omitted, direction follows [Sync direction](#sync-direction).\n\n```\nai-config-sync sync --scope project --include mcp:notion --apply\n```\n\n| Flag | Description |\n|---|---|\n`--output <path>` |\nWrite the reference markdown to `<path>` (parent directories created) |\n`-h` , `--help` |\nShow reference help |\n\n```\nai-config-sync reference --output ~/.ai-config-sync-manager/reference.md\n```\n\n| Flag | Description |\n|---|---|\n`--apply` |\nRewrite files + register overrides + persist new map entries (default: dry-run) |\n`--register` |\nSkip rewriting; only register overrides where the effective map already equates both sides — see\n|\n\n`--map token=paraphrase[,...]`\n\n`--map`\n\nsyntax`--non-interactive`\n\n`paraphrase-map.json`\n\n`--json`\n\n`--scope global|project|all`\n\n`all`\n\n= global + project)`--include area[:item][,...]`\n\n[Selector syntax](#selector-syntax)`--exclude area[:item][,...]`\n\n[Selector syntax](#selector-syntax)`-h`\n\n, `--help`\n\n```\nai-config-sync paraphrase --map \"Read=read the file,Write=write to the file\" --apply\n```\n\n`--include`\n\nnarrows the plan first, then `--exclude`\n\nremoves matches. Both accept `area`\n\nor `area:item`\n\nsyntax; itemized areas (`skills`\n\n, `permissions`\n\n, `hooks`\n\n, `agents`\n\n, `mcp`\n\n, `commands`\n\n) accept glob items.\n\n```\nai-config-sync sync --include skills:code-writer,instructions --exclude mcp --dry-run\nai-config-sync sync --include \"permissions:Write*\" --exclude \"permissions:Bash(rm:*)\" --dry-run\n```\n\n| Area | Itemized? | Apply granularity |\n|---|---|---|\n`instructions` |\n— | file merge |\n`skills` |\nyes | per skill |\n`agents` |\nyes | per agent |\n`mcp` |\nyes | per server |\n`permissions` |\nyes | item-by-item patch |\n`hooks` |\nyes | item-by-item patch |\n`commands` |\nyes | per command |\n`plugins` |\nyes | status only (read-only diff; `sync` skips this area) |\n\nPersistent ignore lives at one of:\n\n`<project>/.ai-config-sync-manager/status-ignore.json`\n\n(project scope, checked first)`~/.ai-config-sync-manager/rules/status-ignore.json`\n\n(global)\n\nEach `exclude`\n\nentry is a string selector (`area:item`\n\nor path glob) **or** an object whose fields combine with AND. `term`\n\nis 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.\n\n```\n{\n  \"version\": 1,\n  \"exclude\": [\n    \"skills:legacy-skill\",\n    \"permissions:Bash\",\n    \"~/.codex/agents/archive-*.toml\",\n    { \"scope\": \"global\", \"area\": \"agents\", \"item\": \"refactor-*\" },\n    { \"area\": \"skills\", \"host\": \"claude\", \"path\": \"~/.claude/skills/coderabbit-review\" },\n    { \"area\": \"skills\", \"term\": \".claude/docs/repo-analysis/\" },\n    { \"area\": \"agents\", \"host\": \"claude\", \"path\": \"~/.claude/agents/*.md\", \"term\": \"TODO: do not sync\" }\n  ]\n}\n```\n\nThe active path and rule count are echoed in `status`\n\noutput as `Status ignore: <path> rules: [...] (N hidden)`\n\n.\n\n| Trigger | Default direction |\n|---|---|\n`AI_CONFIG_SYNC_HOST=codex` (Codex plugin invocation) |\n`codex → claude` |\n| Otherwise (Claude plugin / direct CLI) | `claude → codex` |\n`--from <host> --to <host>` |\nExplicit override |\n\n| Scope | Path coverage |\n|---|---|\n`global` |\n`~/.claude/**` , `~/.codex/**` |\n`project` |\n`<cwd>/.claude/**` , `<cwd>/.codex/**` , `<cwd>/AGENTS.md` , `<cwd>/CLAUDE.md` |\ndefault / `all` |\n`global + project` |\n\n**Dry-run first**—`sync`\n\ndefaults to dry-run;`--apply`\n\nis required for any write.**Backups on every write**— atomic snapshot to`.backups/<area>/<host>/<timestamp>/...`\n\nbefore overwrite.**Apply ledger**— every`--apply`\n\nrecords a per-item sha256 attestation (`before_hash`\n\n/`after_hash`\n\n,`backup_path`\n\n,`plan_hash`\n\n) to`~/.ai-config-sync-manager/ledgers/<timestamp>.json`\n\n;`--ledger <path>`\n\ncopies it elsewhere and`--ledger-json`\n\nprints it to stdout.**Risk labels**— high-impact entries (`permissions`\n\n,`hooks`\n\n, custom commands) marked with their risk level in the diff.**Strict-vocab guard**— host-only tokens (e.g. Codex`update_plan`\n\n) flagged on cross-host copy.**Secret pass-through**— MCP env values are copied by default; set`AI_CONFIG_SYNC_STRIP_SECRETS=1`\n\nto redact.**Schema version**— baseline state requires`schemaVersion: 1`\n\n; unknown versions abort.\n\n| Level | Meaning | Behavior |\n|---|---|---|\n`safe` |\nLossless, deterministic mapping | Auto-applied |\n`partial` |\nMaps to a near-equivalent on the other host | Auto-applied with annotation |\n`manual` |\nNo safe automatic equivalent | Listed in the plan but always review before `--apply` |\n\n| Directory | Keep | Strategy |\n|---|---|---|\n`.backups/<area>/<host>/` |\n30 | FIFO (oldest pruned on next write) |\n`~/.config/ai-config-sync/status-details/` |\n100 | FIFO |\n`~/.ai-config-sync-manager/ledgers/` |\n300 | FIFO (oldest pruned on next `--apply` ) |\n\n| Claude | Codex |\n|---|---|\n`permissions.allow: [\"Write\"]` |\n`sandbox_mode = \"workspace-write\"` |\ncommand-like `permissions.allow` (e.g. `Bash(npm:*)` ) |\n`approval_policy = \"on-request\"` |\n`.mcp.json` server entries |\n`[mcp_servers.<name>]` TOML tables |\n`hooks.PreToolUse` / `PostToolUse` |\nmapped where a Codex equivalent exists, else `manual` |\n`~/.claude/skills/<name>/SKILL.md` |\n`~/.codex/skills/<name>/SKILL.md` |\n\nFull mapping reference: [ rules/](/slash9494/ai-config-sync-manager/blob/main/rules).\n\nSome tokens are **mutually exclusive** between hosts — `Read`\n\n, `Write`\n\n, `Edit`\n\n, `Glob`\n\n, `mcp__*`\n\nonly exist on Claude; `update_plan`\n\n, `spawn_agent`\n\n, `apply_patch`\n\nonly exist on Codex (full list: [ rules/host-strict-vocab.json](/slash9494/ai-config-sync-manager/blob/main/rules/host-strict-vocab.json)). When such a token leaks into the wrong host's file, the terminology map cannot translate it, so\n\n`status`\n\nkeeps reporting the line as a `manual-review`\n\nmismatch forever.This is what keeps **strict YAML round-trip** stable across repeated syncs: without it, host-specific vocabulary would oscillate or accumulate as drift on every cycle.\n\n`paraphrase`\n\nresolves these by rewriting **both sides** to a shared word and registering a per-line override so future status runs treat the pair as in sync.\n\n```\nai-config-sync paraphrase                                            # dry-run preview\nai-config-sync paraphrase --apply                                    # rewrite + register\nai-config-sync paraphrase --map \"Read=Inspect,Write=Author\" --apply  # inline mapping\nai-config-sync paraphrase --register --include skills:foo --apply    # register only (no rewrite)\n```\n\n| Flag | Purpose |\n|---|---|\n`--apply` |\nRewrite files, append to `paraphrase-overrides.json` , persist new entries to `paraphrase-map.json` (default: dry-run) |\n`--map token=paraphrase[,...]` |\nInline token-to-paraphrase pairs; layered on top of the file map |\n`--register` |\nSkip rewriting; only register an override when the effective map already makes both sides byte-equal |\n`--non-interactive` |\nSkip TTY prompts for tokens missing from the map |\n`--scope global|project|all` |\nLimit paraphrase scope (default: both) |\n`--include` / `--exclude` |\nSame selector syntax as `status` / `sync` |\n`--json` |\nMachine-readable result |\n\n`Token=Paraphrase`\n\nfor unambiguous tokens listed in`host-strict-vocab.json`\n\n.- Prefix with\n`claude_only:`\n\nor`codex_only:`\n\nto disambiguate (e.g.`claude_only:Read=Inspect`\n\n). - Comma-separated to chain entries:\n`--map \"Read=Inspect,codex_only:update_plan=Plan refresh\"`\n\n. - Tokens not present in\n`host-strict-vocab.json`\n\nare rejected unless prefixed. **Paraphrase can be free-form prose, not just a single word.** Pick wording that reads naturally on the*opposite*host so the rewritten line still makes sense in context — e.g. when masking a Claude-only token, choose phrasing a Codex prompt would actually use (`Read=read the file`\n\n,`Write=write to the file`\n\n,`Glob=glob for files`\n\n). Quote the value when it contains spaces.\n\n| File | Role |\n|---|---|\n`rules/paraphrase-map.json` |\nToken → paraphrase entries grouped under `claude_only` / `codex_only` |\n`rules/paraphrase-overrides.json` |\nPer-line override archive (host paths, line numbers, anchor texts) |\n\nBoth files follow the same precedence as terminology rules: `<project>/rules/<file>.json`\n\n→ `~/.ai-config-sync-manager/rules/<file>.json`\n\n→ `<repo>/rules/<file>.json`\n\n.\n\n```\n# Preview rewrites for every drifted host-only token\nai-config-sync paraphrase\n\n# Apply with an inline map for two common offenders\nai-config-sync paraphrase --map \"Read=Inspect,Write=Author\" --apply\n\n# Scope to a single agent file in global config\nai-config-sync paraphrase --scope global --include agents:code-writer --apply\n\n# Side already pre-paraphrased outside the CLI — just record the override\nai-config-sync paraphrase --register --include skills:code-writer \\\n  --map \"Read=Inspect,Write=Emit\" --apply\n\n# Natural-language intent — slash-command agent translates this into the\n# matching --map flags on the fly (no need to spell out token=paraphrase pairs)\n/config-manager:paraphrase rewrite to Codex-compatible wording\n```\n\nOverrides are auto-invalidated when the pinned anchor text on either host drifts, so manual edits cleanly retire the recorded pairing without leaving stale entries. The active / stale counts are echoed in `status`\n\noutput.\n\nHTML comment markers the call compiler emits inside transformed text. They are reverse-direction-stable and ignored by humans during normal use.\n\n| Marker | Meaning |\n|---|---|\n`<!-- ai-config-sync:agent-call ... -->` |\nSupported call transformed (see\n|\n\n`<!-- ai-config-sync:stripped ... -->`\n\n`~/.ai-config-sync-manager/backups/<timestamp>/unsupported-calls.json`\n\n.`<!-- ai-config-sync:manual-review reason=\"...\" -->`\n\nItems the engine deliberately does not sync, with the reason and the surface where they remain visible:\n\n| Surface | Behavior | Why |\n|---|---|---|\n`TaskCreate` / `TaskUpdate` / `TeamCreate` SDK calls |\nStripped with `ai-config-sync:stripped` marker; original payload archived under the backup root (`unsupported-calls.json` ) |\nCodex has no native todo/task tracker tool nor an atomic agent-team primitive |\nSymlinked skills (`~/.claude/skills/<name>` is a symlink) |\nReported by `status` as `unsupported` (action: `manual review` ); excluded from `sync --apply` |\nWhether to copy the link or materialize target content is an unresolved policy. Resolve manually by either rewriting as a real directory on the source host, or applying via `--include skills:<name>` after the policy lands |\n`memory` / implicit context / agent runtime state |\nOut of scope for now (no read, no write) | Storage layout, redaction rules, and conflict policy not yet settled. Tracked in\n`status` |\n\n`~/.claude/plugins/installed_plugins.json`\n\n, `~/.agents/plugins/marketplace.json`\n\n)`status --scope global`\n\nas `unsupported`\n\n(action: `manual review`\n\n); excluded from `sync --apply`\n\n. Self-managed `config-manager@ai-config-sync-manager`\n\n/ `ai-config-sync-manager`\n\nare filtered out so they never surface as drift`/plugin install <name>@<source>`\n\nfor Claude, edit `~/.agents/plugins/marketplace.json`\n\nfor Codex.The plugin launcher resolves the CLI in this order:\n\n`AI_CONFIG_SYNC_ROOT`\n\nenv (dev override)- PATH\n`ai-config-sync`\n\n(`npm install -g`\n\nor`npm link`\n\n) `npm exec --yes --package=ai-config-sync-manager@<pin>`\n\nfallback\n\nAfter `npm install -g`\n\n, every host calls the same npm package, so two hosts cannot drift to different versions.\n\n`npm install`\n\nruns the `prepare`\n\nscript, which builds `dist/`\n\n(without touching active plugin caches) so the launcher and host plugin trees are ready to inspect immediately after clone.\n\n`npm run dev`\n\nand `npm run prod`\n\ntoggle between linking the local clone for active development and switching back to a published npm release for verification.\n\n``` php\nnpm install           # also runs `prepare` -> build:dist --skip-sync\nnpm run dev           # npm link + build:dist (active plugin cache sync) — local dev mode\nnpm run prod          # unlink + npm i -g ai-config-sync-manager (latest stable) + plugin reinstall hint\nnpm run prod beta     # opt into a tagged dist-tag (e.g. `beta`, `next`) during prerelease cycles\nnpm test              # node:test integration suite\nnpm run check         # opt-in JSDoc / @ts-check\nnpm run lint\nnpm run format:check\n```\n\nInside a clone, invoke the CLI as `./bin/ai-config-sync.mjs <command>`\n\n(the published `ai-config-sync`\n\nshim only exists after `npm install -g`\n\nor `npm link`\n\n).\n\n**No programmatic API.**`bin/ai-config-sync.mjs`\n\nexecutes on import. Do not`import`\n\nit from another module — see[API surface](#api-surface).**Symlink skills,**— see`TaskCreate`\n\n/`TaskUpdate`\n\n/`TeamCreate`\n\n, and memory/runtime state are not synced[Unsupported](#unsupported)for the per-surface behavior.**Codex host inversion**— when invoked through the Codex plugin,`AI_CONFIG_SYNC_HOST=codex`\n\nflips the default direction to`codex → claude`\n\n. Use`--from`\n\n/`--to`\n\nfor an explicit override.**MCP env values are copied verbatim by default**— opt in to redaction with`AI_CONFIG_SYNC_STRIP_SECRETS=1`\n\n., but reversible: every write creates a`--apply`\n\nis final`.backups/`\n\nsnapshot.`--dry-run`\n\nis the default for a reason.\n\nThis is a **CLI tool**, not a library. There is no programmatic API — `import`\n\n-ing this package from another Node module is not supported and the bundled `bin/ai-config-sync.mjs`\n\nis not designed to be loaded as a library (it executes the command on import). All functionality is exposed through the `ai-config-sync`\n\ncommand and the host plugins. If you need programmatic access to a specific function (mapping rules, plan generation, status diff), open an issue describing the use case so the surface can be designed deliberately.\n\n| Item | Status | Notes |\n|---|---|---|\nAdditional host integrations (Gemini CLI,Cursor, …) |\nPlanned | The launcher pattern is reusable. Each new host gets its own `integrations/<host>-plugin/` after a survey of its plugin/extension spec and config storage layout. |\nMemory / context sync |\nDeferred (RFC-first) | `memory` , implicit context, and agent runtime state currently sit outside the sync surface. The first phase will be read-only discovery / status; `--apply` is reserved for opt-in selectors (e.g. `--include memories:<name>` ) once storage location, schema, redaction, and conflict policy are settled. |\n| Skill symlink full support | Deferred | Symlinked skills appear in `status` only. `sync` will engage once the link-preserve vs target-materialize policy is finalized. |\nPlugin sync (`plugins` area) |\nStatus-only today | `status --scope global` lists user-installed plugins from both hosts as `unsupported` with install hints. Bidirectional sync requires designing the cross-host mapping for marketplace metadata, install commands, and plugin tree copy semantics. |\nExtra mappings (`rules/*.json` import, TOML parser swap) |\nTracked | Mechanical refactors with no user-visible API change. |\n\nIf any of these unblocks your workflow, an issue with the concrete use case helps prioritize the order.\n\nMIT", "url": "https://wpnews.pro/news/show-hn-sync-claude-code-and-codex-configs-with-a-board-that-shows-the-drift", "canonical_source": "https://github.com/slash9494/ai-config-sync-manager", "published_at": "2026-07-25 05:00:14+00:00", "updated_at": "2026-07-25 05:22:15.355024+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "large-language-models"], "entities": ["ai-config-sync-manager", "Claude Code", "Codex", "Node.js"], "alternates": {"html": "https://wpnews.pro/news/show-hn-sync-claude-code-and-codex-configs-with-a-board-that-shows-the-drift", "markdown": "https://wpnews.pro/news/show-hn-sync-claude-code-and-codex-configs-with-a-board-that-shows-the-drift.md", "text": "https://wpnews.pro/news/show-hn-sync-claude-code-and-codex-configs-with-a-board-that-shows-the-drift.txt", "jsonld": "https://wpnews.pro/news/show-hn-sync-claude-code-and-codex-configs-with-a-board-that-shows-the-drift.jsonld"}}