While I was outlining this post, I interrupted myself with a feature request: add Mermaid support to the site. The agent in this thread spun up a Codex teammate in a separate worktree. That teammate changed seven files, ran the tests and Astro check, committed everything, then handed back its base SHA, head SHA, ordered commit list, and checks. The first agent reviewed the commit and replayed it onto main with git cherry-pick -x. I never left the conversation. Neither agent ever saw the other’s loose files.
That tiny job is the shape of almost everything I ship now. I keep feeding feature requests and bug reports into one lead thread in goldengoose. The lead stays available, turns each request into a separate worker, and eventually assembles their finished work into one tested version of main. It looks like a multi-agent orchestration system. Underneath, most of the coordination is ordinary Git and my full 300-line lead playbook, which tells the lead exactly how to use it.

The command that changed the workflow most was not git worktree. It was git cherry-pick.
A worktree gives an agent the world it expects
A Git worktree is another working directory attached to the same repository. It can have a different branch checked out at the same time, so two agents get the same history without sharing an index or a pile of uncommitted files. It is much cheaper than maintaining another clone and much safer than pointing two writers at one checkout.
In goldengoose this is native. When I or an agent adds a teammate, we can give it a worktree name and the runtime creates the branch, prepares the checkout, and attaches the new agent to it. The left sidebar shows every teammate, the worktree it owns, and live line counts. Click one and I am in its normal thread; select its Git view and I can see its changed files, diff, and recent commits. They are not hidden sub-agents. They are visible members of the same flat team, each sitting at a clean desk.
That cleanliness matters more than isolation in the abstract. Before worktrees, my agents could message each other and coordinate, but they still opened the repository to somebody else’s dirty state. A surprising amount of their intelligence disappeared into caution. They would avoid a file another agent had touched, route an implementation around an unknown diff, or spend turns explaining why they were trying not to overwrite work they did not understand.
I suspect this is partly a training prior: coding agents spend a lot of their post-training in clean repositories, and a dirty shared checkout pushes them away from the environment where their instincts are strongest. I cannot verify the training setup from outside. I can see the behavior. Give the same agent a clean worktree and it stops negotiating with ghosts and writes the obvious code again. It is the Git version of not fighting the priors.
flowchart TD
LEAD["One lead thread<br/>stays available"]
LEAD --> A["Agent A<br/>worktree + branch"]
LEAD --> B["Agent B<br/>worktree + branch"]
LEAD --> C["Agent C<br/>worktree + branch"]
A --> Q["Ready queue<br/>base..head"]
B --> Q
C --> Q
Q --> I["Disposable<br/>integration branch"]
I --> G{"Integrated checks<br/>green → origin/main"}
This diagram could not be rendered. Its source is shown instead.
Worktrees unlocked parallel execution. They did not solve the expensive half. Three isolated agents still produce three histories that have to become one.
The leverage is that I stay out of the queue
Three agents typing at once is not leverage by itself. I learned that in the terminal version of this workflow, where every extra agent created another tab I had to remember, another branch I had to inspect, and another merge I had to schedule. The code was parallel; my attention was still serial. In practice I kept the real queue in my head and only ran work concurrently when I was confident the file paths would not overlap.
That is exactly the ceiling the lead removes. It is never busy implementing, so I can interrupt it with the next bug or feature while five earlier requests are researching, coding, reviewing, or waiting to integrate. Finished work enters a ready queue. Unfinished work stays in flight. A conflict blocks one commit range instead of freezing the repository. The lead keeps the clock while I keep deciding what is worth building.
This is what one thread buys me. It is not a chat interface pasted over five terminals; it is the single serial point for my intent, with Git providing the concurrency underneath. I can talk in the order ideas occur to me instead of the order the codebase can safely accept them.
The leverage is not more keystrokes per minute. It is removing myself from the path between finished work and shipped work without giving up provenance, review, or an integrated test gate. For that, the lead needs handoffs more precise than “my branch is done.”
A branch name is not a handoff
The first version of my workflow was simple: give an agent a branch, wait for one commit, cherry-pick it onto main. Then review became serious. A reviewer found something, the implementer added a fix commit, the reviewer found a smaller edge case, and suddenly “the feature” was four commits whose order mattered.
A branch name is too vague for that handoff. It moves. It does not prove the worktree is clean. It does not tell the lead which commits the reviewer approved, or whether the branch contains a merge commit that makes the range unsafe to replay as a simple sequence.
So every code-changing agent now returns an exact implementation base SHA, an exact head SHA, and this ordered log:
git status --porcelaingit rev-parse HEADgit log --reverse --oneline <implementation-base>..HEADgit rev-list --merges <implementation-base>..<approved-head>Before integrating, the lead resolves the reported branch again with git rev-parse <branch> and requires that result to equal the approved head. The friendly name can move after review; the SHA cannot. That range, not the branch, is the unit my reviewers approve and my lead ships. main advancing afterward does not make the approved code less approved. Only a change to the code, a conflict during composition, or a broken assumption does.
The lead’s Git board
Five questions between a request and main
Isolate
Give the worker a clean checkout
Can this agent work without seeing another agent’s loose files?
A linked worktree shares the repository’s history and object store, but checks out a different branch in a different directory.
What changes
Creates a linked checkout and branch
git worktree add -b gg/auth-fix ../auth-fix mainCreate the branch and its linked checkout together.
git worktree listSee every checkout and the branch attached to it.
The commands sound stranger than they are
The names make these commands look more complicated than they are. Each one gives the lead a direct answer to a practical question before it changes shared history.
git status --porcelain checks that the agent has no uncommitted or untracked work left behind. It is the predictable, script-friendly version of git status; no output means the feature is fully committed.
git rev-parse <branch> turns a movable branch name into the fixed SHA of the exact commit the lead is about to use. Git calls main, HEAD, and agent/auth refs: movable pointers to commits. rev-parse resolves the pointer so the lead can confirm it still matches the SHA the reviewer approved.
git log --reverse base..head shows the feature’s commits from first to last. The two dots mean “the commits after base, up to head.” --reverse puts the oldest first.
git rev-list --merges base..head tells the lead whether the approved range contains a merge commit. rev-list searches commits; --merges asks for only the merge commits in this range. No output means the handoff is a simple sequence.
git merge brings the other branch into the branch I am currently on, rather than selecting individual commits. It asks Git to join both branch histories as one operation.
git merge-tree previews whether the agent’s branch and the integration candidate can be combined without changing any checked-out files. It runs the merge calculation without touching the checkout, so it can warn the lead before the real cherry-pick decides.
--ff-only lets Git update the branch only when the update is a straight line, and fails otherwise. Git may move the branch pointer straight forward, but it may not quietly create a merge the lead did not ask for.
git cherry-pick -x base..head copies the approved commits onto the candidate one at a time while leaving the agent’s branch alone. It replays each chosen change on the branch currently checked out and creates one new commit for each. -x appends the original SHA to the new commit message so the source remains traceable.
Everything before that last command is inspection. Cherry-pick is the handoff. Git’s own documentation dates it to August 2005; almost 21 years later, it became the core of my multi-agent workflow because its unit is the same unit my reviewers approve: an exact commit or exact commit range.
Cherry-pick is the underrated multi-agent command
The obvious way to bring a finished worktree back is to merge its branch. That is the habit pull requests teach us: approve the branch, then run the equivalent of git merge agent/auth.
That works, but it solves a slightly different problem. A merge says, “join the complete histories of these two branch tips.” My reviewer approved something smaller and more precise: the commits from this exact base SHA to this exact head SHA, in this order. The merge is not unsafe. It is simply broader than the thing I approved, and a naïve merge uses a branch name that can keep moving after review.
Cherry-pick lets the integration use the same unit as the review:
git cherry-pick -x <approved-base>..<approved-head>That command means: take only these approved commits, apply them here in the same order, and leave the agent’s branch alone. Git creates one new commit for each original commit, so the boundaries the reviewer saw stay intact. -x records the original SHA in each new commit message, so I can always trace where it came from.
That precision becomes useful as soon as several worktrees are moving in parallel. If main advances, the approved range does not change; the lead can replay the same commits onto the new candidate. If one range conflicts, the lead can abort that range and continue with the others. Rebasing would make every worker rebuild and retest its branch whenever main moved. Copying the files by hand would throw away the commit history. Cherry-pick keeps the workers untouched and makes integration the lead’s problem once, in one place.
I say that cherry-pick brings the work “into main,” but I no longer run it directly on local main. I run it on a disposable branch based on the latest origin/main. Think of that branch as the version I hope will become main. It earns the name only after every ready range has been replayed and the combined checks pass.
This is what broke the rebase loop for me. The old lead would land Agent A, advance main, then decide Agent B’s older base was automatically stale. It sent B away to rebase, retest, and hand back a new commit range. While B did that, Agent C landed and moved main again. I had accidentally turned every successful parallel branch into more work for every branch still in flight.
An old base is not a conflict. If B’s approved changes still apply cleanly on top of the current candidate, cherry-pick replays them and the job is over. The workers do not all need to absorb every new main commit. The lead reconciles shared history once, where the histories meet.
gitGraph LR:
commit id: "M0"
branch agent-auth
checkout agent-auth
commit id: "A1"
commit id: "A2"
checkout main
commit id: "M1"
branch integration
checkout integration
commit id: "A1 replay"
commit id: "A2 replay"
This diagram could not be rendered. Its source is shown instead.
The agent branch above started at M0. The integration candidate started later, at M1. Cherry-pick reproduces the approved changes as A1 replay and A2 replay without rewriting the agent branch or pretending its ancestry became current.
I never rehearse the integration on main
Cherry-pick is safe to abort, but my early leads still ran it directly on local main. A conflict put the checkout into an in-progress sequence, dirtied the index, and blocked every unrelated branch until somebody aborted or resolved it. Even when recovery took seconds, the most important branch in the repository had become scratch space.
The current playbook creates a disposable integration branch from the latest origin/main instead:
git switch maingit pull --ff-onlygit status --porcelaingit rev-parse origin/maingit switch -c gg/integration-<timestamp> origin/mainThe lead records that remote SHA as the round base. For branches with plausible overlap, it may run git merge-tree --write-tree first. merge-tree performs a real merge calculation without reading from or writing to the working tree or index, which makes it useful as an early warning. It is not an oracle: it models a whole-tree merge, not my exact sequence of cherry-picks. The disposable cherry-pick remains the authoritative integration test.
Each ready range gets its own git cherry-pick -x command. If one conflicts, git cherry-pick --abort returns the candidate to its pre-sequence state. The lead skips only that range and keeps integrating unrelated work. The agents that wrote the conflicting changes get the exact candidate SHA and conflict paths, then talk to each other and resolve it with the context only they have.
flowchart TD
M["origin/main<br/>record exact SHA"] --> C["Create disposable<br/>integration candidate"]
C --> R["Replay approved ranges<br/>one branch at a time"]
R -. "one range conflicts" .-> A["Abort only that range<br/>keep the rest moving"]
R --> T["Run checks on<br/>the combined result"]
T --> Q{"origin/main still<br/>at recorded SHA?"}
Q -->|yes| P["Push tested candidate<br/>fast-forward main"]
Q -->|no| B["Discard candidate<br/>repeat from new main"]
This diagram could not be rendered. Its source is shown instead.
Everything in the middle of that diagram is expendable. Only the final push touches shared main.
After the integrated checks pass, the lead fetches origin/main again and compares its SHA with the recorded round base. If the remote moved while the checks ran, it does not force-push and does not send every implementer away to rebase. It creates a fresh candidate from the new remote tip, replays the same approved queue, and reruns the gate. If the SHA stayed still, git push origin HEAD:main publishes the exact candidate that was tested, git merge --ff-only origin/main moves local main to it without inventing a merge commit, and git branch -d gg/integration-<timestamp> removes the temporary branch. If the push still loses a race, the same rule applies: rebuild, replay, retest, never force.
The playbook is the infrastructure
I did not sit down and design this workflow. The lead playbook grew one failure at a time: agents writing over one another, dirty worktrees making them timid, branch names pointing past reviewed code, merge commits poisoning replay ranges, leads returning branches merely because main moved, conflicts on one feature blocking everything else, tested candidates racing a remote push.
Each failure became one sentence or one Git command. The file is now 300 lines long and has been edited enough that my leads are startlingly good at the job. I can keep dropping requests into the same conversation because the lead never writes the code. It decides what can run in parallel, gives each worker a clean worktree, waits for exact handoffs, maintains the ready queue, stages integration rounds, validates the composed result, and pushes. That is the lead as a judgment engine expressed as Git: a queue of immutable ranges and a place to decide what lands next.
goldengoose makes the arrangement pleasant: worktree creation is a native agent operation, every teammate is visible in the sidebar, every branch has a live diff, and I can enter any worker’s thread whenever I want. But none of the Git logic requires a new orchestration service. It is a markdown file teaching an agent to use commands Git has had for years.
If you are starting to run coding agents in parallel, learn more Git before you add more agents. Give each one a worktree. Require clean, committed handoffs with immutable endpoints. Treat the commit range as the artifact. Replay approved ranges onto a disposable candidate, abort conflicts per range, and fast-forward only after the integrated result passes.
Git did not make my agents parallel. It made their parallelism replayable.