One Task, One Session: The Parallel Agent Field Manual
A 9-minute documentary and a field manual for running Claude Code and Codex in parallel: when to stay, clear, branch, fork or spin off, when you need a worktree, what it costs, and how to make the agents do it for you.
You open a project, give the agent a task, go a few rounds of feedback, and then type the sentence that breaks everything: "also do this in parallel." From there, either one chat collects four tasks, or four chats share one folder, one git index and one branch, and soon you cannot tell which instructions still apply or whose changes are about to land in your commit. The film above is the fast version. This is the manual.
| 👉 | Start here: two tasks at once, step by step 1. Start one agent. Open a terminal tab in your project, type 2. New task, new tab. Press ⌘T, start another agent in the same folder and give it the second task there. Never type task two into task one's tab. You decide when a tab opens and when it closes. 3. Steer each task in its tab. Click a tab, or move with ⇧⌘[ and ⇧⌘]. iTerm2's Claude Code integration (iTerm2 menu, Install Claude Code Integration) shows each Claude session as working, waiting or idle, with a colored dot on its tab, and Claude Code sends a desktop notification when a task finishes or stops at a permission prompt while you are away. 4. Keep parallel tabs on different things. Tabs in one folder share the files and the git state. The rules below cover the git side, and in my setup, when one tab's agent tries to edit a file that another open tab has changed but not committed, a guard holds the edit and names that tab. Want a task completely separate? Add "in a worktree" to its first message: the agent works in its own copy of the repository, and the copy is cleaned up once the work has landed (step by step below). 5. Close the tab when you are happy (⌘W). In my setup there is nothing to do first: each agent commits only its own files and delivers finished work (pushed, or in a pull request) before it says it is done, unfinished work stays where it is, and a worktree is removed once its work has landed. The next task gets a new tab, so you never need One tab per task is the whole workflow. Boris Cherny, who created Claude Code, also runs parallel tabs with notifications: "I run 5 Claudes in parallel in my terminal. I number my tabs 1-5, and use system notifications to know when a Claude needs input." |
| ⚡ | TL;DR One task, one session. Feedback stays in the session. A new goal gets a fresh context: a new tab, or Two isolations. Sessions isolate what the model sees. Checkouts isolate what it writes. Solve them separately. Side questions go sideways. A shared folder needs rules. Commit only your own files by name, never stash, reset, clean or switch branches there, and merge when a push bounces. Overlap gets a worktree. Same files, a branch or a long unattended run. Just say "in a worktree" (or launch with Clean sessions waste less; parallel sessions still add up. Every request re-sends the current context. Caching makes that cheaper, not free. Make it automatic. One rules file every session reads at startup, and hooks that track sessions, catch common risky git commands, hold a file another session is editing and sweep up landed worktrees. |
Two ways it goes wrong
The kitchen sink. One session, every task. The spec you pasted first, the feedback, the side question, the second task and four hundred lines of test output all sit in the same context window, and every request carries all of it again. Old decisions compete with new ones. When the window fills, the tool compacts the history into a summary, and a summary keeps the gist, not every detail. Anthropic's best-practices page has a name for this, the kitchen sink session, and a one-line diagnosis: "Context is full of irrelevant information."
The free-for-all. So you open more sessions. Good instinct, dangerous without rules, because sessions in one folder share the working files, the git index and the branch. A git add -A sweeps another agent's half-finished files into your commit. A git stash yanks work you never saw out of the folder, and git reset --hard destroys it. One agent switches branches and the other agent's files change under it. Two dev servers fight for one port. And separate copies don't save you when the work overlaps: Nicholas Carlini at Anthropic gave each parallel agent its own clone of one repository, and on a single shared job they still collided. "Every agent would hit the same bug, fix that bug, and then overwrite each other's changes."
Parallel is not the problem. Shared state is.
Separate the two problems
Context is what the model sees on every request. Sessions isolate it: a fresh session, a branch of the conversation, a subagent with its own window.
Workspace is the files and git state the agent writes. A shared folder leaves all of it shared; a git worktree or a cloud sandbox gives a session its own files, index and HEAD.
Most advice mixes the two. Keep them apart and the decisions get simple. And keep the human part simple too. The best version of this has three layers: things that happen automatically, things you ask for in plain words ("clean up the worktrees"), and native keystrokes for when you want direct control.
What to use when
Use the lowest rung that works.
Keep the number of sessions you actively steer small. Simon Willison: "the natural bottleneck on all of this is how fast I can review the results." Addy Osmani: "Don't run more agents than you can meaningfully review. 3-5 is the sweet spot."
The command map
Checked against Claude Code 2.1.296 and Codex CLI 0.162.1.
Mind the naming trap: Claude Code's /branch is what Codex calls /fork, while Claude Code's /fork copies the conversation into a separate background session and leaves you working in the original.
Talking to a busy agent
Why does a message you type sometimes land instantly and sometimes wait? In Claude Code, Enter queues it, and Claude Code passes it to Claude "as soon as those tool calls finish, within the same turn." If a single command runs for two minutes, your message waits two minutes. On a Mac terminal the keys are Control keys: Ctrl+X then Ctrl+S sends what you queued right now (Ctrl+Enter does the same only where the terminal reports extended keys), Esc interrupts the turn, and the up arrow takes queued text back so you can edit it. Esc is not a cancel button for the queue: it interrupts without sending your draft, and Claude Code sends what you already queued right away. Slash commands you queue wait for the end of the turn; a few, like /status and /usage, run immediately.
For a quick question while it works, /btw answers from what is already in the conversation, with no tools and nothing added to the history. That also means it cannot open a file to check: a side answer is not an investigation.
Codex flips the default. Enter while a task runs steers the running turn now. Tab queues the message for after the turn, and Shift+← edits the last queued message.
The spec is not message one
Most real sessions start with a big spec and then grow forty follow-ups: new ideas, corrections, "actually use GraphQL." By message thirty the spec the agent obeys is a blur of message one and twenty-nine contradictions.
Put the spec in a file: the intended change, acceptance criteria, exclusions, decisions that still apply, the paths involved and the open questions. Feedback that changes the goal updates the file, and the agent revises the affected requirement instead of appending a contradiction. A small correction stays in the chat. A change of direction starts a fresh session from the file. A good handoff names the task, the spec, the current state, the owned paths, what was verified and the next step; it does not replay the conversation. If you do compact, tell it what to keep: /compact Focus on the API contract and the failing tests. For a long task, Claude Code's /goal sets a finish line it checks before stopping; Codex has /goal where goals are enabled.
Who writes to your screen
The main thread is the conversation you see.
A subagent appears as one row, with its name and task, and runs in its own context window. In Claude Code, open its row in the panel below the prompt to watch it work; after it finishes, /tasks opens its transcript. Only its summary returns to the main thread. The full transcript lives in its own file under ~/.claude/projects/…/subagents/, and it survives when the main conversation compacts.
A /fork copy or a background session is a whole separate session with its own transcript. claude agents lists them; claude attach opens one. In Codex, /agents opens the command center and /subagents switches between a session's subagent threads.
A side question (/btw, /side) shows its answer and leaves the main history as it was.
None of these copies protect your files. A branched or forked conversation shares the workspace with the original until something isolates it.
The practical rule: if you will want to steer it, it should be a session. If you only want the answer, it can be a subagent.
Shared checkout or worktree
When sharing works
Documentation, notes and knowledge bases share well: different files, often pushed straight to main. There, every session follows three rules.
- Commit only your own files, by name:
git add FILEfor new files, thengit commit -m "MSG" -- FILE. Given paths,git commitrecords only those, "disregarding any contents that have been staged for other paths." - Never stash,
reset --hard,clean,checkout ./restore .or switch branches in the shared folder. - Push directly. If the push bounces because the remote moved, run
git pull --no-rebase --no-edit --no-autostashand push again. A merge can proceed alongside unrelated uncommitted edits, but staged or overlapping changes can block it, and then you coordinate instead of forcing it.pull --rebaserefuses while any tracked file has uncommitted changes, and autostash would stash someone else's work.
A pathspec commit protects other files, not two edits inside the same file. Keep one owner per file, area or pipeline, and when your paths might overlap with a live peer's, say which ones you are taking.
When you need a worktree
Code with branches and reviews, anything that runs a server or a database, and long unattended runs get a worktree per session. A worktree is a second checkout of the same repository: it shares objects, branches and config, and has its own working files, index and HEAD. A branch can be checked out in only one of them at a time.
- Create.
claude --worktree orm-upgrademakes.claude/worktrees/orm-upgradeon branchworktree-orm-upgrade, from the remote default branch by default (worktree.baseRef: "head"keeps your local commits). Sessions you start withclaude --bgor from agent view move into a worktree before their first edit unless you setworktree.bgIsolation: "none"; a session you send to the background mid-task with/backgroundkeeps editing where it was.codex --worktreemakes a detached checkout of your current HEAD under$CODEX_HOME/worktrees. Neither carries your uncommitted edits over. - Secrets. A worktree starts with tracked files only. List
.envand friends in.worktreeinclude(gitignore syntax). Claude Code reads it, and Codex documents it for its desktop-app worktrees; I found no handling in the 0.162.1 CLI, so copy what you need into a Codex CLI worktree yourself. - Heavy folders. When both checkouts need identical dependencies and neither session will change them, point
node_modulesor a virtualenv at the main checkout withworktree.symlinkDirectories, then check your ignore rules. A pattern with a trailing slash,node_modules/, never matches a symlink: git's own docs sayfoo/"will not match a regular file or a symbolic link foo." I hit exactly this: the links showed up as untracked files, blockedgit worktree remove, and would have been swept into a commit. Add the slash-less name next to it. And remember that a symlinked folder is still shared: two worktrees installing packages into it collide. A shared environment must also stay read-only during runs and hold no editable installs or other links back to the main checkout's source; otherwise give each worktree its own environment and share only the package download cache. - Processes. Give each worktree its own port and database.
- Land, then remove. For a PR, create a task branch if the worktree is detached, then push it and open the PR. For a repository that takes direct pushes, follow its landing procedure to put the commits on the remote default branch. Once the PR is merged, or the work is on the default branch, check for uncommitted or unpushed work and for ignored files that exist nowhere else, such as a local database (
git worktree removedeletes ignored files even without--force), then remove the worktree and its branch:git worktree remove PATHandgit branch -d BRANCH. After a squash merge-dmay refuse; before using-D, confirm that the merged PR's recorded head commit matches the branch's current tip. A worktree that still holds uncommitted or unpushed work stays; never--forceover someone else's work. My agents do this without being asked, and a sweep catches what a closed session left behind (below).
Cleanup matters because every worktree is a full checkout of the tracked files. Claude Code removes a clean unnamed worktree on exit and asks otherwise; claude -p runs leave theirs behind, and its periodic sweep covers only worktrees it made for subagents and background sessions. The Codex CLI never deletes its worktrees; the desktop app keeps the 15 most recent and snapshots before deleting.
| 🌿 | In a worktree, step by step 1. Ask for it. Add "in a worktree" to the task: "fix the login bug, in a worktree". It holds for that task and its follow-ups. In a repository I registered as pull-request-only you can skip it: my guard refuses edits in the main folder there, so the agent moves into a worktree anyway. 2. The agent moves in. Claude Code has a tool for exactly this: ask it to "work in a worktree" during a session "and it creates one with the 3. Done means delivered. My rules have the agent deliver the work when the task is finished and the checks pass, before it tells you it is done; you never say "merge". In a repository that takes direct pushes, delivering is landing: it rebases, pushes to the default branch, updates your main folder and deletes the worktree and its branch. In a pull-request repository, it pushes the branch and opens or updates the PR; merging follows that repository's review rules, and the worktree stays until the PR has merged, because review fixes go there. Want to look first? Say "don't land yet". 4. Follow-ups. While the PR is open, follow-ups go into the same worktree and update the PR. After a direct-push landing, the next change gets a fresh worktree from the updated branch. 5. Close the tab whenever you like. Unfinished work stays: open a new tab and say "continue the login fix", and the agent finds the worktree and carries on. (If you leave Claude Code with |
Should you split the repository?
Sometimes, yes. Things that change together belong together; things that don't can live in separate projects with their own folders, their own CLAUDE.md or AGENTS.md, smaller contexts and fewer collisions. But a single product still needs parallel work inside one repository, so the rules above don't go away. Split by ownership and lifecycle, not to avoid learning worktrees.
The bill
The model remembers nothing between requests, so Claude Code "re-sends the full context: the system prompt, your project context, every prior message and tool result, and your new message." Prompt caching bills the unchanged part at a reduced rate: on the Claude API a cache read costs 0.1 times the base input price (0.05 times on Opus 5.5 and Sonnet 5.5), a five-minute cache write 1.25 times, a one-hour write 2 times. Cheaper, not free, and you pay it on every turn. In my own usage ledger last week, the average Claude request carried about 390,000 input tokens, and about 99% of them were cache reads. That is an observation of my setup with partial coverage, not a bill. Caching makes repeated context cheaper; it does not make irrelevant context free, and it does not make it smarter.
Here is why mixing tasks costs more. Take two equal tasks where every turn adds the same amount of context. In one shared session the second task drags the whole first task through every one of its requests; in two separate sessions it doesn't. Ignoring the fixed instructions and compaction, the growing history comes out at about twice the input for the shared session over many turns. Illustrative, not measured, and caching shrinks the price of that extra input, not its size.
The rest of the bill:
Separating unrelated tasks cuts the context each request carries. Five sessions at once still cost five sessions. And none of these API multipliers translate directly into subscription usage; check /usage in Claude Code and /status in Codex for reported usage and limits.
Sessions can talk
Claude Code sessions on one machine can message each other. Claude finds them with ListAgents and sends with SendMessage; you can also type @name in a prompt. A message is plain text, "never the sender's conversation history or files", read between the receiver's tool calls. Claude can ask for one notice when another session goes idle. A message can't approve anything, and the receiver's crossSessionInbound setting (accept, hold, refuse) decides what gets delivered. Codex has codex queue --thread ID --message TEXT for an existing session, plus thread tools inside a session.
Use messages for facts, not orders: "I own docs/ until 11:00." "The migration landed." "Done and pushed." Correctness comes from git, worktrees and leases, never from a message arriving, and another agent's request is never your authorization. Avoid ping-pong: a message to an idle Claude session starts a new turn with its full context, so batch facts into one useful report. If you want real orchestration, keep it shallow: one home session or the agents dashboard dispatches independent sessions, each worker owns disjoint paths or a worktree, and each reports back once.
What happens behind the scenes
You open the tabs; the setup keeps them from stepping on each other. I built these pieces into my harness, and none of them asks you to remember anything:
- Every session reads the rules first. Claude Code loads
~/.claude/CLAUDE.md, the instructions for all your projects, at the start of every conversation; Codex readsAGENTS.mdfiles "before doing any work", including the defaults in its home directory. I generate both files from one source, so every new session in every project already knows the parallel-work rules: commit only your own files by name; never stash,reset --hard,cleanor switch branches in a shared folder; merge and push again when a push bounces; put overlapping or branch work in a worktree, and any task you ask to run "in a worktree"; deliver the work when the task is done; remove the worktree as soon as its work has landed. - Hooks track the sessions. Both tools run small scripts on events: a session starts, a file is edited, a command is about to run. Mine record which session works in which folder and which files it changed.
- A notice when you are not alone. When another live session, Claude or Codex, works in the same folder, the agent gets a one-time note naming it and the files it has changed but not committed.
- A guard on risky git. The Claude Code docs say instructions are "context, not enforced configuration", and point to a PreToolUse hook to block an action whatever the model decides. So a guard checks each git command before it runs and blocks the ones that would sweep up or destroy another session's uncommitted edits: whole-tree adds and commits, stash,
reset --hard, checkout and restore of someone else's files,clean, branch switches, forced worktree removal. Outside repositories registered as pull-request-only, single-session work is never affected. - A hold on files in use. The same guard checks the agents' own edit tools: Claude Code's Edit and Write, and Codex's
apply_patch, which Codex hooks can intercept. When one of them targets a file that another live session has changed but not committed, the edit is refused, with the name of the session holding the file. The agent works on other files, asks that session to commit, or moves into a worktree. When several hooks answer, Claude Code lets a deny win: "precedence isdeny>defer>ask>allow." - Pull-request repositories stay clean. Repositories I register as pull-request-only refuse edits, commits and branch switches in their main folder, so every task there starts in a worktree whether you asked or not.
- A sweep for landed worktrees. At every session start, a background job removes the worktrees my agents made once their work has landed: contained in the freshly fetched default branch, or the exact head of a merged pull request. It never forces a removal. It respects locks, except the ones Claude Code left for sessions that have exited, and it keeps anything in use, used in the last half hour, or holding work that exists nowhere else: uncommitted, unpushed, or ignored files that are not copies of the main folder's. Each candidate is locked and checked again just before it goes.
What it does not do: it does not read the other sessions' plans or chats, and the hold covers only the agents' own edit tools. A script, a shell redirect, a generator or a person changing the same file acts outside it. When two tasks really need the same files, a worktree is the clean answer: each session gets its own copy, git flags conflicting edits when both land, and a clean merge still deserves a review.
The notice fires once per new peer, not on every prompt: repeating a registry into the context is just more noise. And none of it wraps the native controls: /clear, /btw, worktrees and background sessions stay exactly what the tools ship.
In its first live test against a real checkout, with a second session mid-edit, the guard refused a git add -A that would have staged 14 of that session's uncommitted files. The same afternoon, two sessions in that checkout committed by path and pushed to main minutes apart without a conflict. The next morning I ran the new pieces against real headless sessions in throwaway repositories. Asked to work "in a worktree" in a repository that takes direct pushes, Claude Code created the worktree, committed, pushed to main, stepped out, updated the main folder and deleted the worktree and its branch on its own. In a repository registered as pull-request-only, Codex's first patch to the main folder was refused; it made a worktree with git worktree add and pushed its branch from there. With a simulated session holding uncommitted edits to a file, both Claude Code's Edit and Codex's patch on that file were refused, and a Claude session free to choose did the change in a worktree instead. Told only "continue the login fix" in a new session, a Claude and a Codex session each found the unfinished worktree, finished the step its last commit named, pushed and cleaned up. After the test branches merged, the sweep removed the remaining worktrees and their branches. It is a seatbelt for cooperating agents, not a security boundary: unusual shell syntax, scripts and people act outside it.
No harness? Three rules in your global CLAUDE.md and AGENTS.md get you most of the way:
- Other sessions may be working in this folder at the same time: stay on the files of your own task.
- Commit only your own files (
git add FILE, thengit commit -m MSG -- FILE); never stash,reset --hard,cleanor switch branches in a shared folder. - Put overlapping or branch work in a worktree; deliver the work when the task is done. Remove the worktree only after its work has landed, it is no longer in use, it holds no uncommitted or unpushed work, and any ignored files that exist nowhere else have been saved.
A day with it
Illustrative, on a made-up shop repository:
- 09:00 Tab 1: you start an agent and type "fix the checkout bug".
- 09:20 You open tab 2 yourself and type "write the API docs". Its agent gets a note that tab 1 is editing the checkout code, and each stays on its own files.
- 10:00 Tab 3: you type the risky database upgrade, "in a worktree". Its agent moves into its own copy, uses its own port and database, and opens a pull request.
- 10:30 A Codex session in the main folder tries
git add -A. The guard names the file that belongs to the bug-fix session. Codex adds and commits its own test file by name. - 10:45 Tab 2's agent tries to edit the checkout file. The guard holds it: tab 1 has not committed it yet, so tab 2 leaves it alone.
- 11:00 Tab 2 commits its own files and pushes. You close it when you are happy.
- 11:20 Bug fixed and pushed. You close tab 1 too; the next task gets a new tab.
- 18:00 The upgrade's pull request is merged, long after you closed tab 3. Your next session's sweep removes the worktree and the branch.
Seven rules
- One task, one session.
- Side questions go sideways.
- Branch the conversation to try an idea.
- Commit only your own files.
- Overlap gets a worktree.
- Messages carry facts.
- Hooks catch the common mistakes.
Your agents can run in parallel. Your attention cannot. Run what you can review.