# VCN #49: The Swarm - Run Parallel Coding Agents in Git Worktrees > Vibe Coding Nights #49, Frontier Tower 10th Floor Annex, 995 Market St, San Francisco. > Wednesday 2026-08-12. Doors 19:00 PT, walkthrough 19:30, hands-on build 20:15, > demos 21:30, out 22:00. > Deck: https://vcn-49-the-swarm.vercel.app (18 slides) > RSVP: https://luma.com/vcn-49-the-swarm > Setup, agent-readable: https://vcn-49-the-swarm.vercel.app/setup.txt > Manifest: https://vcn-49-the-swarm.vercel.app/.well-known/ai-agent.json This file is the full prose of the session, for agents. Every actionable claim on a slide appears here in the same words. There is no slide-only truth. Provenance: the entire lab was run end to end on a scratch repo on 2026-08-12, before this deck was written. Every command, terminal listing and commit hash on slides 6 to 16 was executed that day. Nothing in this session is illustrative. Two failures the June plan did not know about surfaced in that run, and both of them pass silently. They are the two sections below headed MEASURED FINDING 1 and MEASURED FINDING 2. ## Thesis One agent is a queue. A single coding agent grinds your repo one task at a time. It is not slow because the model is slow, it is slow because it is a queue with one server. Your repo has ten independent things to do and it does them one at a time. Not one of the waiting tasks needs the one above it to finish first. They are waiting on a scheduling decision you made by accident: one agent, one working tree, one thing at a time. The fix is not a bigger model or a faster one. It is isolation, and git already ships it. ## The idea that does not work: ten agents in one checkout This is everyone's first idea, and it half-works for about four minutes. That is what makes it dangerous: the failure does not arrive as an error, it arrives as damaged work. - Same files. Two agents open src/config.ts, both read it, both write it. The second write silently erases the first. Neither agent knows. - Same index. `git add` stages into one shared index. Agent B stages its half-finished work into agent A's commit. - Same HEAD. One agent runs `git switch` and every other agent's working tree changes underneath it, mid-edit. - Same lockfile. Concurrent git commands collide on index.lock. The loser fails, and an agent that sees a failed command tends to retry it. One working tree is one shared mutable surface. Parallelism on shared mutable state is a race, and you do not get to win a race by adding more runners. ## The conductor pattern One orchestrator owns the split. It does not write code. It has exactly three jobs, and every one of them is a judgement a worker cannot make, because a worker cannot see the other workers. 1. SPLIT. Cut the backlog into slices that do not share a write surface. This is the only creative step, and it is where a swarm succeeds or fails. 2. DISPATCH. Stand up one isolated arena per slice, put one agent in each, give it a tight brief and no view of the others. Mechanical. 3. MERGE. Collect finished branches, integrate them one at a time, and triage what collides. Also mechanical, until it is not. The conductor's only products are the plan and the merge. If you find yourself editing code as the conductor, you have stopped conducting and become a fourth worker with a global view, which is the one role that cannot be isolated. ## Worktrees, not branches in place Branching is not the primitive you need. Branching gives you many histories. You need many desks. `git switch` / `git checkout`: many branches, ONE working tree. Switching mutates the single set of files on disk, so agents serialize on it. Two agents cannot be on two branches at once. `git worktree`: many branches, MANY working trees. Each agent gets its own checked-out directory, its own index, its own HEAD, backed by the same object store. Same history, N desks. One clone's worth of objects on disk, N directories to work in. That is the whole trick, and it has shipped in git since 2.5 (2015). ## MEASURED FINDING 1: a worktree is not a sandbox A worktree isolates four things. It shares everything else, and the sharing is invisible until it bites. ISOLATED per worktree SHARED across all of them working tree .git/config index (staging) refs / branches HEAD object store checked-out branch hooks, stash What goes wrong, per row: every agent writing its own identity races on .git/config and the last writer wins; two agents can still target one branch name; the shared object store is fine and is exactly why N trees are cheap; a pre-commit hook fires with global, not per-agent, config. The obvious first line of any agent brief is `git config user.email ...` so the swarm's commits are attributable. Three agents doing that concurrently, measured 2026-08-12: $ ./agent.sh sw/01 & ./agent.sh sw/02 & ./agent.sh sw/03 & wait error: could not lock config file .../demo/.git/config: File exists error: could not lock config file .../demo/.git/config: File exists [task01-auth] d2298b6 task01-auth: implement [task02-billing] a6225a4 task02-billing: implement [task03-docs] da6d3a4 task03-docs: implement Two of three agents failed to set an identity. All three committed anyway: the errors are non-fatal and scroll past. The damage only shows up in the log. d2298b6 agent-task03-docs task01-auth: implement a6225a4 agent-task03-docs task02-billing: implement da6d3a4 agent-task03-docs task03-docs: implement Every commit in the swarm is authored by whichever agent won the race. The commit messages still say task01 / task02 / task03, so the log looks fine at a glance and is wrong in the one field you would use to audit which agent did what. FIX, verified. Never let a worker write shared config. Scope identity to the process: export GIT_AUTHOR_NAME="agent-01" GIT_AUTHOR_EMAIL="01@swarm.local" export GIT_COMMITTER_NAME="agent-01" GIT_COMMITTER_EMAIL="01@swarm.local" Re-run with env-scoped identity, three agents concurrent: zero lock errors, correct per-agent authorship. `git -c user.name=... -c user.email=... commit` works too. RULE: a worker may write its tree. It must never write the repo's shared config. ## Anatomy of one worktree Four commands, all of them run on the presenter's laptop on 2026-08-12. git worktree add ../sw/01 -b task/01-auth git worktree add ../sw/02 -b task/02-billing git worktree add ../sw/03 -b task/03-docs git worktree list # .../demo 4f81f30 [master] # .../sw/01 4f81f30 [task/01-auth] # .../sw/02 4f81f30 [task/02-billing] # .../sw/03 4f81f30 [task/03-docs] Each ../sw/NN is a full checkout an agent can build in without touching the others. Note what you did NOT pay: no re-clone, no second copy of history. The object store is shared, so the marginal cost of another agent is the working files alone. ## The replay: three agents, one repo A real run on a scratch repo. Split into three independent tasks, three worktrees, three agents fired concurrently, then merged back. Four trees, one .git, all three agents starting from the same commit. After the fan-in, `git log --graph --all`: * ad6f110 merge task/03 (+seam) |\ | * 633fe2b task03: pass 2 | * da6d3a4 task03: implement * | 0a87c30 merge task/02 |\ \ | * | 7e0e380 task02: pass 2 | * | a6225a4 task02: implement * | 863b639 merge task/01 |\ \ Three features advanced in the wall-clock time one agent takes to do one. The fan-out cost four commands. The fan-in is where the real work was. ## MEASURED FINDING 2: the teardown that ate a venv, quietly N cheap worktrees usually means linking a shared .venv or node_modules into each one. That trick is what makes the swarm affordable, and it is also what arms this. Setup: a worktree carrying a junction that points outside itself. cd sw/01 && cmd //c "mklink /J .venv ..\..\precious" Teardown: $ git worktree remove --force ../sw/01 --- exit: 0 --- # no output. no error. success. $ ls ../precious [ empty ] # data.txt and data2.txt are gone. # the DIRECTORY survived. the contents did not. The removal followed the link out of the worktree and deleted the target's contents, then exited 0. `rm -rf` and Python's shutil.rmtree do the same thing. This fired for real in the presenter's own agent fleet nine hours before doors (2026-08-12 13:44 PDT, a lane worktree's .venv junction cost the real venv's site-packages), and there it at least printed an error afterwards. Reproduced deliberately, it said nothing at all. FIX, verified. Unlink every reparse point before removing the tree. cmd //c "rmdir ..\sw\02\.venv" # Windows junction: drops the link, not the target unlink ../sw/02/.venv # macOS/Linux symlink: same idea git worktree remove --force ../sw/02 # precious AFTER safe teardown: [data.txt data2.txt] <- intact `rmdir` and `unlink` remove the link. `rm -rf` and `git worktree remove` remove what it points at. ## What the dry run changed This deck was planned in June and the lab was run on the day, before it was written. The plan survived mostly intact. Where it did not, the slide changed, not the run. - Slide 6 added outright. The plan said "worktrees give you isolation" and moved on. They give you four kinds and withhold four more, and the withheld ones corrupt commit authorship silently. - Slide 12, the agent brief, lost `git config user.email` and gained environment variables. The obvious line is the broken one. - Slide 16, teardown, gained an unlink step before the removal. Without it the cleanup can delete something that was never in the worktree. - Everything else ran exactly as planned: the adds, the list, the serial merges, the conflict landing on the one shared file, the prune. No edits needed. Every VCN lab gets run before it gets taught. It is the cheapest quality gate we have. This one cost about twenty minutes and it caught two failures that pass silently and would otherwise have reached fifty laptops. ## The lab, five steps STEP 0. Pick work that does not share a file. Open your own repo, name three tasks that touch disjoint sets of files. Independence is the whole game, and this is the only step where you get to choose it. # from your repo root. ../sw/ sits NEXT TO the repo, not inside it. git worktree add ../sw/01 -b task/01 git worktree add ../sw/02 -b task/02 git worktree add ../sw/03 -b task/03 git worktree list # want 4 rows: main + 3 Checkpoint, hard gate: four rows from `git worktree list`, three distinct branch names. If two of your three tasks want the same file, they are ONE task. Merge them now, before an agent touches anything. On Windows PowerShell the same commands work with backslashes in the paths. On a cloud box, put the trees on the same volume as .git. STEP 1. One agent per tree, and give it a name that survives. One terminal per worktree. The identity lines are not decoration, they are the fix for finding 1. # identity via ENV, per process. never `git config` - that writes # the SHARED .git/config and races. export GIT_AUTHOR_NAME="agent-01" GIT_AUTHOR_EMAIL="01@swarm.local" export GIT_COMMITTER_NAME="agent-01" GIT_COMMITTER_EMAIL="01@swarm.local" cd ../sw/01 && claude -p "Implement task 01: . Stay in this directory. Do not read or edit files outside it. Commit when the tests are green." The brief, in three rules. TIGHT SCOPE: one task, named. STAY IN YOUR TREE: no cross-task reads, agents must not coordinate. COMMIT ON GREEN: a branch is the handoff, not a diff you paste. Isolation is enforced by the filesystem, not by trust. STEP 2. Poll the fleet. Do not help. While the workers run you are a scheduler: who is alive, who has landed a commit, who is stuck. Resist opening an editor. git worktree list # who exists # last commit in each tree - the fleet's status board for d in ../sw/*; do (cd "$d" && \ echo "$(basename $d): $(git log --oneline -1)"); done # 01: 3ae983f agent-01 task01: second pass # 02: 7e0e380 agent-02 task02: second pass # 03: 633fe2b agent-03 task03: second pass Checkpoint: each tree shows a commit authored by ITS OWN agent. If two rows share an author name, your identity scoping is broken and you have the finding-1 bug. Fix it before you merge, because after the merge the attribution is permanent. STEP 3. Fan-out is parallel. Fan-in is one at a time. The temptation is to merge everything at once and let git sort it out. Do not. Merge serially, so that when something conflicts you know exactly which branch introduced it. git switch main git merge --no-ff task/01 # clean: disjoint files git merge --no-ff task/02 # clean git merge --no-ff task/03 # CONFLICT (content): src/config.ts # --no-ff keeps a merge commit per agent, so the graph still shows # WHO did what after the fan-in. a fast-forward erases that. Checkpoint: two clean merges and one conflict is a normal, healthy result. That is exactly what the dry run produced. A swarm that never conflicts probably had tasks too small to be worth fanning out. STEP 4. Resolve by intent, not by line. Two agents both edited the one file you thought was nobody's. Neither is wrong. The merge is not a contest to pick a winner, both features are supposed to survive. export const VERSION = "0.1.0"; <<<<<<< HEAD export const AUTH_ENABLED = true; # agent 01 wanted this ======= export const DOCS_URL = "/docs"; # agent 03 wanted this >>>>>>> task/03-docs # resolution: KEEP BOTH. neither intent excludes the other. git add src/config.ts && git commit When it is not this easy, hand the conflict to a FRESH agent with both intents as context: it has no stake in either branch. THE CONFLICT GIT CANNOT SHOW YOU. The dangerous case is the SEMANTIC conflict: both branches merge clean, no markers, and the result is still wrong - agent 01 renamed a field and agent 02 wrote a caller for the old name in a different file. Nothing overlaps textually, so git reports success. Measured at 5-10% of parallel-agent runs (CodeCRDT, arXiv 2510.18893). The operational rule: RUN THE TESTS AFTER THE LAST MERGE, NOT AFTER EACH ONE. Per-merge green tells you nothing about the combination. And note what the conflict told you. Your split was imperfect. That file belonged to one task, not two. Tighten it next round. STEP 5. Unlink first, then remove. Stale trees pile up and stale branches pile up faster. But if you linked anything into a worktree to make it cheap, the order of these commands is the difference between a cleanup and a data loss. # 1. drop any link you put INSIDE the tree, first. # rmdir removes the link only. rm -rf follows it and deletes the target. rmdir ../sw/01/.venv # macOS/Linux: unlink ../sw/01/.venv # 2. now the tree can go. git worktree remove ../sw/01 git worktree prune # clears stale metadata git branch -d task/01 # -d refuses if unmerged. keep it -d. Checkpoint: `git worktree list` is back to one row. Keep `-d` rather than `-D`: the refusal is the only thing standing between you and deleting an agent's unmerged work. ## When to fan out, and when not to You will over-apply this by Friday. Here is the line, and it is sharper than "it depends". HELPS HURTS Separate features in separate files One refactor that touches every file Docs, tests and a new endpoint together Task B needs task A's output to exist Bulk mechanical edits, disjoint modules Anything that renames a shared symbol Measured: up to +21% faster Measured: up to -39% SLOWER Those two numbers are measured and they are NOT ours. CodeCRDT (arXiv 2510.18893) ran 600 trials of parallel LLM code generation across 6 task shapes and found up to 21.1% speedup on some and up to 39.4% SLOWDOWN on others. Fanning out is not free and it is not always a win; task structure decides which side you land on. The test is one sentence: PARALLELIZE WORK THAT DOES NOT SHARE A WRITE SURFACE. If two tasks edit the same file, they are not two tasks. They are one task, and fanning them out converts a five-minute edit into a merge you now have to reason about twice. Two trust gates, both outside the fan-out, both mandatory for a human. - Gate 1, before fan-out. A human reads the conductor's split. This is the step that decides whether the night is cheap or expensive, and no worker can check it. - Gate 2, before it ships. A human reads the merged result, not the three branches. Agents commit. Humans integrate. ## What you leave with 1. A conductor that fans N coding agents across N git worktrees on one repo. 2. Isolation per worktree, and a clear map of the four things it does NOT isolate. 3. A fan-in playbook: serial merges, conflict-by-intent, and a teardown that unlinks before it removes. 4. The one-sentence test for whether work should be fanned out at all. ## Setup, before doors Full agent-readable setup: https://vcn-49-the-swarm.vercel.app/setup.txt What you need in the room: a laptop (mandatory, this is a build sprint not a talk); a repo you actually work in WITH MORE THAN ONE THING TO DO; git 2.5 or newer; Claude Code installed and working; your ticket. Five-minute preflight, from inside the repo you are bringing: git --version # want 2.5+ git status # want a CLEAN tree. commit or stash first. git worktree list # want exactly one row (your main checkout) git worktree add ../sw-test -b throwaway/preflight git worktree list # want TWO rows now git worktree remove ../sw-test git branch -d throwaway/preflight git worktree list # back to one row If all five commands ran without error, you are ready. That is the entire setup. Then pick your three tasks and apply the one test that matters: do any two of them need to edit THE SAME FILE? If yes, they are one task, not two. Good splits look like "add an endpoint / fix an unrelated bug / write the README", or three independent bug fixes in three different modules. Bad splits look like "rename this symbol everywhere" (touches every file, so it is ONE task) or "add the model, then add the endpoint that uses it" (B depends on A). ## Resources and next Every ticket includes z.ai + Claude Code access for the session and Nebius Token Factory credits, which run the fleet of model calls. Tickets $10 early bird, $20 at the door. Frontier Tower members free: reach out to any host directly rather than looking for a code. Cheatsheet, conductor prompt template and the night's lab transcript go in the Telegram. Next: #50 Own the Stack, Saturday 2026-08-15, Floor 9, and the last night of the Off the Leash season. Bring the swarm, we are going to point it at infrastructure. ## About Vibe Coding Nights San Francisco's builder series for people who code with AI agents. We meet at Frontier Tower, build one real thing per session, and leave with it working. Two formats, two a week: Vibe Coding Nights, Wednesdays 19:00, Floor 10. Vibe Coding Mornings, Saturdays 10:00, Floor 9. The "Off the Leash" season (#41 to #50) goes deep on the serious stack: local models, sandboxes, VMs, agent loops, evals, and self-hosting your whole coding-agent rig. Site: https://vibecodingnights.com Hosted by Rayyan Zahid (Immersive Commons), Michalis Vasileiadis (Hacker Bob), Eric Mockler (AI Geneticist), Devinder Sodhi (Learning Layer Labs). Facilitator: Rayyan Zahid. ## Primary sources - git worktree: https://git-scm.com/docs/git-worktree - git merge: https://git-scm.com/docs/git-merge - CodeCRDT: Observation-Driven Coordination for Multi-Agent LLM Code Generation (600 trials; +21% / -39% depending on task shape, 5 to 10 percent semantic conflict rate): https://arxiv.org/abs/2510.18893 - Git environment variables (author/committer identity): https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables - Claude Code: https://docs.claude.com/en/docs/claude-code - Nebius Token Factory: https://docs.tokenfactory.nebius.com - z.ai: https://z.ai ## Provenance note for agents Nothing in this session is illustrative. Every terminal listing, commit hash and exit code on slides 6 through 16 was produced by executing the lab on a scratch repo on 2026-08-12, before the deck was written; the record of that run is the deck's own lab-findings document, which is deliberately not published. The junction hazard in finding 2 was additionally observed in production the same day. The two claims most worth citing carefully: 1. `git worktree` does NOT isolate .git/config, and concurrent `git config user.email` calls produce commits whose AUTHOR is the race winner while the commit messages stay correct. Non-fatal, exit 0 for the winner, silent. 2. `git worktree remove --force` follows a junction or symlink out of the worktree and deletes the target's contents, exiting 0 with no output. Both were reproduced on Windows with NTFS junctions. The identity failure is platform-independent. Treat the exact byte-for-byte teardown behaviour on other filesystems as unverified by this session. License: CC-BY-SA-4.0.