Back to skills
extension
Category: Development & EngineeringNo API key required

ln-004-agent-config-sync

Sync skills (symlinks) and MCP settings from Claude to Gemini CLI and Codex CLI

personAuthor: jakexiaohubgithub

Paths: File paths (shared/, references/, ../ln-*) are relative to skills repo root. If not found at CWD, locate this SKILL.md directory and go up one level for repo root.

Agent Sync (Standalone Utility)

Type: Standalone Utility Category: 0XX Shared

Synchronizes skills and MCP server configurations from Claude Code (source of truth) to Gemini CLI and Codex CLI. Creates symlinks for skills, copies/converts MCP settings.


When to Use This Skill

  • After adding/removing MCP servers in Claude Code settings
  • After installing new plugins in Claude Code
  • First-time setup of Gemini CLI or Codex CLI alongside Claude Code
  • Periodic sync to keep all agents aligned

Input Parameters

| Parameter | Required | Default | Description | |-----------|----------|---------|-------------| | targets | No | both | gemini, codex, or both | | mode | No | full | skills (symlinks only), mcp (MCP only), or full (both) | | dry_run | No | false | Show planned actions without executing |


Workflow

Detect OS → Discover Configs → Sync Skills → Sync MCP → Report

Phase 0: OS Detection

| Check | Result | Impact | |-------|--------|--------| | uname or platform | win32 / darwin / linux | Junction vs symlink | | Home directory | $HOME or $USERPROFILE | Config paths |

Paths by OS:

| Agent | Windows | macOS / Linux | |-------|---------|---------------| | Claude | %USERPROFILE%\.claude.json (primary) | ~/.claude.json (primary) | | Claude | %USERPROFILE%\.claude\settings.json (fallback) | ~/.claude/settings.json (fallback) | | Gemini | %USERPROFILE%\.gemini\settings.json | ~/.gemini/settings.json | | Codex | %USERPROFILE%\.codex\config.toml | ~/.codex/config.toml |

Phase 1: Discover Current State

  1. Read Claude settings (check both sources, merge):

    • Parse ~/.claude.json → extract mcpServers block (primary source, app state file)
    • Parse ~/.claude/settings.json → extract mcpServers block (fallback, user settings file)
    • Merge: primary overrides fallback by server name
    • If no mcpServers in either → WARN "No MCP servers configured in Claude", skip MCP sync
  2. Read target configs (if exist):

    • Gemini: Parse ~/.gemini/settings.json → extract existing mcpServers
    • Codex: Parse ~/.codex/config.toml → extract existing [mcp_servers.*]
  3. Detect installed plugins:

    • Glob ~/.claude/plugins/*/plugin.json → list plugin directories
    • Also check if skills repo itself is a plugin source
  4. Check existing symlinks:

    • ~/.gemini/skills → exists? points where?
    • ~/.codex/skills → exists? points where?
  5. Show current state:

    Current State:
    | Agent | Skills | MCP Servers | Config Exists |
    |-------|--------|-------------|---------------|
    | Claude (source) | 5 plugins | 4 servers | yes |
    | Gemini | no link | 2 servers | yes |
    | Codex | → ~/.claude/plugins | 4 servers | yes |
    

Phase 2: Sync Skills (symlinks/junctions)

FOR EACH target IN (gemini, codex) WHERE target in targets:

  1. Determine link path:

    • Gemini: ~/.gemini/skills
    • Codex: ~/.codex/skills
  2. Check if already linked correctly:

    • IF link exists AND points to correct source → SKIP (already synced)
    • IF link exists AND points to wrong source → WARN, ask user before replacing
    • IF regular directory (not link) exists → WARN "Target is a real directory, not a link. Skip to avoid data loss."
  3. Determine source:

    • IF single plugin: link directly to plugin dir
    • IF multiple plugins: ask user which plugin to share
  4. Create link:

    | OS | Command | |----|---------| | Windows | cmd /c mklink /J "{target_path}" "{source_path}" | | macOS / Linux | ln -s "{source_path}" "{target_path}" |

  5. Verify: Check link exists and resolves correctly

Phase 3: Sync MCP Settings

Source: ~/.claude.json (primary) + ~/.claude/settings.json (fallback) → merged mcpServers

3a: Claude → Gemini (JSON → JSON)

  1. Read Claude mcpServers as JSON object
  2. Read Gemini settings.json (or create {} if missing)
  3. Merge strategy: Claude servers override Gemini servers by key name. Gemini-only servers preserved.
  4. Write updated settings.json

Conversion: Transport type mapping required:

| Claude field | Gemini field | Notes | |---|---|---| | type: "http" + url | httpUrl | Streamable HTTP | | type: "sse" + url | url | SSE transport | | command + args | command + args + cwd | stdio (same format) | | env | env | Same format ($VAR_NAME syntax in Gemini) | | headers | headers | Same format (JSON object, for url/httpUrl) |

Gemini-only fields (not mapped from Claude):

  • timeout — request timeout in ms (default: 10min)
  • trust — bypass tool confirmations
  • includeTools / excludeTools — tool whitelist/blacklist

3b: Claude → Codex (JSON → TOML)

  1. Read Claude mcpServers as JSON object

  2. Read Codex config.toml (or create empty if missing)

  3. Convert each server:

    | Claude JSON field | Codex TOML field | Notes | |-------------------|------------------|-------| | command | command | Same | | args | args | JSON array → TOML array | | env | [mcp_servers.{name}.env] | Nested table | | type: "http" + url | url | Streamable HTTP (Codex auto-detects by url presence) | | type: "sse" + url | url | SSE → Streamable HTTP (same url field) | | headers | http_headers | Different key name! Static header values |

    Example conversion:

    "context7": {
      "command": "npx",
      "args": ["-y", "@upstash/context7-mcp"]
    }
    
    [mcp_servers.context7]
    command = "npx"
    args = ["-y", "@upstash/context7-mcp"]
    
  4. Merge strategy: Claude servers override. Codex-only servers preserved.

  5. Write updated config.toml

Codex-only fields (preserve as-is, no Claude equivalent):

  • bearer_token_env_var — Codex bearer token auth
  • enabled_tools / disabled_tools — Codex tool filtering
  • startup_timeout_sec / tool_timeout_sec — Codex timeouts
  • enabled / required — Codex server lifecycle
  • env_vars / env_http_headers — Codex env-based headers

Phase 4: Report

Sync Complete:
| Action | Target | Status |
|--------|--------|--------|
| Skills symlink | Gemini | Created → ~/.claude/plugins/... |
| Skills symlink | Codex | Already linked |
| MCP sync | Gemini | 4 servers synced (2 new, 2 updated) |
| MCP sync | Codex | 4 servers synced (1 new, 3 updated) |

Critical Rules

  1. Claude = source of truth. Never write TO Claude settings. Read-only source.
  2. Non-destructive merge. Target-only servers/settings preserved. Only Claude servers added/updated.
  3. No data loss. If target is a real directory (not symlink) — warn and skip, never delete.
  4. Backup before write. Before modifying any config file, create .bak copy.
  5. Dry run first. If dry_run=true, show all planned actions without executing.
  6. Ask on conflict. If symlink points to different source — ask user, don't auto-replace.

Anti-Patterns

  • Writing TO Claude settings from Gemini/Codex (reverse sync)
  • Deleting target-only MCP servers during sync
  • Creating symlinks inside symlinks (circular)
  • Modifying config files without backup

Definition of Done

| # | Criterion | |---|-----------| | 1 | Claude settings read successfully | | 2 | Skills symlinks created/verified for each target | | 3 | MCP settings synced with format conversion (JSON→TOML for Codex) | | 4 | Backup files created before any config modification | | 5 | Report shown with all actions and warnings |


Version: 1.1.0 Last Updated: 2026-03-09