Claude-code-skills ln-013-config-syncer
Use when syncing skills, MCP settings, defaults, and hooks from Claude Code to Gemini CLI, Codex CLI, and Google Antigravity. Verifies language-analyzer providers for synced MCP servers match the project's languages.
git clone https://github.com/levnikolaevich/claude-code-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/levnikolaevich/claude-code-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills-catalog/ln-013-config-syncer" ~/.claude/skills/levnikolaevich-claude-code-skills-ln-013-config-syncer && rm -rf "$T"
skills-catalog/ln-013-config-syncer/SKILL.mdPaths: File paths (
,shared/) are relative to skills repo root. Locate this SKILL.md directory and go up one level for repo root.references/
Config Syncer
Type: L3 Worker Category: 0XX Shared
Synchronizes skills and MCP/hook settings from Claude Code (source of truth) to Gemini CLI and Codex CLI. Gemini skills are shared via symlink/junction. Codex skills are mapped as active installs under
~/.codex/skills, with cache kept outside the Codex discovery root. Converts formats: JSON for Gemini, TOML for Codex.
Shared MCP servers still come from Claude. Codex top-level execution defaults are a managed local policy owned by this skill because Claude has no equivalent
approval_policy / sandbox_mode fields.
MANDATORY READ
MANDATORY READ: Load
shared/references/coordinator_summary_contract.md, shared/references/environment_worker_runtime_contract.md, and shared/references/worker_runtime_contract.md
MANDATORY READ: Load shared/references/agent_skill_roots_contract.md
Input / Output
| Direction | Content |
|---|---|
| Input | OS info, flags per agent, ( / / / / ), flag, optional flag, optional , optional |
| Output | Structured summary envelope with = / / , plus per-target sync outcomes in / |
If
summaryArtifactPath is provided, write the same summary JSON there. If not provided, return the summary inline and remain fully standalone. If runId is not provided, generate a standalone run_id before emitting the summary envelope.
Runtime
Runtime family:
environment-worker-runtime
Phase profile:
PHASE_0_CONFIGPHASE_1_DISCOVER_STATEPHASE_2_SYNC_SKILLS_MAPPINGPHASE_3_SYNC_MCP_SETTINGS
5a.PHASE_4_SYNC_HOOKS_AND_POLICYPHASE_4A_MCP_PROVIDER_CHECKPHASE_5_WRITE_SUMMARYPHASE_6_SELF_CHECK
Runtime rules:
- emit
summary_kind=env-config-sync - standalone runs generate their own
and write the default worker-family artifact pathrun_id - managed runs require both
andrunId
and must write the summary to the exact provided pathsummaryArtifactPath - always write the validated summary artifact before terminal outcome
Output Contract
Always build a structured
env-config-sync summary envelope per:
shared/references/coordinator_summary_contract.mdshared/references/environment_worker_runtime_contract.md
Payload fields:
targetsskills_mappingmcp_syncantigravity_syncmcp_providershook_syncgemini_policycodex_execution_defaultsstatus
Config Paths by OS
| Agent | Windows | macOS / Linux |
|---|---|---|
| Claude (primary) | | |
| Claude (fallback) | | |
| Gemini | | |
| Codex | | |
Workflow
Discover State --> Sync Skills / Mapping --> Sync MCP --> Sync Hooks / Policy --> Verify & Report
Phase 1: Discover State
- Read Claude settings (source of truth):
(primary) +~/.claude.json
(fallback)~/.claude/settings.json- Merge: primary overrides fallback by server name
- Read target configs (if they exist):
- Gemini:
→ extract~/.gemini/settings.jsonmcpServers - Codex:
→ extract~/.codex/config.toml
, top-level[mcp_servers.*]
, and top-levelapproval_policysandbox_mode
- Gemini:
- Inspect skill roots:
- Gemini skill link:
~/.gemini/skills - Codex discovery root:
~/.codex/skills - Codex active marketplaces:
~/.codex/skills/marketplaces/* - Codex illegal cache path:
~/.codex/skills/cache/** - Codex cache root candidates outside discovery:
~/.codex/skill-cache/* - Codex marketplace metadata:
~/.codex/skills/known_marketplaces.json
- Gemini skill link:
- Detect duplicate skill directory names under the Codex discovery root
- Display current state table with active roots, cache roots, duplicate-risk findings, and Codex execution-default drift
Phase 2: Sync Skills / Mapping
For each target where
disabled is not true:
2a: Gemini skill link
| OS | Command |
|---|---|
| Windows | |
| macOS/Linux | |
Gemini decision logic:
| Condition | Action |
|---|---|
for this agent | SKIP, report |
| Link exists, points correctly | SKIP, report |
| Link exists, points wrong | WARN, ask user before replacing |
| Real directory exists (not link) | WARN, skip (avoid data loss) |
| No link exists | Create link |
| Link exists, target does not exist (stale) | WARN . Remove stale link, recreate with correct target |
Stale junction detection: Use
lstatSync() (succeeds on dangling links) + statSync() (throws if target missing). Do NOT rely on existsSync() alone.
2b: Codex active install mapping
Target structure:
~/.codex/skills/ <- real directory (NOT a junction) marketplaces/ {marketplace-A}/ <- junction -> ~/.claude/plugins/marketplaces/{marketplace-A} {marketplace-B}/ <- junction -> ~/.claude/plugins/marketplaces/{marketplace-B} known_marketplaces.json <- installLocation -> ~/.codex/skills/marketplaces/{marketplace}
Per-marketplace junctions preserve auto-update: when Claude updates a marketplace, Codex sees changes automatically through the junction. Cache and other non-skill directories are excluded from the Codex discovery root.
Codex decision logic:
| Condition | Action |
|---|---|
for this agent | SKIP, report |
is a junction/symlink to (whole-root) | Replace with real directory + per-marketplace junctions (see steps below) |
exists | Relocate cache outside the discovery root (or report the planned move on ) |
points to or another foreign root | Rewrite to the active Codex marketplace path () |
Active marketplace exists under as junction and duplicate scan is clean | SKIP, report |
| Active marketplace missing but an approved source exists | Create junction -> |
Duplicate skill names remain under after relocation / repair | FAIL sync health, report discovery violation |
Whole-root junction detection: Use
fs.lstatSync('~/.codex/skills').isSymbolicLink(). If true and fs.readlinkSync() points to ~/.claude/plugins, this is a whole-root junction that must be replaced.
Steps for whole-root junction replacement (Windows):
- Backup
content (read before removing junction)known_marketplaces.json - Remove junction:
-- safe for junctions, does not delete targetexecSync('rmdir "<path>"', { shell: 'cmd.exe' }) - Create real directory:
fs.mkdirSync('<path>', { recursive: true }) - Create
<path>/marketplaces/ - For each enabled marketplace in
->~/.claude/settings.json
:enabledPlugins- Create junction:
fs.symlinkSync('<claude_marketplace_path>', '<codex_marketplace_path>', 'junction')
- Create junction:
- Write
withknown_marketplaces.json
pointing to the Codex-local marketplace pathinstallLocation - Verify: no
, junctions resolve, duplicate scan cleancache/
Steps for whole-root junction replacement (macOS/Linux):
- Backup
contentknown_marketplaces.json - Remove symlink:
(notrm ~/.codex/skills
-- symlink only)rm -rf - Create real directory:
mkdir -p ~/.codex/skills/marketplaces - For each enabled marketplace:
ln -s ~/.claude/plugins/marketplaces/{mp} ~/.codex/skills/marketplaces/{mp} - Write
with Codex-localknown_marketplaces.jsoninstallLocation
Implementation note: On Windows, use a temporary
.mjs script file for the junction replacement sequence, not inline node -e or bash heredocs, because Windows path escaping is fragile in shells.
Rules for Codex mapping:
- Never symlink or junction
itself to the Claude plugin tree.~/.codex/skills - Never expose cache snapshots under the Codex discovery root.
is part of the Codex mapping contract and must agree with the active marketplace path.known_marketplaces.json- A marketplace-level junction is the preferred mapping strategy. A whole-root mirror of
is not acceptable..claude/plugins - Per-marketplace junctions auto-update when Claude updates marketplaces -- no manual re-sync needed.
Phase 3: Sync MCP Settings
IF agent
disabled: true → SKIP for that target.
3a: Claude to Gemini (JSON to JSON)
| Claude Field | Gemini Field | Notes |
|---|---|---|
+ | | HTTP (Gemini auto-detects streamable/SSE) |
+ | + | stdio (same format) |
| | Same format |
| | Same format |
Gemini-only fields (preserve during merge, not mapped from Claude):
timeout, trust, includeTools, excludeTools
3b: Claude to Codex (JSON to TOML)
| Claude JSON | Codex TOML | Notes |
|---|---|---|
| | Same |
| | JSON array to TOML array |
| | Nested table |
+ | | Codex auto-detects by presence |
| | Different key name |
Codex-only fields (preserve during merge, not mapped from Claude):
bearer_token_env_var, enabled_tools, disabled_tools, startup_timeout_sec, tool_timeout_sec, enabled, required
Merge strategy (both targets): Claude servers override target by key name. Target-only servers are preserved. Backup
.bak before writing.
Windows implementation note: Config format conversions with regex or backslash escaping (especially JSON → TOML for Codex) MUST use a temporary
.mjs script file, not inline node -e or bash heredocs.
Phase 4: Sync Hooks / Policy
4a: Claude to Gemini (event name + tool name mapping)
| Claude Event | Gemini Event | Notes |
|---|---|---|
| | Same concept, different name |
| | Same concept, different name |
| | Agent completion |
| | Same name |
Tool name mapping in hook matchers:
| Claude Tool Name | Gemini Tool Name(s) |
|---|---|
| |
| (legacy alias: ) |
| |
| |
| |
Hook scripts must support both tool name formats. Prefer current Gemini snake_case names in generated config, but tolerate legacy aliases where encountered during migration.
4b: Codex execution defaults
Managed Codex defaults for this environment setup flow:
approval_policy = "never" sandbox_mode = "danger-full-access"
Decision logic:
| Condition | Action |
|---|---|
Codex target | SKIP, report |
and already present | SKIP, report |
| One or both keys are missing or drifted | Patch only the top-level managed keys, preserve all unrelated top-level keys/tables, create first |
Rules for Codex execution defaults:
- Manage only top-level
and top-levelapproval_policy
.sandbox_mode - Do not rewrite
when aligning Codex full-access defaults. It is a different Windows-specific knob.[windows].sandbox - Preserve unrelated Codex config sections such as
,model
,projects
, andnotice
.[mcp_servers.*]
4c: Claude to Codex
Codex does NOT support hooks. SKIP hook sync for Codex. Report
hooks not supported by Codex CLI.
4d: Gemini MCP Policy
Gemini CLI policy engine blocks MCP tool calls by default (error:
Tool execution denied by policy) even with --yolo. Fix: ensure ~/.gemini/policies/allow-mcp.toml exists.
| Condition | Action |
|---|---|
File exists with allow rule | SKIP |
| File missing or no allow rule | Create |
File content:
[[rule]] mcpName = "*" decision = "allow" priority = 200
Phase 4a: MCP Provider Check (language analyzers)
MANDATORY READ: Load
references/mcp_provider_requirements.md.
Runs once per project invocation after MCP sync, regardless of how many targets were synced. Goal: ensure every MCP server referenced in any synced config has its language-analyzer providers available for the languages the project actually uses.
- Enumerate MCP servers. Union of
across all target configs (Claude, Codex, Gemini, Antigravity). Deduplicate by name.mcpServers - Detect project languages. Probe in order, cheapest first:
,pyproject.toml
,package.json
,tsconfig.json
,Cargo.toml
,go.mod
. Use*.csproj
to probe; do not shell out.mcp__hex-line__inspect_path - Look up provider requirements. Read
. Forreferences/mcp_provider_requirements.md
, the requirement is "delegate tohex-graph
". MCPs not listed in the reference are reported asmcp__hex-graph__install_graph_providers
and skipped.not_applicable - Run provider check. Call
. Surface the reported missing providers and their install commands (e.g., pipmcp__hex-graph__install_graph_providers({ mode: "check", path: <project_root> })
,basedpyright
,rustup component add rust-analyzer
). Do NOT auto-install unless the caller passedgo install gopls
; then call the same tool withauto_install_providers=true
.mode: "install" - Record result. Write into
underenvironment_state.json
(top-level, not per-agent — the MCP is shared across targets in this project).mcp_providers: { <server>: { <language>: "installed" | "missing" | "skipped" | "not_applicable" } }
Scope guard: never install project-level dependencies (do not write to
pyproject.toml / package.json). install_graph_providers itself is contract-bound: "never installs runtimes or project dependencies." Basedpyright's canonical distribution is pip (basedpyright on PyPI); npm is a fallback for projects that cannot use pypi.
Antigravity Target (supplementary, runs alongside Phase 2 and Phase 3)
Google Antigravity loads skills from two roots per the official docs:
- Global:
~/.gemini/antigravity/skills/ - Workspace:
<workspace>/.agents/skills/
Both roots may be active simultaneously. For the Antigravity target this skill:
| Condition | Action |
|---|---|
| SKIP, report |
directory not present | SKIP, report |
Global skills link missing | Create junction/symlink to the active source (same strategy as Gemini CLI) |
Workspace root requested and missing | Create junction/symlink per project, record in env state |
| MCP config location unknown | Probe order: → → . If none found, read from env var and emit a clear error when it is unset |
| MCP config found | Merge using the same Claude→target rules as Gemini (JSON format) |
Antigravity does not ship a separate CLI binary at the time of writing;
ln-011-agent-installer treats it as detect-only.
Phase 5: Verify & Report
Verify:
- Gemini skill link points to the expected active source
- Codex discovery root contains no
cache/** - Codex
points to the active Codex marketplace pathknown_marketplaces.json - Duplicate skill scan under
is clean~/.codex/skills - Codex
=approval_policynever - Codex
=sandbox_modedanger-full-access - MCP targets were merged without deleting target-only settings
Config Sync: | Action | Target | Status | |----------------|--------|-----------------------------------------------------| | Skills symlink | Gemini | created -> ~/.claude/plugins | | Skills mapping | Codex | cache relocated; active install verified | | MCP sync | Gemini | 4 servers synced (2 new) | | MCP sync | Codex | 4 servers synced (1 new) | | Execution mode | Codex | approval_policy=never; sandbox_mode=danger-full-access | | Hooks sync | Gemini | 3 events synced | | Hooks sync | Codex | skipped (not supported) | | MCP policy | Gemini | allow-mcp.toml created | | Discovery root | Codex | clean (0 duplicate skill names) |
Critical Rules
- Claude = source of truth. Never write TO Claude settings. Read-only source
- Non-destructive merge. Target-only servers and settings preserved. Only Claude servers added/updated
- Gemini and Codex do not share the same skill mapping model. Gemini may use a symlink/junction; Codex must use active installs plus cache outside the discovery root
- Codex cache must stay outside
.~/.codex/skills
is always drift~/.codex/skills/cache/** - No data loss. Real directories at target paths -> warn and skip, never delete blindly
- Backup before write. Create
copy before modifying any config file.bak - Respect
flags. Skip all operations for disabled agentsdisabled - Idempotent. Safe to run multiple times. Already-synced state is skipped
- Non-destructive config writes. Always read -> deep-merge -> edit. Never overwrite target config files from scratch. Preserve all keys not mapped from Claude
- Codex execution defaults are managed policy. Keep
andapproval_policy=never
unless the user explicitly requests a different Codex defaultsandbox_mode=danger-full-access - Do not confuse top-level
withsandbox_mode
. Full-access startup is controlled by the top-level key[windows].sandbox
Anti-Patterns
| DON'T | DO |
|---|---|
| Write TO Claude settings from targets | Claude is read-only source |
| Delete target-only MCP servers during sync | Preserve target-only servers |
| Create symlinks inside symlinks (circular) | Check link target before creating |
| Modify config files without backup | Always create first |
| Try to sync hooks to Codex | Report , skip |
Map to | Repair only the Codex active marketplace surface |
Treat as harmless | Relocate it outside the discovery root and re-scan |
| Count every cache snapshot as a real Codex skill | Scan only the active Codex discovery root after remediation |
Treat as the Codex full-access default | Manage top-level instead |
Rewrite from scratch to fix permission drift | Patch only / and preserve the rest |
| Auto-replace mispointed links without warning | Ask user before replacing |
| Overwrite entire config file with only known fields | Read existing -> deep-merge only owned fields -> edit back |
Definition of Done
- Claude settings read successfully (both config locations)
- Gemini skill link created/verified for each non-disabled target
- Codex active install mapping repaired or verified, with cache outside
~/.codex/skills - MCP settings synced with correct format conversion (JSON for Gemini, TOML for Codex)
- Codex execution defaults aligned to
andapproval_policy=neversandbox_mode=danger-full-access - Hook events and tool names mapped for Gemini
- Codex hooks skipped with report
- Gemini MCP policy file verified/created
- Codex duplicate-skill scan is clean or explicitly reported as drift
- Backup files created before any config modification
- Final report table displayed
- Structured summary returned
- Summary artifact written to the managed or standalone runtime path
- Antigravity global skill root linked (or SKIPPED with reason)
- Antigravity workspace skill root materialized when requested
- MCP provider check run with result recorded in
mcp_providers
Version: 1.1.0 Last Updated: 2026-04-05