Keep Claude Code, Codex, and OpenCode in sync — automatically.
One config to rule them all. When you add an MCP server, create a skill, or update a rule in Claude Code, this system propagates every change to Codex and OpenCode in the correct format.
You use three AI coding CLIs. Each has its own config format:
| Tool | Config | MCP Format | Skills/Agents |
|---|---|---|---|
| Claude Code | ~/.claude.json |
JSON (type: stdio) |
~/.claude/skills/ |
| Codex | ~/.codex/config.toml |
TOML ([mcp_servers.name]) |
~/.codex/skills/ |
| OpenCode | ~/.config/opencode/opencode.json |
JSON (type: local, merged command+args) |
~/.config/opencode/agents/ |
Add one MCP server → update 3 files in 3 different formats. Miss one → tools out of sync.
This system solves that.
Claude Code (~/.claude.json) ← Source of Truth
│
├──► Codex (~/.codex/config.toml)
└──► OpenCode (~/.config/opencode/opencode.json)
A single 7-step sync protocol detects what changed and propagates it:
- MCP diff — new/removed servers → convert format → add to both tools
- Skill diff — new skills → adapt for Codex SKILL.md + OpenCode agents/
- Rule diff — rule changes → update AGENTS.md in both tools
- Agent diff — new agents → add to Codex config + OpenCode agents/
- Memory sync — MEMORY.md critical changes → SYSTEM MEMORY in both AGENTS.md
- OpenCode agent definitions — ensure opencode.json
agentsection complete - Report — how many MCPs, skills, rules, agents synced (Codex | OpenCode separately)
Claude Code: Codex:
────────────────────────────────────────────────────
"type": "stdio" → [mcp_servers.name]
"command": "cmd" → command = "cmd"
"args": ["a", "b"] → args = ["a", "b"]
"env": {"K": "V"} → [mcp_servers.name.env]
K = "V"
"type": "http", "url": "x" → url = "x"
Example:
// Claude Code (~/.claude.json)
"context7": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@upstash/context7-mcp@latest"]
}# Codex (~/.codex/config.toml)
[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp@latest"]Claude Code: OpenCode:
────────────────────────────────────────────────────
"type": "stdio" → "type": "local"
"command": "cmd" → "command": ["cmd", ...args] ← MERGED!
"args": ["a", "b"] → (args merged into command array)
"env": {"K": "V"} → "environment": {"K": "V"}
"type": "http", "url": "x" → "type": "remote", "url": "x"
Example:
// Claude Code (~/.claude.json)
"context7": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@upstash/context7-mcp@latest"]
}// OpenCode (~/.config/opencode/opencode.json)
"context7": {
"type": "local",
"command": ["npx", "-y", "@upstash/context7-mcp@latest"]
}Key difference: OpenCode merges
command+argsinto a single array. Also usesenvironment(notenv) for env vars.
- SKILL.md content stays mostly the same
- Replace
Skill toolreferences → keyword triggers - Replace
Agent tool/Task subagent→spawn_cc MCP tool or inline execution - Replace
ToolSearch→ direct tool name (Codex eager-loads all MCPs) - Copy
lessons/directory too
- Create
~/.config/opencode/agents/{name}.md - OpenCode agents:
description+ instructions format - Valid frontmatter fields:
name,description,model,temperature,mode - Do NOT include:
toolsas string,coloras name (use hex#RRGGBB),skillsarray - Add to
opencode.json→"agent"section
| Claude Code | Codex | OpenCode |
|---|---|---|
~/.claude.json → mcpServers |
~/.codex/config.toml → [mcp_servers.*] |
~/.config/opencode/opencode.json → "mcp" |
~/.claude/rules/*.md |
~/.codex/AGENTS.md (inline) |
~/.config/opencode/AGENTS.md + "instructions" |
~/.claude/skills/{name}/SKILL.md |
~/.codex/skills/{name}/SKILL.md |
~/.config/opencode/agents/{name}.md |
~/.claude/skills/{name}/lessons/ |
~/.codex/skills/{name}/lessons/ |
~/.config/opencode/agents/{name}-lessons/ |
~/.claude/agents/*.md |
~/.codex/config.toml → [agents.*] |
~/.config/opencode/agents/*.md |
~/.claude/projects/*/memory/MEMORY.md |
~/.codex/AGENTS.md → SYSTEM MEMORY |
~/.config/opencode/AGENTS.md → SYSTEM MEMORY |
Some MCPs should stay disabled across all three tools:
| MCP | Reason | Fix |
|---|---|---|
shadcn |
HTTP transport incompatible (returns text/plain) | Wait for SSE/stdio support |
huggingface |
Hardcodes port 3000 (conflicts with other services) | Set WEB_APP_PORT to unused port |
sentry |
Requires OAuth login | Run codex mcp login sentry |
figma (remote) |
Requires OAuth login | Run codex mcp login figma |
Mark these with enabled = false (Codex) or "enabled": false (OpenCode).
Copy SKILL.md to your Claude Code skills directory:
mkdir -p ~/.claude/skills/config-distro
cp SKILL.md ~/.claude/skills/config-distro/SKILL.mdThen trigger with any of:
config-distrodağıt/dagitsenkronize et/sync etcodex e de yap/opencode a da yaptooling sync
Run these checks to find what's out of sync:
# 1. MCP diff (Claude vs Codex)
diff \
<(python3 -c "import json; d=json.load(open(os.path.expanduser('~/.claude.json'))); print('\n'.join(sorted(d['mcpServers'].keys())))" 2>/dev/null) \
<(grep '^\[mcp_servers\.' ~/.codex/config.toml | sed 's/\[mcp_servers\.\(.*\)\]/\1/' | sort)
# 2. Skill diff (Claude vs Codex)
diff <(ls ~/.claude/skills/ | sort) <(ls ~/.codex/skills/ | sort)
# 3. Skill diff (Claude vs OpenCode)
diff \
<(ls ~/.claude/skills/ | sort) \
<(ls ~/.config/opencode/agents/ | sed 's/\.md$//' | sort)Valid fields for ~/.config/opencode/agents/*.md:
---
name: my-agent
description: What this agent does and when to use it.
model: provider/model-name # optional, inherits global default
temperature: 0.7 # optional
mode: subagent # optional
---Invalid fields that cause startup errors:
tools: "Read, Write, ..."→ must be a record:tools:\n write: falsecolor: yellow→ must be hex:color: "#EAB308"skills: [...]→ not supported in OpenCode
See examples/ for ready-to-use config snippets:
claude-mcp-entry.json— Claude Code MCP entry formatcodex-mcp-entry.toml— Codex equivalentopencode-mcp-entry.json— OpenCode equivalentopencode-agent.md— Minimal OpenCode agent template
Found a new format quirk? Open a PR with the conversion rule and an example.
MIT