Skills and agents that let several Claude Code agents build one feature at once without overwriting each other.
One agent per feature is slow. The obvious fix, several agents on one codebase, fails in predictable ways:
- Two agents edit the same file and one silently overwrites the other.
- An agent builds against a type or response shape that another agent changed an hour ago.
- Agents stop and wait for each other, so the parallel build runs at the speed of the slowest question.
This kit fixes that with three mechanisms: a contract committed before any work starts, explicit file ownership per lane, and a shared append-only board where lanes ask, answer, and announce without stopping.
Orchestrator. The parent Claude Code session. It plans the feature, writes the contract, cuts the lanes, dispatches one worker per lane, watches the board, integrates, and verifies. It never writes lane code.
Lanes. One worker agent each, working in its own git worktree on its own branch
feature/<topic>--<lane>, with an explicit list of the files it owns. Two agents never share a
worktree.
Contract first. Typed schemas (zod, pydantic, or your language's equivalent) and one fixture per
response, for everything that crosses a lane boundary, are committed to the integration branch
feature/<topic> before any lane starts. Consumer lanes build and test against the fixtures before
the producer exists. Later changes come only from the contract owner: it commits the change on its
own lane branch and posts CONTRACT, the orchestrator merges that branch into the integration branch
right away and posts INTEGRATED, and every lane picks the change up by merging the integration
branch. Lanes never merge each other's branches.
File ownership. Every path the build touches appears exactly once in the ownership map. Shared files (barrels and index files, registries, route maps, migrations, package manifests) get exactly one owner. Any other lane that needs a change there posts a NEED instead of editing.
The board. board.sh is a small CLI over an append-only log at
~/.agent-sync/<topic>/BOARD.log. It lives outside git, so every worktree on the machine sees the
same file. Every command has the form board.sh <topic> <command> [args]. Set
B=~/.claude/skills/parallel-build/board.sh in each shell call, because Claude Code Bash calls do
not share variables. Boards live under ~/.agent-sync by default; set AGENT_SYNC_ROOT to move
them. Claim globs are shell patterns: * also matches /, so src/*.ts covers every .ts under
src/; braces are rejected. Exact paths, including bracketed route files, match literally.
| Command | What it does |
|---|---|
init |
Create the board for a topic and copy the lane protocol next to it |
post <agent> <TYPE> <msg> |
Append one entry and print its id |
new <agent> |
Entries from other agents since this agent last ran new |
tail [n] |
Last n entries (default 40) |
claims |
Active claims: agent and path globs not yet released |
owner <path> |
The claim(s) covering a path, as agent (glob), or unclaimed; paths are relative to the repository root |
open [agent] |
ASK and NEED entries with no ANSWER yet |
path |
Print the board file path |
Entry types: CLAIM, RELEASE, ASK, NEED, ANSWER, CONTRACT, STATUS, BLOCKED, DONE, INTEGRATED, NOTE.
ASK and NEED start with to=<agent>; ANSWER starts with re=<id>. Every lane follows five rules:
- Own only your files. Check
ownerbefore editing; post a NEED for anything another lane owns. - Never sit idle. If you are waiting on an answer, post BLOCKED and build another part of your order.
- Check the board at every checkpoint: before each commit, after each sub-task, before you wait.
- Answer first. An ASK or NEED addressed to you is handled before your own work continues.
- Pull shared changes before you commit. On INTEGRATED, merge the integration branch first; never merge another lane's branch.
Continuous integration. The orchestrator merges the contract owner's branch as soon as it posts
CONTRACT, and merges other lane branches after every STATUS that other lanes need, in a fixed order
(contract owner first). It runs the type-check after each merge and posts INTEGRATED. Lanes only
ever merge the integration branch (git merge feature/<topic>), before their next commit, so drift
surfaces in minutes instead of at the end.
Reviewer before the final merge. An adversarial reviewer agent reads every lane that touches
money, auth, or data deletion before its final merge.
+--------------------------------------+
| orchestrator |
| plan, contract, dispatch, integrate |
+---+-------------+-------------+------+
| | | dispatch, relay ASK/NEED
v v v
+-----------+ +-----------+ +-----------+
| lane: api | | lane: ui | | lane: ntf | one worktree and
| worktree | | worktree | | worktree | branch per lane
+--+-----+--+ +--+-----+--+ +--+-----+--+
| | | | | |
| +--------+--+--+--------+ | post / read
| | |
| ~/.agent-sync/<topic>/BOARD.log | append-only
| |
+--------+ merge each lane +----+
v v
feature/<topic> (integration branch: contract + merged lanes)
type-check after each merge, then post INTEGRATED
| Path | Purpose |
|---|---|
skills/parallel-build/SKILL.md |
The orchestrator's playbook: size the lanes, map ownership, write the contract, dispatch, integrate, finish |
skills/parallel-build/PROTOCOL.md |
The rules every lane reads; init copies it next to the board |
skills/parallel-build/lane-work-order.md |
Template for one lane's work order |
skills/parallel-build/board.sh |
The board CLI |
skills/orchestrating/SKILL.md |
The orchestrator loop for any delegated task: investigate, plan, dispatch, verify |
skills/orchestrating/work-order.md |
Template for a single-worker work order |
agents/builder.md |
Implements a fully specified work order and reports proof |
agents/reviewer.md |
Read-only adversarial reviewer with a SHIP / FIX FIRST / REWORK verdict |
agents/scout.md |
Fast read-only reconnaissance |
tests/board-test.sh |
Test suite for board.sh |
install.sh |
Copies the skills and agents into ~/.claude/ |
.github/workflows/test.yml |
Runs the test suite on Ubuntu and macOS, and shellcheck on Ubuntu, for every push and pull request |
- A recent Claude Code with custom skills and agents (
~/.claude/skills/,~/.claude/agents/), agents that honourmodel:andeffort:frontmatter, background Agent dispatch, SendMessage, and Monitor. If SendMessage to a running sub-agent is unavailable in your version, lanes still pick up board entries at their next checkpoint withnewandopen; relaying only makes it faster. - bash 3.2 or newer. The scripts are written for bash 3.2 and POSIX tools; they are tested on Linux (bash 5), and the repository's GitHub Actions workflow runs the test suite on Ubuntu (bash 5) and on macOS with the system /bin/bash 3.2.
- git 2.17 or newer (
git worktree addandgit worktree remove). flock(util-linux), recommended on Linux. Without it (macOS does not ship it),board.shfalls back automatically to amkdir-based lock.- Standard POSIX tools: awk, sed, sort, tail, tr, mktemp, and friends (BSD or GNU versions both work).
- Optional, for development: shellcheck.
git clone https://github.com/Kevsosmooth/claude-parallel-kit.git
cd claude-parallel-kit
./install.shinstall.sh copies each skills/* directory to ~/.claude/skills/ and each agents/*.md file to
~/.claude/agents/. It refuses to overwrite anything that already exists and lists what it
skipped; pass --force to overwrite. To install by hand instead:
mkdir -p ~/.claude/skills ~/.claude/agents
cp -r skills/parallel-build skills/orchestrating ~/.claude/skills/
cp agents/*.md ~/.claude/agents/
chmod +x ~/.claude/skills/parallel-build/board.shVerify:
~/.claude/skills/parallel-build/board.sh demo init # prints the new board path
rm -rf ~/.agent-sync/demo # remove the demo board
bash tests/board-test.shThe agents pin model: and effort: in their frontmatter. The kit ships one builder at effort
medium. For orders with cross-file invariants, or when escalating a failed order, create a copy
pinned to a higher effort and dispatch that instead:
sed -e 's/^name: builder$/name: builder-high/' -e 's/^effort: medium$/effort: high/' \
~/.claude/agents/builder.md > ~/.claude/agents/builder-high.mdUse effort: xhigh for the hardest orders, or model: sonnet in a builder-sonnet copy for
routine work. The reviewer runs at xhigh on purpose; the scout runs on haiku at low
because it only reads.
To uninstall, remove the two skill directories, the three agent files (and any copies you made), and the board data:
rm -rf ~/.claude/skills/parallel-build ~/.claude/skills/orchestrating
rm -f ~/.claude/agents/builder.md ~/.claude/agents/reviewer.md ~/.claude/agents/scout.md
rm -rf ~/.agent-syncSkip any item that install.sh reported as skipped; that file was yours before the install. If you
set AGENT_SYNC_ROOT, remove that directory instead of ~/.agent-sync.
You want a "saved searches" feature: users save a search, see a list of saved searches, delete
one, and get a daily email when new results match. You ask the orchestrator session to build it
with the parallel-build skill. It splits the work into three lanes and writes the ownership map
into the plan before anything else:
| Lane | Owns | Produces | Consumes |
|---|---|---|---|
api |
src/saved-searches/contract.ts, src/saved-searches/contract.test.ts, src/saved-searches/fixtures/**, src/saved-searches/server/**, src/app/api/saved-searches/**, db/migrations/**, src/app/routes.ts, package.json |
create, list, delete routes | contract |
ui |
src/saved-searches/ui/**, src/app/searches/** |
list page, save dialog | contract, fixtures |
notifications |
src/saved-searches/notify/**, src/jobs/saved-search-digest.ts |
daily digest job | contract |
api is the contract owner, and it also owns the shared route map, the migrations, and
package.json, so the other lanes post a NEED for any change there.
The orchestrator commits the contract on the integration branch, creates the board and the lane
worktrees, and dispatches all three lanes in one message. (The blocks below set B once for
readability; in Claude Code, set it in every Bash call.)
B=~/.claude/skills/parallel-build/board.sh
# 0. Once per project, before the first worktree: keep worktrees out of git.
grep -qxF '.worktrees/' .gitignore 2>/dev/null || printf '\n.worktrees/\n' >> .gitignore
# 1. Integration branch with the contract: schemas, one fixture per response, a fixture test.
git worktree add -b feature/saved-searches .worktrees/saved-searches main
cd .worktrees/saved-searches
git add src/saved-searches/contract.ts src/saved-searches/contract.test.ts src/saved-searches/fixtures/
git commit -m "feat(saved-searches): add lane contract and fixtures"
cd ../..
# 2. The board, and one worktree and branch per lane.
$B saved-searches init
for lane in api ui notifications; do
git worktree add -b "feature/saved-searches--$lane" ".worktrees/saved-searches--$lane" feature/saved-searches
done
$B saved-searches post main NOTE "ownership map: docs/plans/saved-searches.md"
# 3. Dispatch the three lanes (Agent tool, run in background, one work order each).
# Each lane starts by claiming its globs:
$B saved-searches post ui CLAIM "src/saved-searches/ui/**, src/app/searches/**"Midway through, the ui lane needs a "last run" timestamp that the contract does not have. It
does not edit contract.ts; it asks the owner and keeps building the save dialog:
$B saved-searches post ui NEED "to=api add lastRunAt (ISO string, nullable) to SavedSearch in contract.ts and its fixture"
# prints 7, the entry id
$B saved-searches post ui BLOCKED "list badge waits on entry 7; meanwhile building the save dialog"The orchestrator sees the entry on the board and relays it to api with SendMessage. api checks
$B saved-searches open api, commits the change on its own lane branch, and announces it:
$B saved-searches post api CONTRACT "4f2c1ab add nullable lastRunAt to SavedSearch and fixture"
$B saved-searches post api ANSWER "re=7 4f2c1ab lastRunAt added; merge the next INTEGRATED before your next commit"The orchestrator merges the contract owner's branch into the integration branch at once, type-checks, and posts INTEGRATED:
cd .worktrees/saved-searches
git merge --no-ff feature/saved-searches--api && npx tsc --noEmit
$B saved-searches post main INTEGRATED "8b51d20 contract change 4f2c1ab merged, tsc clean"ui runs git merge feature/saved-searches in its worktree before its next commit and finishes the
list badge. It never merges feature/saved-searches--api directly.
Later, when api and ui post a STATUS with commits the others need, the orchestrator merges them
into the integration branch, contract owner first, and type-checks after each merge:
cd .worktrees/saved-searches
git merge --no-ff feature/saved-searches--api && npx tsc --noEmit
git merge --no-ff feature/saved-searches--ui && npx tsc --noEmit
$B saved-searches post main INTEGRATED "9d03e7c api and ui merged, tsc clean"Every lane merges the integration branch before its next commit. The api lane owns the delete route, so before
its final merge the orchestrator dispatches the reviewer agent on that lane's diff
(git diff feature/saved-searches...feature/saved-searches--api). The reviewer returns FIX FIRST:
the delete route checks that the search exists but not that it belongs to the caller, with a repro
test. The finding goes back to api with the test, api fixes it and posts a STATUS, and the
reviewer re-reviews the fix before its final merge.
When all three lanes post DONE, the orchestrator does the final merge, runs the full type-check and
test suite on the integration branch, removes the lane worktrees, and opens a pull request from
feature/saved-searches to main.
- Run an adversarial reviewer on every money, auth, or data-deletion lane before its final merge. In one rebuild of a billing module it found three bugs, each with a repro test: a customer's prepaid credit was refunded as cash, a credit was stranded after an account transfer, and a same-day cancel and re-subscribe billed twice.
- Send reviewer findings back to the owning lane with the repro tests, and re-review the fix. The first fix in that case was only partial.
- When one lane makes a shared field nullable, type-check the integration branch after merging. Each lane can be green on its own while the merge is red.
- Dev servers hold scarce resources. Run one only for a screenshot pass, then stop it.
- Session cookies and auth state never live beside shared screenshots.
- A background lane cannot answer a permission prompt. When one blocks a lane's merge or edit, reassign that file's ownership or do the step from the orchestrator instead of forcing the lane through.
- Each lane is a separate agent run, so cost scales with lane count. Two lanes that would each finish in ten minutes are cheaper as one.
- The board is a file, not a service. It works on one machine, where every worktree sees it.
- The orchestrator still has to read every security-relevant diff.
- This does not replace code review.
- It works best on codebases with a type-checker and tests, because the contract and continuous integration rely on both to catch drift.
Issues and pull requests are welcome. Before opening a pull request, run:
bash tests/board-test.sh
shellcheck -s bash skills/parallel-build/board.sh install.sh tests/board-test.shMIT. See LICENSE.