# Running several agent sessions in worktrees

> Run two agent sessions on one project at once, each in its own git worktree and branch with a task that changes other files, keep a one-line note per session, and integrate in a fixed order: merge the API branch, have the docs session rebase and run the check again, and keep every session away from the shared stash and port.

Page: https://schubergphilis.github.io/ai-training/coding-with-agents/parallel-sessions/
License: CC BY-SA 4.0, https://creativecommons.org/licenses/by-sa/4.0/

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 (Designing workflows, Brilliant, Coding with AI skills map).

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.

## Give each session its own worktree

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
(git-worktree, Git reference documentation).

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`:

```sh
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 (git-worktree, Git reference documentation). The branch stays until you delete it.

#### Example: Two worktrees, and one that git refuses

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.

```sh
python3 worktrees.py
```

Output:

```text
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
```

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 (Run parallel sessions with worktrees, Claude Code documentation). 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)

```text
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

```text
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)

```text
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: Which two tasks can run side by side?

Which pair of tasks suits two parallel sessions?

- Rename a function in every module, and add a new option to one of those modules.
- Fix a bug in the payment module, and write a guide for the report module in the docs folder.
- Upgrade the web framework, and fix a bug in a page that uses the web framework.
- Split the settings file into three files, and add a new setting to the settings file.

## Keep a note per session

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:

```text
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: Which note gets you back on track?

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

- "shop-api: working on the shipping change, looked fine at the last check."
- "api-half-kilo: 4 commits so far, 2 files changed, the tests pass on the branch."
- "shop-api, api-half-kilo: price per half kilo, check at 10:40, waiting on me: no."
- "Session 2: see the chat window for the details, it will say when it is done."

## Know what the worktrees share

Git stores the newest stash in the ref `refs/stash` and the older ones in
that ref's log (git-stash, Git reference documentation), and every ref under `refs/` is shared
by all the worktrees of the clone (git-worktree, Git reference documentation). So there is one
stash for all the sessions.

#### Example: 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.

```sh
python3 stash.py
```

Output:

```text
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)
```

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.

#### Pitfall: Two sessions that never touched the same file

A developer ran two sessions in two worktrees of one clone. The API
session stashed its own edit to try something, and later the docs session
stashed its half-done README. When the API session ran `git stash pop` to
get its edit back, git applied the newest stash, the docs edit, in the API
worktree. No merge conflict and no error showed it. Tell every session to
leave the stash alone and to commit its work in progress instead.

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 (Run parallel sessions with worktrees, Claude Code documentation).

#### Checkpoint: Its own, or shared?

Buckets:

- Each worktree has its own
- Shared by both sessions

Items:

- The files of the checked-out branch
- The staged changes for the next commit
- The list of stashed changes
- The branches and tags of the repository
- Port 4321 on the laptop

## Integrate in a fixed order

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 (git-rebase, Git reference documentation).

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: Merge the API, rebase the docs

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.

```sh
python3 integrate.py
```

Output:

```text
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
```

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 (git-merge, Git reference documentation), 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)

```text
`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: Both sessions say they are done

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

- Merge the docs branch first, because it is the smaller change, and then merge the API branch after it.
- Merge both branches into main one after the other, since both checks passed and git reports no conflict.
- Tell the docs session to merge its branch into the API branch, so the two changes can be reviewed together.
- Merge the API branch, have the docs session rebase on main and run the check again, then merge the docs branch.

## How this course is built

Many pages of this course are written by agent sessions that run side by
side, and the repository's page on orchestration describes how
(Orchestrating agents, AI Training repository, docs/agents/orchestration.md):

- 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 second branch
  back to its builder, and doesn't resolve the conflict itself. The table
  of sources is the exception: when two branches add lines to it, the
  coordinator keeps the lines of both. The shared bibliography never stops
  a rebase, because git merges that file by keeping the lines of both
  sides. When two branches add the same entry, the check after the
  rebases finds the entry twice, and the coordinator drops one copy.

#### Checkpoint: Which lines go into the docs brief?

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

Select exactly 3.

- Change only README.md, and leave the code files to the other agent.
- Run the check in your worktree, and don't use the git stash.
- Start the dev server on its usual port to look at the pages.
- Pull the other branch into yours whenever it has new commits.
- Commit and stop when the check passes, and wait for me to say rebase.

## 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:

```sh
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 (git-worktree, Git reference documentation). A new worktree has no ignored files and no installed dependencies until you set it up (Run parallel sessions with worktrees, Claude Code documentation).
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.

#### Habit

Before you start a second agent session next to a running one, write its line in your note: branch, task, next check-in, and whether it waits on you.

## References

- Designing workflows, Brilliant, Coding with AI skills map
- git-worktree, Git reference documentation, https://git-scm.com/docs/git-worktree
- Run parallel sessions with worktrees, Claude Code documentation, https://code.claude.com/docs/en/worktrees
- git-stash, Git reference documentation, https://git-scm.com/docs/git-stash
- git-rebase, Git reference documentation, https://git-scm.com/docs/git-rebase
- git-merge, Git reference documentation, https://git-scm.com/docs/git-merge
- Orchestrating agents, AI Training repository, docs/agents/orchestration.md, https://github.com/schubergphilis/ai-training/blob/main/docs/agents/orchestration.md
