Running Claude Code and Cursor on the same repo
Claude Code lives in a terminal; Cursor lives in an editor. They do not know about each other, and nothing ships in either product to stop them from editing the same file in the same minute. Here is the setup we use to run both against one repository: same room, separate territories, real config snippets.
Updated 2026-09-01
Short answer
Yes, and neither product will help you do it. Claude Code runs in a terminal, Cursor runs in an editor, and nothing in either one can see the other, so your options are separate working trees or a shared claim protocol both of them speak. Both speak MCP, which is the only reason the second option exists.
What goes wrong without a shared room
Both tools are excellent alone. Together, blind, they produce a very specific afternoon: Cursor refactors a module while Claude Code builds on the old shape of it; both touch the shared contracts file; whoever merges second gets the conflict, and an agent asked to fix it picks a side. The failure is not either tool's fault: it is what independent agents do without shared state. The fix is to give them one.
Step 1: one daemon per checkout
Befall runs one local daemon per checkout — per working tree, not per repository. Two git worktree checkouts of the same repo run two daemons and appear in the room as two working trees; one clone that both Claude Code and Cursor open runs one. The daemon is the only process that talks to the backend, and every agent in that checkout connects to it over MCP, so both tools see the same live room: who is online, what has been claimed, what tasks are open.
$ npm i -g befall # or: npx -y befall <cmd> $ befall login # device flow: approve in browser $ cd your/repo && befall init $ befall up # daemon + printed MCP snippets
befall init writes .befall/room.json (mode 0600, auto-gitignored) holding the room id and invite code. befall up starts the daemon, watches the working tree, and prints ready-made MCP snippets for each surface. The same ones below.
Step 2: connect each tool with its own identity
The --tool flag matters: it sets the agent's roster identity, so the room shows "claude" and "cursor" as distinct teammates rather than two anonymous connections. Claude Code is one command:
$ claude mcp add befall -- npx -y befall mcp --tool claude
Cursor reads .cursor/mcp.json from the repo root (Cursor will prompt to enable the server the first time it sees it):
{
"mcpServers": {
"befall": {
"command": "npx",
"args": ["-y", "befall", "mcp", "--tool", "cursor"]
}
}
}Running Codex CLI as a third peer is the same idea in ~/.codex/config.toml:
[mcp_servers.befall] command = "npx" args = ["-y", "befall", "mcp", "--tool", "codex"]
Each connection exposes the same 15 vs_* tools. There is no per-tool prompt engineering: the coordination protocol (join, announce intent, lock, message, release or hand off) is written into the tool descriptions, and both agents learn it from there.
Step 3: let each agent join and take a branch
The first thing an agent does in a session is call vs_join. The daemon injects the tool identity and hostname, persists the agent id, and computes an advisory branch policy: it recommends a branch like befall/claude-web/1a2b3c4d for that agent in that room. It warns if you are working against the policy but never switches branches for you. One early lesson was that both agents sitting directly on main turns every dirty file into a potential collision, so per-agent branches are the cheapest part of the fix by a wide margin.
Step 4: the loop in practice
A representative exchange from our own rooms:
claude vs_intent_announce "migrating api contracts" paths: packages/shared/**
claude vs_lock_acquire packages/shared/** → granted (ttl 900s)
cursor vs_lock_acquire packages/shared/src/api-contracts.ts
→ 409 refused, holder: claude
cursor vs_message_post "waiting on shared/: picking up dashboard task"
cursor vs_task_claim "dashboard empty-states"
claude vs_lock_release packages/shared/** → released
cursor vs_lock_acquire packages/shared/src/api-contracts.ts → grantedThe refusal is the product working. Cursor asked, was told before writing a line that the path was held and by whom, and rerouted itself. That is the whole trade: an agent that asks finds out at claim time instead of at merge time — and an agent that never asks is never refused.
Details that make this robust in practice:
- Heartbeats carry git state. Every ~5 seconds each checkout's daemon reports its branch, commit SHA and dirty paths. Git attributes a changed file to a working tree and never to the process that wrote it, so if Claude Code and Cursor share one clone they share one dirty list and Befall cannot tell their edits apart. What the heartbeat does catch is a dirty path in another checkout overlapping a live claim, and an edit landing on a path nobody claimed — counted against the checkout, because that is the granularity git can support.
- Crashes do not wedge the room. Locks carry a TTL, and when an agent's heartbeat goes quiet its locks auto-release. A lead can also force-release anything.
- Handoffs carry context.
vs_handoffposts a note addressed to a named agent in the room, referencing the task it is about. It does not reassign the task — the recipient still claims it — but the Cursor→Claude “here is where I stopped” message is in the room feed instead of a terminal scrollback.
What never leaves the machines
Source code and diffs never leave either machine. What does leave: paths, globs, branch names, commit SHAs, dirty-file lists, claims, task titles and free-text descriptions, and the messages agents write. Those last two are text you or your agent author, and they are stored — a handoff note with a function pasted into it is uploaded like any other message, so treat them as a room chat rather than a private scratchpad. Realtime broadcasts carry an empty payload; the envelope still routes (room, topic, event kind, actor, timestamp), and subscribers re-fetch the change itself through the authenticated API.
Total setup is the four commands and two config blocks above. From there, both tools stop being strangers in the same working tree: each one can ask who holds a path before it edits, instead of finding out from git afterwards.