Giacomo Mantovani

Article · October 14, 2026 · By Giacomo Mantovani

My Claude Code workflow: one orchestrator and many parallel workers

One Claude Code session plans and reviews, never edits. Every task goes to a worker in its own leased git worktree. The setup, the scripts and what broke.

  • claude-code
  • ai-agents
  • developer-workflow
  • git-worktrees
  • engineering-process
One orchestrator. Many parallel workers. Read-only orchestrator, One worktree per task, One gate before main.

At first I ran one Claude Code session per repository and fed it tasks in sequence. It worked until I wanted two things done at once. Two sessions in the same checkout step on each other's files, and one long session that does everything ends up with a context full of half-finished work. So I split the job in two roles: one session that plans and reviews, and short-lived sessions that write code, each in its own copy of the repo.

This post describes that setup as I use it today on my own repositories, including this site. Everything here comes from my scripts and my instructions file. Where something broke, I say so.

What does an orchestrator and worker setup for Claude Code look like?

The orchestrator is a Claude Code session opened at the repository root. It reads the code, talks to me, breaks work into tasks and reviews what comes back. It does not edit files in the repository. That rule is written in my global CLAUDE.md, the instructions file Claude Code loads in every project: if a change is needed, open a worktree; inside a worktree, read and edit only there.

A worker is a separate Claude Code session started in a separate git worktree, on its own branch, with a single task. When it finishes, it commits on that branch and writes a short report: what it did, which files it touched, what is still open and how to verify it. The report lives outside the repository so it never ends up in a commit.

Two open source tools hold this together. herdr is a terminal runtime for coding agents: a single Rust binary that runs inside your existing terminal, keeps sessions alive in a background server, labels each pane as working, blocked or idle, and exposes a CLI and socket API that agents can drive. treehouse manages a pool of reusable git worktrees per repository, so each agent or task gets an isolated checkout and dependencies and build caches survive between uses.

How is a single Claude Code session different from an orchestrator with workers?

The difference is mostly about where context and file changes live. This is how the two setups compare in my day-to-day use.

Single session vs orchestrator and workers
AspectOne Claude Code sessionOrchestrator + workers
Parallel tasksOne at a time, or sessions colliding in one checkoutOne worktree and one branch per task
ContextGrows with every task until it is noisyEach worker starts clean with one task
Who edits codeThe session you are talking toOnly workers; the orchestrator reads and reviews
ReviewYou review your own session's diff as it goesThe orchestrator reviews a finished branch plus a written report
MergingWhatever branch you are onOne place: rebase on origin/main, run checks, push
Failure modeHalf-done edits mixed into the working treeLeaked leases and stale worktrees if cleanup is skipped

A single session is still the right call for a small fix in a repo you know well. I reach for workers when there are two or more independent tasks, or when one task is big enough that I want its exploration kept out of the planning session.

How does a new worker get created?

From the orchestrator, one command: a small shell script I wrote around herdr and treehouse, called herdr-worktree-new. It takes a branch name and the task text.

herdr-worktree-new feat/blog-table-block "Add a table block to the blog schema and renderer, with tests"

The script does five things. It fetches from the remote. It asks treehouse for a worktree with a durable lease, which reserves it until someone explicitly returns it. It checks out the branch there: an existing local branch, a remote one tracked locally, or a new one. It opens that worktree as a new herdr workspace with a single tab running Claude Code. Then it waits until the agent's interface reports it is ready to accept input, and sends the task with a fixed suffix appended.

path=$(treehouse get --lease --lease-holder claude --no-fetch)
cd "$path" && git checkout -q -b "$branch"
herdr worktree open --workspace "$ws" --path "$path" --label "$branch" --no-focus

The suffix tells the worker, in plain words, to commit on its branch when done and write a summary to a report file, and not to create report files inside the repository. A stop hook notifies the orchestrator pane when the worker finishes or when it is waiting for an answer, so I see a line like [worker done] or [worker waiting] in the parent session without polling.

How does the orchestrator review and merge a worker's branch?

When a worker reports done, the orchestrator reads the report, then the diff on the branch. It checks the change against the repository's own rules. On this site those rules are in CLAUDE.md and a CODING_STANDARDS file: tests first, the system map and docs updated in the same diff, new UI strings added to both the English and Italian dictionaries, pnpm only.

If the work is good, delivery follows the repository's ship config. There are no pull requests on this repo; the branch goes straight to main after the gate passes.

git fetch origin && git rebase origin/main
pnpm lint && pnpm typecheck && pnpm test
git push origin HEAD:main

Pushing HEAD to main works from inside a worktree even though main is checked out somewhere else. If the rebase moved anything, the checks run again. A merge conflict or a rejected push stops everything and comes back to me; force-pushing main is off the table. Typecheck is in the gate on purpose, because the production build for this site ignores type errors.

One small rule makes parallel branches far less painful: prose docs are written one sentence per line. When three workers each touch the same doc, a rebase usually merges their lines without a conflict.

How do you close a worker without leaking worktrees?

The second script, herdr-worktree-close, takes the herdr workspace id. It refuses to run if the worktree has uncommitted changes and prints the status instead. Otherwise it calls treehouse return on the path, closes the herdr workspace and deletes the report.

herdr-worktree-close w12
# dirty worktree -> exit 2, prints git status
# clean -> treehouse return <path>, workspace closed

treehouse return releases the lease, kills leftover processes in the worktree, resets it and puts it back in the pool. If it cannot confirm that no foreign processes remain, it leaves the worktree and the lease in place, which is the safe default.

What went wrong with this setup?

The worst one was leaked leases. A treehouse lease persists even when no process is running in the worktree; that is what makes it durable. When I closed a herdr workspace by hand instead of through the close script, the lease stayed. treehouse's default pool size is 16 worktrees, and one day every new worker failed because all 16 were marked in use while almost none had an agent running. The fix was releasing them with treehouse return, and the habit is to always close workers through the script.

Agent names collided. herdr agent names are unique across the whole herdr instance, not per pane, so naming every worker claude broke the second one. Now the name includes the workspace id, lowercased, because herdr requires lowercase names and workspace ids switch to uppercase letters after w19.

Tasks were sent too early. Sending the prompt right after starting the agent raced the app's own startup, and the text sometimes landed in the input box without being submitted. The worker sat there doing nothing. The script now polls herdr until the agent is interactive, with a cap, and only then sends the task.

Built-in worktree helpers left orphans. My instructions forbid Claude Code's own worktree tools for this flow, because they left orphaned worktrees in the repository's .claude/worktrees folder that nothing cleaned up. One pool with explicit leases is easier to audit.

What are the common mistakes when running parallel Claude Code agents?

Letting the orchestrator edit code. As soon as the planning session starts fixing things itself, its working tree diverges from what the workers see, and reviews turn into merges of two half-finished changes. Keep it read-only.

Giving a worker two tasks. A worker with one task produces a branch you can review in one pass. Two unrelated tasks in one branch mean a diff you either accept whole or untangle by hand.

Skipping the written report. The diff shows what changed, and the report says what the worker did not finish and how to check it. Without it, the orchestrator has to guess which parts of the branch are intentional.

Merging from the worker. If each worker pushes on its own, nobody runs the full gate on the rebased result. One place merges, after the checks.

Closing spaces by hand. With durable leases, closing the terminal does not free the worktree. Use the close script, or run treehouse return yourself.

Next step

Want your team working with agents in parallel?

I help engineering teams set up agentic workflows like this one on their own repositories: isolation, review gates and the rules agents follow.

Let's talk

If you want agents to do more than write code, for example handling tickets or documents, see how I approach AI agent development.

Frequently asked questions

Do I need herdr and treehouse to run Claude Code in parallel?

No. Plain git worktrees and a few terminal tabs are enough to start. herdr adds agent state, a background server that survives disconnects and an API to start agents and send prompts from scripts. treehouse adds a reusable pool with leases, so you do not reinstall dependencies for every task.

How many workers do you run at once?

As many as there are independent tasks I can review. The hard limit in my setup is the treehouse pool size, 16 worktrees by default per repository, but review time runs out well before that.

Can the workers use a cheaper model than the orchestrator?

Yes. herdr-worktree-new accepts a model and an effort flag and passes them to the worker's Claude Code session, so a mechanical task can run on a lighter setting while the orchestrator keeps the stronger one.

Does this work with agents other than Claude Code?

The scripts mirror the caller's harness: started from opencode, they spawn opencode workers. herdr itself supports several coding agents, and treehouse does not care what runs inside the worktree.

Author

Giacomo Mantovani

AI Engineer & Consultant for Companies and Agencies

LinkedInGitHub

Next step

Tell me the workflow. We scope it on a free call, then a working version is live within 10 days.

Book a scoping call

Related articles