← BlogGuides

How to split work between Claude Code, Codex and Cursor

How to split work between Claude Code, Codex and Cursor: a division of labour that holds up, and where the shared state lives since none of them reads the others.

The Taskfolk team

11 min read9 views

XLinkedIn

Two migration files, same table, same new column, both sitting in one pull request. Claude Code wrote the first at 11:40. Codex wrote the second at 11:52, from a branch that had never heard of it. Neither agent did anything wrong. Neither had any way to find out about the other.

A July 2026 paper put a number on that. The authors replayed three way git merges on 747 pairs of concurrently open, agent authored pull requests, one pair per repository, drawn from a dataset of 33,596 agent PRs across 2,807 repos. Pairs written by two different agents hit textual conflicts 41.7 percent of the time. Pairs where the same agent ran twice hit 19.8 percent, with non overlapping 95 percent confidence intervals. Source files, not lockfiles, were 84.4 percent of the conflicted files (Xu, Subramanian and Karthik, arXiv:2607.04697).

The caveat is the interesting half. Cross agent pairs were only 0.5 percent of the co-active pairs they found, in 122 of 2,807 repositories. Almost nobody is running two vendors' agents into one repo at the same time yet. If you are reading this, you are in that 4.3 percent, and roughly double the conflict rate is your baseline.

I work on Taskfolk, so discount the product sections accordingly. The first half is vendor documentation you can go and check.

Three subscriptions is ordinary, the transport cost is not

Most people asking how to split work between these tools are really asking whether paying for three is stupid. The adoption data says it is normal. Digital Applied surveyed 2,847 developers at 320 agencies and in-house teams between January and March 2026. Primary tool share came out at Claude Code 28 percent, Cursor 24, GitHub Copilot 17, Codex 11.

The column worth reading is any-use: Copilot 58 percent, Claude Code 54, Cursor 49, Codex 31. Those sum to well over 100 because most respondents named at least two more tools in a supporting role. It is an agency's own marketing research rather than a peer reviewed study, so treat the decimals as directional and the shape as real.

The second and third subscription is cheap next to the actual cost, which is that you have become the transport layer between them. You explain a decision to Claude Code, explain it again to Cursor, paste the acceptance criteria into Codex. Every one of those is you carrying state by hand because nothing else will.

The Taskfolk agents hub showing a workspace member directory with several connected AI agents listed alongside human members, each row carrying a provider badge, an owner, and a session count.

What each tool actually stores, and where

Instructions and memory get discussed as one thing. They are two, and the difference decides what you can share. Every row below comes from the vendor's own docs, read on 26 July 2026. Check the dates on any table like this, including this one.

Claude Code Codex Cursor
Instruction file CLAUDE.md, .claude/CLAUDE.md, ~/.claude/CLAUDE.md, plus a managed policy path AGENTS.override.md then AGENTS.md, from ~/.codex and the git root down .cursor/rules/*.mdc, plus AGENTS.md in the root and subdirectories
Reads the others? No. The docs say flatly that it reads CLAUDE.md, not AGENTS.md No CLAUDE.md by default, though fallback filenames are configurable Yes for AGENTS.md; the CLI docs add CLAUDE.md at project root
Merge rule Discovered files concatenated root to cwd, closest last, @path imports to a depth of four Concatenated root to cwd, closer overrides, combined size capped at 32 KiB Team rules, then project rules, then user rules, all merged, earlier source wins
The trap Past roughly 200 lines adherence drops, and it is context, not enforcement Hit the 32 KiB ceiling and it simply stops adding files A plain .md in .cursor/rules is ignored because it has no frontmatter
Auto memory ~/.claude/projects/<project>/memory/, first 200 lines or 25 KB per session, machine local Not documented as a feature Per project and per person, generated in the background, managed in settings
Session store JSONL under ~/.claude/projects/, format internal and version dependent Rollout JSONL under ~/.codex/sessions/, community verified rather than documented Not documented; --resume and session listing exist

Two things follow. Instructions really are converging: all three read a plain markdown file, AGENTS.md is winning the naming fight, and one symlink or a single @AGENTS.md import line gives you one instruction file that all three load. Claude Code's own docs tell you to do exactly that. Call it solved.

Memory and session state are not converging, and were never designed to. Claude Code's memory page says auto memory is machine local and the files are "not shared across machines or cloud environments". Cursor keeps its rules as .mdc files with frontmatter and its memories per project, per person, behind your settings. Codex writes rollout files whose shape it does not publish. Nobody is building a bridge between them, because none of the three has a reason to.

flowchart LR
  A["Claude Code"] --> A1["CLAUDE.md and local auto memory"]
  B["Codex"] --> B1["AGENTS.md and rollout files"]
  C["Cursor"] --> C1["mdc rules and per project memories"]
  A --> T["The work record"]
  B --> T
  C --> T

So the only state all three can read and write is state you keep somewhere else. For most teams that place already exists, and it is the tracker.

A split that survives Tuesday afternoon

Here is the division of labour nearly everyone converges on. I do not think it is wrong. I think it is the least interesting part of the problem.

Stage Usually best Why
Write Claude Code Long autonomous multi-file runs, plus first-party worktree isolation
Review Codex, or a second Claude Code session A second opinion is only worth having if it did not write the code
Polish Cursor Tight edit loop with a human watching the diff land

As an intention, that table is worth nothing. On Tuesday afternoon you will hand the reviewer agent a half finished feature because it was the terminal already open. The split becomes real when it is a column on a board and a permission on a key.

Columns first. Give the project one status per stage, named for the work rather than the tool (Building, In review, Polishing), then decide which moves are legal. In Taskfolk the allowed transition list is the enforced control: a move that is not on the list returns an error from every write path, REST and MCP included.

The work in progress number is not enforced. The board renders the count against the limit and highlights the column when it goes over, and that is the whole behaviour. Any post telling you a WIP limit will refuse a card is guessing.

The board statuses tab in Taskfolk project settings, showing custom workflow columns with their category mapping and colour, and the controls for reordering them and setting allowed transitions.

Now the handoff is a status change instead of a paste. The writer sets In review and stops. The reviewer finds a ticket in its column with a pull request link on it, and the ticket carries the decisions, so nobody re-explains anything. Two agents, one backlog works through the columns as protocol argument in more depth.

None of it survives a bad ticket. A column cannot rescue a one line description, and the fields that decide whether an agent finishes or flails are a separate subject: how to write a ticket an AI agent can actually finish.

Three identities, and what each may write

A shared backlog for AI coding agents covers the roster mechanics generally, so this section is only the part that changes when the three agents come from three vendors.

Connect each one separately instead of sharing a key. Connecting mints an API key whose creator is that agent's own user record, which is what puts the right name on activity, comments and assignment history. Three keys is bookkeeping. Three attributions is the point: when the reviewer disagrees with the writer, you want that argument sitting on the ticket with two names on it.

A reviewer that can write every field will eventually reassign its own ticket to itself and close it. Stopping that takes two controls rather than one. Set the field policy allowlist to the fields review actually needs, and leave assignee out of it:

{
  "field_policy": ["status", "labels"]
}

Then grant that key the comments:write scope so it can still report what it found. Comments are governed by scopes, not by the field allowlist, which is why one control is not enough. The allowlist is also per field and not per value: you can say this agent may write status, or may not write status. You cannot say it may only set status to In review. I would like that too.

The agent field permissions dialog in Taskfolk, showing the fourteen issue field toggles with only a few enabled, so the agent can write those fields and nothing else.

How to set agent field permissions is the walkthrough. The same allowlist is your main blast radius control when a ticket contains text you did not write, which is its own post.

How the second agent finds out

The writer finishes at 02:14. The reviewer is a process on a machine somewhere, and nothing tells it anything. This is the gap that kills most homegrown multi agent setups, and the usual advice about it is wrong.

Polling is fine. The argument that polling is expensive does not survive arithmetic: a Taskfolk key allows 600 requests a minute by default, and a ten second poll spends six of them. What polling actually costs is latency and visibility. The queue exists only inside whatever loop you wrote, so nobody else can inspect it, and nothing replays the hours your laptop spent asleep.

The alternative is one long lived Server-Sent-Events connection per agent, opened with that agent's own key.

curl -N "https://taskfolk.ai/api/v1/workspaces/acme/agent-events?since=2026-07-26T02:00:00Z" \
  -H "Authorization: Bearer tfk_live_a1b2..."
import httpx

url = "https://taskfolk.ai/api/v1/workspaces/acme/agent-events"
params = {"since": "2026-07-26T02:00:00Z"}
headers = {"Authorization": "Bearer tfk_live_a1b2..."}

with httpx.stream("GET", url, params=params, headers=headers) as r:
    for line in r.iter_lines():
        if line.startswith("data: "):
            handle(line[6:])
: connected
data: {"type":"ready"}
data: {"type":"issue.assigned","issue_key":"APP-14","at":"2026-07-26T02:14:52Z"}
: ping

The endpoint needs the agents:read scope; a human key gets a 400 telling you to use the agent's key instead. Five event types arrive on it: issue.assigned, comment.mention, session.updated, automation.notify and chat.message. Payloads carry pointers plus an excerpt clamped to 240 characters, never full content, and a heartbeat every 25 seconds makes a dead connection obvious.

since is the parameter that matters overnight. It replays missed events out of the source tables, clamped to a 24 hour window, so the laptop that slept through the night reconnects and catches up instead of losing the assignment.

Two things then happen without the agent doing anything. Assigning an issue to an agent creates a pending session immediately, so tomorrow morning's queue is visible tonight, and a run that stops sending heartbeats reads as stalled after 30 minutes rather than quietly hanging. Separately, the notify_agent automation action wakes an agent straight from a rule: it publishes an automation.notify event on that agent's stream and touches nothing on the issue.

The agent sessions list in Taskfolk showing sessions in different states with their issue, agent, duration and status, including a pending session created by assignment.

One feature crossing three agents, end to end. Taskfolk delivers the trigger and keeps the record; each agent's own runtime does the work, on your machine or in your CI.

sequenceDiagram
  participant Human
  participant Board
  participant Writer
  participant Reviewer
  Human->>Board: assign APP 14 to Writer
  Board->>Board: create pending session
  Board-->>Writer: issue.assigned
  Writer->>Board: claim session, status Building
  Writer->>Board: status In review, attach PR link
  Board-->>Reviewer: issue.assigned
  Reviewer->>Board: comment findings, status Polishing

All three agents call the same tool catalogue, because the MCP tools are generated from the REST specification rather than maintained next to it. Claude Code task management and Cursor task management cover the per tool setup.

What a shared board still cannot do

We do not sync anyone's memory, rules file or context window. Nothing in Taskfolk writes to your CLAUDE.md, your AGENTS.md or your .cursor/rules. If a post from us ever says otherwise, it is wrong.

We also do not run your agents. The stream delivers triggers, the session row stores what happened, the runtime stays yours.

The installable skill bundle generates MCP client configs for Claude Desktop, Cursor and VS Code, and no Codex config. Until that changes, write the TOML by hand:

# ~/.codex/config.toml
[mcp_servers.taskfolk]
url = "https://taskfolk.ai/api/mcp/v1"
bearer_token_env_var = "TASKFOLK_API_KEY"

Claude Code takes the same endpoint from the command line. The --transport http flag is not optional there; a JSON entry with a url and no transport is a configuration error, and the failure message it produces does not say so.

claude mcp add --transport http taskfolk https://taskfolk.ai/api/mcp/v1 \
  --header "Authorization: Bearer $TASKFOLK_API_KEY"

The biggest limit is the one the arXiv number was really about. No board stops two agents editing the same file. That is a git problem, and Anthropic already shipped an answer: claude --worktree <name> creates an isolated checkout under .claude/worktrees/ on its own branch, a custom subagent can carry isolation: worktree in its frontmatter, and a .worktreeinclude file copies gitignored files like .env into every new one.

Worktrees keep the files apart. The board keeps the work apart. You need both, and a tracker claiming to solve the first one is selling you something.

If you already run two of these, the smallest useful change is one review column on one project, transitions set so nothing can jump straight to done, and one agent connected to sit in it. Everything else here is an argument about what to do once that column starts earning its keep.

Frequently asked questions

Can two AI agents work on the same repository at the same time?

Yes, but file isolation is a git problem rather than a tracker problem. Give each agent its own worktree (Claude Code ships claude --worktree <name> for exactly this) so their edits never touch the same checkout, and use the board to stop them picking up overlapping work in the first place.

Does Taskfolk sync memory or rules between Claude Code and Cursor?

No, and nothing else does either. Each vendor's memory and session store is local, per project, and format-unstable by design. Taskfolk holds the work record all three can read and write over the API; your CLAUDE.md, AGENTS.md and .cursor/rules stay yours.

How does an agent find out a ticket was assigned to it?

It holds one Server-Sent-Events connection at GET /api/v1/workspaces/{slug}/agent-events with its own key and receives an issue.assigned event. Reconnecting with ?since= replays anything missed in the last 24 hours, so an agent that was offline overnight still gets the assignment.

Should each AI agent have its own API key?

Yes. Connecting an agent mints a key whose creator is that agent's own user record, so activity, comments and assignment history carry its name instead of yours. Sharing one key across three agents collapses all three into a single identity in the audit trail.

What stops a reviewer agent from reassigning its own ticket?

A field policy allowlist that includes status and labels but leaves out assignee, plus the comments:write scope so it can still report what it found. The allowlist is per field rather than per value, so it cannot restrict which status the agent picks.

Related reading

Add a comment

Start the conversation.