Skip to content

Running several agent sessions in worktrees

While an agent works on a task, you wait for it. A second agent session can use that time on another task, and a third one on a third. Running parallel sessions multiplies what gets done, and it also multiplies the ways the work goes wrong. Two agents may edit the same file. A session may wait an hour for an answer you forgot to give. Organizing that kind of workflow and keeping an eye on it is a skill of its own [1].

In this lesson you run two sessions side by side on one small project. The project is the shipping module of a web shop, in the course repository under site/examples/coding-with-agents/parallel-sessions/shop/. shipping.py has one function, quote, which gives the price of a parcel in euros (EUR): 4.00 plus 1.50 for each started kilo. test_shipping.py tests it, README.md documents it, and python3 check.py runs the tests and every >>> example in the README. The lesson has two tasks. The API (application programming interface) change makes quote charge 0.75 per started half kilo. The docs task adds a usage section with examples to the README.

Sessions that run in one folder share every file, so one agent’s half-done edit is in the other agent’s test run. Git worktrees solve this. A worktree is an extra working folder of the same repository, with its own branch and its own files. All the worktrees of a clone share one history, and a commit made in one of them is visible in the others at once. Git keeps a few things per worktree, such as HEAD (the branch that is checked out) and the index (what is staged for the next commit). It shares the rest, including every branch and tag. By default git refuses to check out a branch in a new worktree when another worktree has it checked out [2].

These are the commands, run in the project folder shop on main. Each add makes a new branch from main and checks it out in a new folder next to shop:

Terminal window
git worktree add -b api-half-kilo ../shop-api
git worktree add -b docs-usage ../shop-docs
git worktree list

When the work is merged, git worktree remove ../shop-api removes the folder [2]. The branch stays until you delete it.

Example · run it

The course’s script copies shop to a temporary place and makes the copy a git repository with one commit on main. Then it runs the commands above and prints each one after the name of the folder it runs in. The list shows only the folder and the branch of each worktree, because paths and commit hashes differ on every machine. The script runs git quietly, so the two add lines show no output of their own. For the last command the script says in its own words what git does. Run it from site/examples/coding-with-agents/parallel-sessions/ in your clone of the course repository, and compare what you see with the output below.

Terminal window
python3 worktrees.py
Output
shop$ git worktree add -b api-half-kilo ../shop-api
shop$ git worktree add -b docs-usage ../shop-docs
shop$ git worktree list
shop       main
shop-api   api-half-kilo
shop-docs  docs-usage
shop$ git worktree add ../shop-extra main
git refuses: main is checked out in shop

Output verified in CI from site/examples/coding-with-agents/parallel-sessions/worktrees.py.

The examples in this lesson aren’t graded. Each one is a command you run, with output the course checks on every build.

Claude Code can make the worktree for you. claude --worktree api-half-kilo creates a worktree under .claude/worktrees/api-half-kilo/ in the repository, on a new branch called worktree-api-half-kilo that starts from the repository’s default branch, and starts the session in it. A new worktree starts with only the files git tracks. Files that git ignores, such as a .env file, aren’t in it, and the dependencies aren’t installed. The vendor page says to set up the environment in each new worktree, and a .worktreeinclude file in the project lists the ignored files that Claude Code copies into each worktree it creates [3]. With plain git, as above, you do the same steps yourself.

A worktree separates the files. It doesn’t make two tasks independent. Choose tasks that change different files, and write each brief so the agent stays in its own files. The transcripts below are illustrative and don’t record a specific model’s words.

Prompt (illustrative, not a recorded transcript)

You work in shop-api on the branch api-half-kilo. Change quote in shipping.py to charge 4.00 plus 0.75 per started half kilo, and update test_shipping.py to match, with a test for a parcel of 0.4 kg. Change only those two files. Another session is editing README.md on its own branch, so leave it alone. Don’t use git stash, and commit your work in progress instead. Done when python3 check.py passes here. Then commit, and tell me the last line of its output.

Response

I changed the rule in quote to 400 + 75 * math.ceil(weight_kg * 2) cents and updated the docstring. In test_shipping.py the 2.3 kg parcel now costs EUR 7.75, and a new test checks that 0.4 kg costs EUR 4.75. The check prints check passed. I committed on api-half-kilo.

Prompt (illustrative, not a recorded transcript)

You work in shop-docs on the branch docs-usage. Add a “Usage” section to README.md with two >>> examples of quote, for 1 kg and for 2.3 kg, and one sentence on what a weight of 0 kg or less does. Change only README.md, and don’t use git stash. Done when python3 check.py passes here. Then commit and stop. I will tell you when to rebase.

Checkpoint · choice

Which pair of tasks suits two parallel sessions?

You can follow one session closely at a time. While you read the diff of one, the other one may fail its check or stop to ask you a question. Keep a written note, one line per session, with the worktree and its branch, the task, when you look at it next, and whether it is waiting on you:

shop-api api-half-kilo price per started half kilo check at 10:40 waiting on me: no
shop-docs docs-usage usage section in README.md check at 10:40 waiting on me: yes, asks about the 0 kg sentence

Update the line each time you look at a session. A session that says “waiting on me: yes” comes first, because it does nothing until you answer. When the note has more lines than you can check in the time the sessions take, you are running too many.

Checkpoint · choice

Which line lets you pick up that session after the meeting?

Git stores the newest stash in the ref refs/stash and the older ones in that ref’s log [4], and every ref under refs/ is shared by all the worktrees of the clone [2]. So there is one stash for all the sessions.

Example · run it

The docs session's stash, popped by the API session

Section titled “The docs session's stash, popped by the API session”

The course’s script opens the two worktrees, makes both sessions’ edits without committing them, and then runs the commands below in the folder each line names. (nothing) means the command printed nothing. The script runs git quietly, so the stash push and stash pop lines show no output of their own. Run it from the same directory.

Terminal window
python3 stash.py
Output
shop-docs$ git stash push -m "usage section, half done"
shop-api$ git stash list
stash@{0}: On docs-usage: usage section, half done
shop-api$ git stash pop
shop-api$ git status --short
 M README.md
 M shipping.py
 M test_shipping.py
shop-docs$ git stash list
(nothing)
shop-docs$ git status --short
(nothing)

Output verified in CI from site/examples/coding-with-agents/parallel-sessions/stash.py.

The API worktree now holds the docs session’s README edit next to its own changes, and the docs session’s work is gone from its own worktree. Git reported no error at any step.

What else the sessions share needs a decision before they start. Give each session its own copy of what it can have per worktree, such as the dependency install and a test database file. When a session must run a server, pick a port for it. Leave alone what only exists once: the stash, the main branch, which only you merge into, and a dev server on a fixed port. For the last one, tell the agents to run the build or the check and not to start the server. Claude Code also shares permission approvals between worktrees. In a worktree session, a “Yes, and don’t ask again” answer for a command saves the rule in the main checkout’s settings. The rule then applies in every worktree of the repository, except on Windows and in the other cases the vendor page names [3].

Checkpoint · sort

Branches that run side by side drift apart, and the longer they live, the harder they are to merge. Integrate often, and in an order you choose before you start: the change that others depend on goes first. Here the docs describe the API, and the API branch merges into main first. Then the docs session rebases its branch on the new main. A rebase replays the branch’s own commits, one at a time, on top of the new starting point, and stops at the first conflict [5].

The two tasks change different files, so the rebase has no conflict. That doesn’t mean the docs are still right. The docs session wrote its example for the old price, and the check is what finds that. So the session runs the check again after every rebase.

Example · run it

The course’s script makes both sessions’ commits, then merges and rebases in the order above. It prints a short result where git’s own messages differ between git versions. The merge lines have no output of their own, because the script runs the merges quietly. The line in parentheses is the step the docs session takes after the failed check. Run it from the same directory.

Terminal window
python3 integrate.py
Output
shop-docs$ python3 check.py
tests: 2 passed, 0 failed
README examples: 2 passed, 0 failed
check passed
shop$ git merge --ff-only api-half-kilo
shop-docs$ git rebase main
rebased with no conflict
shop-docs$ python3 check.py
tests: 3 passed, 0 failed
README examples: 1 passed, 1 failed
  quote(2.3): expected 'EUR 8.50', got 'EUR 7.75'
check failed
(the docs session fixes the example and commits: docs: example for the half-kilo price)
shop-docs$ python3 check.py
tests: 3 passed, 0 failed
README examples: 2 passed, 0 failed
check passed
shop$ git merge --ff-only docs-usage
shop$ git log --format=%s
docs: example for the half-kilo price
docs: usage examples for quote
feat: price per started half kilo
chore: the shipping module

Output verified in CI from site/examples/coding-with-agents/parallel-sessions/integrate.py.

The check passed on the docs branch before the rebase and failed after it, and the rebase had no conflict. The check caught the example. A sentence in the README about the price rule would have gone stale without a failing check, so the brief for the rebase also asks the session to read what the other branch changed. With --ff-only, git refuses a merge that it can’t do as a fast-forward [6], so you notice when main moved after the branch last rebased. The history on main then has one line of commits, in the order you merged them.

Prompt (illustrative, not a recorded transcript)

api-half-kilo is merged into main. It changes the price to 0.75 per started half kilo. Rebase docs-usage on main, read the diff of the merged commit with git show main, and run python3 check.py. Fix anything in README.md that no longer matches, commit, and tell me the last line of the check.

Checkpoint · scenario

Both branches are finished, and each check passed on its own branch. What do you do?

Many pages of this course are written by agent sessions that run side by side, and the repository’s page on orchestration describes how [7]:

  • One coordinating session takes the ready issues and starts one builder session per issue. Each builder works in its own worktree, in one folder next to the repository, on a branch named after its issue.
  • The prompt for each builder names the files that another builder also edits, such as the shared bibliography, so each builder knows where its change can collide with another one.
  • No agent runs git stash in any worktree, because all the worktrees of the clone share one stash. A hook in the repository blocks the command, and the agents commit work in progress or save it as a patch instead.
  • Builders don’t start the site’s dev server. A server left running from an earlier session keeps its port and serves old pages, so a builder would check the wrong content.
  • The coordinator rebases the approved branches onto one integration branch, one at a time in the order they were approved, and runs the full check on the result before it opens one pull request. When a branch conflicts, the coordinator stops the rebase and sends the branch back to the builder who wrote it, and doesn’t resolve the conflict itself.
Checkpoint · multi-choice

You write the brief for the docs session. Which of these lines do you put in it?

Select exactly 3.

Exercise

Make a project of your own from the course files. Afterwards you can run two real sessions side by side without them taking each other’s files or stash. Make sure ~/shop, ~/shop-api and ~/shop-docs don’t exist yet. Then, from the root of your clone of the course repository, run:

Terminal window
cp -R site/examples/coding-with-agents/parallel-sessions/shop ~/shop
cd ~/shop
printf '__pycache__/\n' > .gitignore
git init --initial-branch=main
git add .
git commit -m "The shipping module"
git worktree add -b api-half-kilo ../shop-api
git worktree add -b docs-usage ../shop-docs

Start one agent session in ~/shop-api and one in ~/shop-docs, and give them the two briefs from this lesson. Write the one-line note for each session before you press enter, and update it each time you look at a session. When both have committed, merge the API branch in ~/shop with git merge --ff-only api-half-kilo, and give the docs session the rebase brief. Merge the docs branch when its check passes. Then remove the two worktrees with git worktree remove. If git refuses, run git status in that worktree to see which files an agent left there.

A good result has a main with the API commit first and the docs commits after it, a README.md whose examples pass python3 check.py, and a note whose last lines match what the sessions did. Delete ~/shop when you are done. Then answer one question: which resource on your own machine would two of your sessions share without either of them knowing?

Stretch: Run the same two tasks again with claude --worktree. Run claude once in ~/shop first to accept the trust prompt, then find where Claude Code put each worktree and what it named the branches.

Recap

  1. Parallel sessions use the time you would spend waiting. Give each one a worktree on its own branch, with a task that changes different files from the rest.
  2. Worktrees of one clone share the history and every ref under refs/, including the stash. Each worktree has a separate folder of files, HEAD and index [2]. A new worktree has no ignored files and no installed dependencies until you set it up [3].
  3. Keep one line per session: worktree and branch, task, next check-in, and whether it waits on you. Answer a waiting session first.
  4. Integrate in a fixed order, the change others depend on first. The other sessions rebase and run the check again, because a rebase without a conflict can still leave a stale example.
  5. Give each session its own copy of what a worktree can hold, and tell every session to leave alone what exists once, such as the stash, main and a fixed port.

You can now

  • Runs several agent sessions without losing coherence

  1. Brilliant. Designing workflows. Brilliant, Coding with AI skills map. Reference. Brilliant BLD
  2. The Git project. git-worktree. Git reference documentation. Reference. Git docs git-worktree
  3. Anthropic. Run parallel sessions with worktrees. Claude Code documentation. Reference. Claude Code worktrees
  4. The Git project. git-stash. Git reference documentation. Reference. Git docs git-stash
  5. The Git project. git-rebase. Git reference documentation. Reference. Git docs git-rebase
  6. The Git project. git-merge. Git reference documentation. Reference. Git docs git-merge
  7. The AI Training contributors. Orchestrating agents. AI Training repository, docs/agents/orchestration.md. Reference. AI Training orchestration