Migrating between Codex, Cursor, and Claude Code
PLMigrating between Codex, Claude Code, and Cursor means moving three layers: instructions, MCP and skills, and permissions. The reliable pattern is one AGENTS.md as the only instruction source, each CLI’s built-in importer for MCP servers, commands and skills, and a parity run in which both agents execute the same closed ticket and are judged on the same tests.
Your team standardised on Codex last spring. Now half of them want Claude Code in the terminal, one squad lives in Cursor, and the first Claude Code session on the repo ignores the build commands that Codex always followed. Nobody knows which instruction file is authoritative, and the MCP token sits in three configs.
This guide is for developers who move a repository from one of these agents to another, or who add a second agent beside the first. It covers every direction. If you are a tech lead setting one standard for a whole team, read it, then continue with shared context and rules for a team. If you have not yet decided which agent should own which work, start with Codex compared with Claude Code and Cursor.
What you get from moving a repository between agents
Section titled “What you get from moving a repository between agents”- One
AGENTS.mdthat Codex reads natively, Claude Code imports with one line, and Cursor receives as a project rule. - The exact import commands both CLIs ship for the other tools’ configuration, and what each one misses.
- MCP servers written correctly in all three formats, with tokens read from the environment and never committed.
- A parity run: the same closed ticket executed by the old and the new agent, compared on tests, lint, and boundaries instead of on a line-by-line read.
- A failure-modes list for the migration traps that fail silently.
What changes when you switch agents?
Section titled “What changes when you switch agents?”The model is the smallest difference. The configuration surface is the larger one, and it is where migrations fail quietly.
| Layer | Claude Code (v2.1.283) | Codex CLI (0.157.1) | Cursor (3.x line, checked 2026-08-28) |
|---|---|---|---|
| Project instructions | CLAUDE.md; reads AGENTS.md only when there is no CLAUDE.md (v2.1.277+) | AGENTS.md (/init creates one) | AGENTS.md and CLAUDE.md in the project root and subdirectories (Cursor docs, checked 2026-10-12); Rules under .cursor/rules/ for Cursor-only rules |
| Import from other agents | claude import codex|cursor|gemini, or /import in a session | /import in the TUI (described as importing from Claude Code in 0.162.1, checked 2026-10-12; Cursor too, per the 0.145.0 release notes) | none verified |
| MCP config | .mcp.json (project) via claude mcp add | [mcp_servers.<name>] in ~/.codex/config.toml via codex mcp add | .cursor/mcp.json or ~/.cursor/mcp.json |
| Skills | .claude/skills/ | .agents/skills/ | .agents/skills/ (where npx skills add installs for Cursor, skills 1.7.0); Cursor also loads .cursor/skills/, .claude/skills/ and .codex/skills/ (Cursor docs, checked 2026-10-12) |
| Permissions | Permission modes; auto mode is the starting mode for interactive sessions from v2.1.283 (both channels) | Approval policy (-a) plus sandbox or permission profile | Run modes |
| Isolated parallel work | --worktree, --bg, /batch | --worktree, codex cloud (experimental), desktop app | Worktrees, Cloud Agents |
| Default model | Claude Opus 5.5 | GPT-6.1 Sol | no single default model; Hobby uses Auto (Cursor, checked 2026-10-12) |
Prices and the full model lineup live on the models hub. The rule for a migration is the same as for any model change: start on the new tool’s default model, tune effort before you switch model, and switch only when your own evals say so.
How to move a repository from one agent to another
Section titled “How to move a repository from one agent to another”-
Make
AGENTS.mdthe one source of instructions. Every tool either reads it or can be pointed at it, and it is the only format of the three that is an open standard. Pick your direction below. -
Run the importer, in dry-run mode first. Both CLIs ship one. It moves MCP servers, commands, and skills faster than you can by hand, and the dry run shows what it would overwrite.
-
Rewrite MCP servers in the target format and read every secret from the environment.
-
Map permissions and parallel work to the new tool’s model, so the agent is neither blocked on every command nor running unsandboxed.
-
Prove the migration with a parity run before you delete anything from the old setup.
Step 1: consolidate instructions into AGENTS.md
Section titled “Step 1: consolidate instructions into AGENTS.md”Rename CLAUDE.md so that Codex reads it, then give Claude Code a one-line pointer back:
# terminal, repository rootgit mv CLAUDE.md AGENTS.mdprintf '@AGENTS.md\n\n## Claude Code only\n' > CLAUDE.mdThe @AGENTS.md line is a native import. It works on every release channel and in repositories that keep both files. Claude Code’s own fallback does not: when a CLAUDE.md exists, Claude Code reads only that file. Put anything that is truly Claude-specific, such as a note about a hook or a subagent, under the Claude Code only heading.
Keep AGENTS.md where it is. Add a CLAUDE.md that imports it, so the file works on every version, including builds older than v2.1.277:
# terminal, repository rootprintf '@AGENTS.md\n' > CLAUDE.mdCursor needs no generated rule: it reads AGENTS.md in the project root and in subdirectories, and reads CLAUDE.md the same way, always applied (Cursor’s rules docs and help, checked 2026-10-12). A Rules copy of the same text would repeat what Cursor already reads, so keep .cursor/rules/ for rules that only Cursor needs. If you still want a tool to generate per-tool files, the trade-offs between rulesync, Ruler, and a plain @AGENTS.md import are on one rules source for every agent.
Cursor keeps its instructions in several rule files. Merge them into one AGENTS.md with the prompt below, then add the @AGENTS.md pointer for Claude Code. Keep the Cursor rules until the parity run passes, and then delete the ones whose content now lives in AGENTS.md: Cursor reads AGENTS.md directly (Cursor’s rules docs, checked 2026-10-12), so a rule that repeats it only duplicates it. Keep a .cursor/rules/ file only for rules that are specific to Cursor.
# terminal, repository root, after the agent has written AGENTS.mdprintf '@AGENTS.md\n' > CLAUDE.mdIn a monorepo, repeat the pattern in every directory that has its own instructions: a packages/api/AGENTS.md with the content, and a packages/api/CLAUDE.md that contains only @AGENTS.md.
Step 2: run the importer, and read the dry run
Section titled “Step 2: run the importer, and read the dry run”Both CLIs import the other tools’ configuration. Neither import is a full migration, so run the dry run first and treat the output as a checklist.
claude import codex --dry-run # or: claude import cursor --dry-runclaude import codex # opens a picker; choose what to bring overPer Anthropic’s commands reference (checked 2026-09-26), /import brings in instruction files, MCP servers, commands, subagents, and skills. Because it can bring instruction files, run it after Step 1 and check that it did not recreate a second copy of your rules in CLAUDE.md.
Start codex in the repository and run /import. In 0.157.1 it offers to “import setup, this project, and recent chats from Claude Code”, and the 0.162.1 command description reads the same (checked 2026-10-12). Neither names Cursor. Per the 0.145.0 and 0.147.0 release notes (checked 2026-09-26), the import also covers Cursor: settings, MCP servers, plugins, sessions, commands, and Cursor-managed skills. Run it and read what it offers before you rely on that.
Trust the project when Codex asks. Since 0.150.0, untrusted projects do not supply project-level AGENTS.md, so an untrusted checkout runs with none of your instructions.
Neither CLI exports to Cursor, and no Cursor importer could be verified on 2026-09-26. Cursor reads AGENTS.md directly (Step 1, Codex tab), so write only .cursor/mcp.json by hand (Step 3) and install skills with the skills CLI (below).
Skills move with the Agent Skills standard: a SKILL.md folder works in all three tools, only the directory differs. npx skills add <owner/repo> (npm skills 1.7.0) installs into each agent it detects. Plugins do not move: Claude Code plugins, Codex plugins, and Cursor plugins come from different marketplaces, so reinstall the equivalent in the new tool.
Step 3: rewrite MCP servers in the target format
Section titled “Step 3: rewrite MCP servers in the target format”The servers are the same; only the wrapper changes. The example below uses two official remote servers: the GitHub MCP server and Context7. The GitHub server reads its token from GITHUB_PAT in your shell, never from a committed file; Context7 needs none.
# writes .mcp.json, which is safe to commit because it holds only a variable referenceclaude mcp add --scope project --transport http context7 https://mcp.context7.com/mcpclaude mcp add --scope project --transport http github https://api.githubcopilot.com/mcp/ \ -H 'Authorization: Bearer ${GITHUB_PAT}'claude mcp listThe single quotes keep ${GITHUB_PAT} literal. Claude Code expands it from the environment each time the server starts.
codex mcp add context7 --url https://mcp.context7.com/mcpcodex mcp add github --url https://api.githubcopilot.com/mcp/ --bearer-token-env-var GITHUB_PATcodex mcp listThis writes the following to ~/.codex/config.toml (tested on 0.157.1):
[mcp_servers.context7]url = "https://mcp.context7.com/mcp"
[mcp_servers.github]url = "https://api.githubcopilot.com/mcp/"bearer_token_env_var = "GITHUB_PAT"Do not copy a JSON headers object into TOML. Codex parses headers = { … } without an error and drops it. The header keys it reads are bearer_token_env_var, http_headers, env_http_headers, and http_headers_helper (as listed by codex mcp get in 0.157.1).
{ "mcpServers": { "context7": { "url": "https://mcp.context7.com/mcp" }, "github": { "url": "https://api.githubcopilot.com/mcp/", "headers": { "Authorization": "Bearer ${env:GITHUB_PAT}" } } }}Save it as .cursor/mcp.json. The ${env:NAME} interpolation comes from Cursor’s MCP docs as quoted in our research, not from a fetch on 2026-09-26, so check it on your version before you commit the file.
One protocol difference survives the translation. Claude Code negotiates the 2026-07-28 MCP specification with direct HTTP servers by default. Codex 0.157.1–0.162.1 does not (its mcp_2026_07_28 feature is still under development and off, checked 2026-10-12), so a server can behave differently in the two tools even with an identical entry.
Step 4: map permissions and parallel work
Section titled “Step 4: map permissions and parallel work”The habit that breaks most often is autonomy. An agent that was allowed to run your tests in the old tool stops and asks in the new one, or the reverse: a flag copied from a blog post turns the sandbox off.
| You relied on | Claude Code | Codex | Cursor |
|---|---|---|---|
| Edit files, gate risky commands | Auto mode (the starting mode for interactive sessions from v2.1.283); --permission-mode acceptEdits for edits-only autonomy | -a on-request (the default) with --sandbox workspace-write; to let a reviewer model decide instead of you, --approve-for-me | Run modes: Auto-review, Allowlist and Run Everything, under Settings > Agents > Approvals & Execution (Cursor docs, checked 2026-10-12) |
| Headless run in a script | claude -p (starts in Manual, or in auto mode on third-party providers or with telemetry off from v2.1.285; allow tools with --allowedTools) | codex exec (put -a before exec: codex -a never exec …) | Cursor CLI print mode (-p) (per Cursor’s headless docs, checked 2026-08-28) |
| Isolated parallel sessions | claude --worktree or --bg | codex --worktree, or Codex cloud | Worktrees or Cloud Agents |
Two corrections to advice you may have followed. First, codex "prompt" starts an interactive local session in your current checkout, not a cloud sandbox. Five of them in five terminals edit the same files unless each runs with --worktree. Second, codex --full-auto does not exist in 0.157.1; use --approve-for-me or a permission profile. Keep --dangerously-skip-permissions and --dangerously-bypass-approvals-and-sandbox for disposable, network-restricted sandboxes only. The full model for each tool is on permissions and sandboxing for agents.
How do you prove the migration worked without reading every diff?
Section titled “How do you prove the migration worked without reading every diff?”Run one closed ticket through both agents from the same commit, and let the repository’s own gates decide. Pick a ticket with a merged fix and a test that failed before it. That test is your oracle: it is the part neither agent is allowed to change.
# terminal: two isolated checkouts of the commit before the fixgit worktree add ../parity-old BASE_SHAgit worktree add ../parity-new BASE_SHA# dependencies are installed before either agent starts(cd ../parity-old && npm ci) && (cd ../parity-new && npm ci)
# copy the oracle test from the fix commit into both checkouts and commit it therefor d in ../parity-old ../parity-new; do git -C "$d" checkout FIX_SHA -- path/to/oracle.test.ts git -C "$d" commit -qm "oracle test" # record the oracle commit; the gate diffs against it, so an agent's own commits are still checked git -C "$d" tag "oracle-$(basename "$d")"done# the oracle must fail before either agent runs(cd ../parity-old && npx vitest run path/to/oracle.test.ts) && echo "ORACLE PASSES AT BASE: pick another ticket"
# old tool (Codex here), headless, sandboxed to the workspace, transcript kept(cd ../parity-old && codex exec --json --sandbox workspace-write "$(cat ../parity-task.md)" > ../run-old.jsonl)
# new tool (Claude Code here), headless, edits allowed, the same commands AGENTS.md lists(cd ../parity-new && claude -p "$(cat ../parity-task.md)" --permission-mode acceptEdits \ --allowedTools "Bash(npm test *)" "Bash(npm run *)" \ --output-format stream-json --verbose > ../run-new.jsonl)
# the gate, identical for bothfor d in ../parity-old ../parity-new; do base="oracle-$(basename "$d")" (cd "$d" && git add -A \ && git diff --cached --quiet "$base" -- path/to/oracle.test.ts \ ':(glob)**/*.test.*' ':(glob)**/*.spec.*' 'test/**' 'tests/**' \ && npm test && npm run lint && git diff --cached --stat "$base") || echo "FAILED: $d"done
# did each agent run the commands AGENTS.md lists?for f in ../run-old.jsonl ../run-new.jsonl; do grep -q 'npm test' "$f" && grep -q 'npm run lint' "$f" || echo "MISSING COMMANDS: $f"doneReplace FIX_SHA with the merged fix and BASE_SHA with its parent. The oracle test comes from the fix commit, so it does not exist at BASE_SHA: copy it in before the agents start and confirm that it fails there, or npm test can pass without the ticket being solved. Swap npx vitest run for your own single-test command, list every test location your repository uses in the gate’s pathspec (co-located tests, snapshot folders, fixtures), adjust the command list to what your AGENTS.md names, and put the ticket text, its acceptance criteria, and “do not edit the test files” in parity-task.md. Before you run anything, confirm that Codex sees your MCP entries with codex mcp list, and that it recognises every key with codex --strict-config exec "Reply OK" (it names any unknown key; --strict-config does not work with codex mcp, checked on 0.157.1).
Both checkouts must be trusted projects for Codex, or it ignores AGENTS.md there, and codex exec cannot show the trust prompt. Trust them first: run codex interactively once in each worktree and accept the prompt, or add both absolute paths to ~/.codex/config.toml (key format checked on 0.157.1):
[projects."/abs/path/to/parity-old"]trust_level = "trusted"
[projects."/abs/path/to/parity-new"]trust_level = "trusted"Then add Before you start, list the instruction files you loaded. to parity-task.md and reject a run that reports none.
The migration passes when the gate prints neither FAILED nor MISSING COMMANDS: both runs are green on the same tests, neither agent modified a test file, and both transcripts show the commands AGENTS.md lists. The grep also matches a command the agent only read, so open the transcript when a run looks suspiciously quick. Then check the staged diff stat against your Boundaries section. Claude Code gets Bash(npm test *) and Bash(npm run *) so it can run every command AGENTS.md lists; add any other command your AGENTS.md names, or the comparison favours Codex, which may run anything inside its workspace sandbox. You sign off on that evidence, not on the diff. If you want a second opinion on the two diffs, use the prompt below.
Run the parity task in both directions whenever you change AGENTS.md substantially. The cheapest guard against drift afterwards is a CI step that fails when CLAUDE.md stops importing the shared file:
# CI stepgrep -qx '@AGENTS.md' CLAUDE.md || { echo "CLAUDE.md must import AGENTS.md"; exit 1; }What breaks when you move a repository between Codex, Claude Code, and Cursor?
Section titled “What breaks when you move a repository between Codex, Claude Code, and Cursor?”Claude Code ignores AGENTS.md. The repository has a CLAUDE.md (so the fallback never fires), the teammate’s build is older than v2.1.277, or the toggle under Project instructions in /config is off. Recovery: make @AGENTS.md the first line of CLAUDE.md. That works in all three cases.
Codex runs as if there were no instructions. The project is untrusted, and since 0.150.0 an untrusted project supplies no project-level AGENTS.md. Recovery: trust the project when Codex prompts, then ask it which instruction files it loaded.
An MCP server loses its token in Codex only. A JSON headers object was pasted into config.toml, and Codex dropped it without an error. Recovery: re-add the server with --bearer-token-env-var, and run codex --strict-config exec "Reply OK" to catch other unknown keys.
A server works in Claude Code but misbehaves in Codex. The two negotiate different MCP protocol versions. Recovery: test the server in Codex specifically, and check its README for a pre-2026-07-28 compatibility note.
The importer doubled your rules. claude import or Codex /import wrote a second copy of instructions you had already merged. Recovery: run the dry run first, delete the duplicate, and keep AGENTS.md as the only file with content.
A token ended up in git. Someone replaced ${GITHUB_PAT} with the literal value while debugging. Recovery: revoke and rotate the token first, then remove it from history. Rewriting history alone does not protect a token that has already been pushed.
Results got worse after the switch. The prompts and AGENTS.md were tuned for the old model. Recovery: do not change the model first. Raise effort on the default model, rerun the parity task, and change the instruction that the comparison prompt points to.
Parallel sessions overwrote each other. Several sessions ran in one checkout. Recovery: give each session its own worktree (--worktree in both CLIs, Worktrees in Cursor) and merge through pull requests.