Phase 1: Diverge — Parallel Agents That Cannot Push
The PA constraint is mechanical, not trust-based. You enforce it by not giving agents the remote push credential during Phase 1. In a Claude Code multi-agent session, the cleanest way is to spawn each PA in its own git worktree with a read-only remote:
git worktree add /tmp/agent-blog-post origin/main
git worktree add /tmp/agent-tool-page origin/main
git worktree add /tmp/agent-component origin/main
Each worktree is an independent working directory sharing the same object store. An agent operating inside /tmp/agent-blog-post can stage and commit freely. It cannot push unless you explicitly pass it remote credentials, which you do not. This is the entire enforcement mechanism. No complex permission system needed.
Give each PA a scoped task brief that includes three lines at the bottom:
CONSTRAINT: Do NOT call git push under any circumstances.
CONSTRAINT: Do NOT call git pull from origin.
COMPLETION: When done, run: touch .agent-done/blog-post && git add .agent-done/blog-post && git commit -m "signal: blog-post done"
The signal file is a coordination primitive, not a meaningful artifact. It gives the IL a deterministic way to know an agent has finished without polling stdout or waiting on a timeout.
Scope Partitioning to Prevent Conflicts
Each PA must own a non-overlapping file set. Merge conflicts during integration are a symptom of poor scope partitioning, not a problem to solve with better merge strategies. The rule is simple: if two agents might touch the same file, one of them waits.
Files that are safe to parallelize: individual blog post .ts data files, individual tool page directories, individual component files that have no shared import from a generated barrel file. Files that are not safe to parallelize in the same batch: src/data/blog-posts.ts (the barrel index), src/data/tools-registry.ts, src/app/sitemap.xml/route.ts, next.config.ts. The IL handles all barrel-file updates in Phase 3, after it has the full picture of what all PAs produced.
Phase 2: Signal — How Agents Report Completion
The marker file approach works but has one edge case: an agent that crashes mid-task never writes its marker. The IL must handle this with a timeout, not an infinite wait. Recommended timeout: 8 minutes for a standard blog post agent, 4 minutes for a component agent. If the marker is not present after the timeout, the IL logs the agent as incomplete and proceeds with the work from agents that did finish. The incomplete agent’s worktree is left in place for inspection.
A more explicit signal is a structured completion JSON written to a known path:
.agent-done/blog-post.json
{
"agent": "blog-post",
"status": "complete",
"files_written": ["src/data/blog-posts/2026-06-18-example.ts"],
"build_check": "skipped",
"completed_at": "2026-06-18T07:12:44Z"
}
The IL reads this file to know exactly which files need to be cherry-picked or merged. When an agent writes its own file list, the IL does not have to diff-guess which files belong to which agent.
Phase 3: Integration — The Leader’s Serial Merge Protocol
This phase is the core of the Single-Push Protocol. The IL runs these steps in order, with no parallelism:
- Collect worktrees. List all worktrees:
git worktree list. For each completed agent, read its completion JSON to get the exact file list.
- Create an integration branch. From a clean
main: git checkout -b integrate/batch-YYYYMMDD-HHmm.
- Patch in each agent’s files, one at a time. For each agent, copy the specific files it wrote from its worktree into the integration branch working directory. Stage and commit per agent:
cp /tmp/agent-blog-post/src/data/blog-posts/2026-06-18-example.ts src/data/blog-posts/
git add src/data/blog-posts/2026-06-18-example.ts
git commit -m "integrate: blog-post agent output"
- Update barrel files. Only now — with all agent outputs present — does the IL update
src/data/blog-posts.ts, src/data/tools-registry.ts, or any other index file. One commit per barrel update.
- Run the build.
npm run build --no-lint or the project’s equivalent. If the build fails, triage the failure before proceeding. Do not push a broken build.
- Squash-merge to main.
git checkout main && git merge --squash integrate/batch-YYYYMMDD-HHmm. This collapses the integration commits into one logical changeset. Write a summary commit message that names all agents and all files touched.
The squash-merge step is optional but strongly recommended. It keeps main’s history clean — one entry per batch of agent work, not a dozen internal integration commits. If your team reviews git log on main to understand what deployed, the squash produces readable history. If you need full provenance, keep the integration branch around instead of deleting it after merge.
Conflict Resolution in Phase 3
If two agents accidentally touched the same file despite scope partitioning — a type definition file both agents imported and extended, for example — the IL resolves the conflict manually in this phase. This is explicitly not a PA responsibility. The PA’s job is to produce content; the IL’s job is to make all that content coexist. Separating these concerns means PAs can run fast and dumb while the IL runs slow and careful.
Phase 4: Ship — The One Push
After the build passes on the integration branch, there is one command:
git push origin main
One push. One CI run. One deploy. The deploy pipeline sees a single commit (or a small set of squashed commits), acquires the deploy lock once, SSHes once, builds once, swaps once.
The IL must confirm the push completed before reporting success to the operator. A pre-push hook running next build --no-lint is a second line of defense. If the hook fires and the build fails, the push is rejected at the hook level — no CI run starts, no partial deploy happens. This is exactly the behavior you want: fail fast locally, never push broken code.
The Failure Mode Matrix
Running multi-agent sessions without the Single-Push Protocol produces four observable failure modes. The table below maps each to its root cause and the Protocol phase that prevents it.
| Failure Mode |
Root Cause |
Symptom |
Protocol Phase That Prevents It |
| Double-deploy 502 |
Two pushes within 90s trigger two concurrent CI runs; both SSH to VPS |
502 gateway error lasting 2-8 minutes; watchdog auto-recovers |
Phase 4 (one push from IL only) |
| Stale image deploy |
Second CI run overwrites first with an image built from older code |
New feature missing in prod despite “successful” deploy |
Phase 4 (single squashed commit) |
| Lock deadlock |
Two CI runs contend on /tmp/wowhow-deploy.lock; second hangs |
GH Actions run stuck at “Waiting for lock” for 10+ minutes |
Phase 4 (one push = one lock acquisition) |
| Barrel file corruption |
Two agents both append to blog-posts.ts; merge produces duplicate exports |
TypeScript build error: “Duplicate identifier” |
Phase 3 (IL owns all barrel updates) |
| Partial deploy |
Agent A’s push deploys; Agent B’s push is canceled mid-run by concurrency group |
Tool page exists but is missing from sitemap; 404 on direct access |
Phase 3+4 (all content in one squashed commit) |
Coordination Without a Shared State Server
Some multi-agent frameworks use a shared Redis key or a message queue to coordinate agent completion. That is a viable approach if you already have that infrastructure. The Single-Push Protocol deliberately avoids it, because the coordination problem here is a git problem, not a messaging problem. Git’s object store is already a reliable, crash-consistent shared state. Marker files committed to worktrees are durable. The IL reading those markers is a pull-based coordination model — no broker, no heartbeats, no connection failures.
The only external dependency the protocol requires is the shared git remote (GitHub). Every agent can see the same remote when reading, and the IL is the only writer to main. This matches the trust model that GitHub branch protection rules enforce at the platform level — you can require all merges to main to go through a designated branch and a status check, which maps exactly to the IL’s integration branch and the build check in Phase 3.
Applying This to Claude Code Sessions
In practice, a Claude Code multi-agent session running the Single-Push Protocol looks like this. The operator opens three agent sessions. Sessions 1 and 2 are Produce Agents given scoped tasks with the no-push constraint. Session 3 is the Integration Leader, given the integration brief and a list of the agent worktree paths to monitor. The operator runs all three sessions in parallel using tabs or tmux panes.
Sessions 1 and 2 finish and write their marker files. The IL detects the markers (either by polling every 30 seconds with a shell loop, or by being told explicitly when both PAs report done), runs the integration sequence, runs the build, and pushes once. Total wall-clock time: roughly the time of the slowest PA plus 3-5 minutes of IL integration work. Total CI runs: one. Total 502s: zero.
The session memory note that triggered this framework: two parallel blog agents pushing independently caused three consecutive deploy failures in one session — two double-deploy 502s and one stale image. The fix was not retrying. The fix was this protocol, applied starting from the next session. No failures since.
When to Break the Protocol (and How)
There is one legitimate exception: hotfixes. If production is down and you need to push a one-line fix immediately, you do not spin up a multi-agent session. One engineer, one commit, one push. The protocol is for batch multi-agent work, not emergency patches.
There is also a degenerate case where only one agent is doing meaningful work and the others are idle. In that case, the “IL” role collapses — the single active agent is both PA and IL. It can push directly. The protocol adds overhead; apply it only when two or more agents are writing distinct files in parallel.
A useful heuristic: if your session plan has the word “parallel” in it, the Single-Push Protocol applies. If it does not, a single agent working sequentially can push normally.
Integration with the WOWHOW Deploy Stack
The WOWHOW deploy stack has several layers that the Single-Push Protocol complements without conflicting with:
- The pre-push hook (
.githooks/pre-push) runs next build --no-lint before the IL’s single push. It catches broken builds locally, before CI ever starts.
- The deploy concurrency group in
deploy.yml means even if two pushes somehow happened, only one CI run would proceed. The protocol makes this a belt-and-suspenders defense rather than the primary safeguard.
- The deploy lock (
/tmp/wowhow-deploy.lock) on the VPS is the last line of defense against a VPS-side race. With the protocol in place, the lock should never be contended during a normal session.
- The watchdog cron (
ops/watchdog.sh) auto-rolls back on three consecutive non-200 responses. With the protocol, the watchdog should trigger zero times per session.
Find the full set of WOWHOW developer tools built with this same deployment discipline, and browse the product catalog for starter kits that ship with pre-configured multi-agent coordination patterns. The Pro Vault tier includes session logs and workflow templates for the exact agent briefing format described in Phase 1.
The Protocol as a Forcing Function
The Single-Push Protocol does something beyond preventing deploy races: it forces you to think about agent scope before you start. The moment you assign tasks, you are also deciding which files each agent owns. That pre-task scope map is the thing that prevents merge conflicts in Phase 3. Without the protocol, scope is implicit and conflicts are discovered late — at merge time, with pressure to ship. With the protocol, scope is explicit and conflicts are prevented early, at task-assignment time.
The IL role is also a forcing function for integration discipline. When one person (or one agent) is responsible for assembling all outputs into a single coherent commit, that person has the full picture. They catch the case where Agent A wrote a new tool page but forgot to add it to the sitemap, or where Agent B added a blog post but did not update the blog index. The IL is the integration conscience of the session.
Start your next multi-agent session with three lines in each PA brief, three worktrees on disk, and one designated IL. The 502s stop immediately.
People Also Ask
What is the WOWHOW Single-Push Protocol for multi-agent git workflows?
The WOWHOW Single-Push Protocol is a four-phase git coordination framework for AI agent sessions. Produce Agents run in parallel in isolated git worktrees, writing files and committing locally but never pushing. A single Integration Leader then serially merges all outputs, resolves conflicts, runs the build, and makes exactly one push to main, ensuring one CI run and one deploy per batch.
How do you prevent double-deploy 502 errors when running parallel Claude Code agents?
The root fix is eliminating the second push entirely. Give each Produce Agent a git worktree with no remote push credentials. Enforce a no-push constraint in the task brief. A designated Integration Leader collects all agent outputs after they signal completion, merges them serially into one commit, and pushes once. One push triggers one CI run, removing the race condition that causes 502s.
What is a git worktree and why does it matter for multi-agent coordination?
A git worktree is an additional working directory linked to the same repository object store. Running git worktree add /tmp/agent-blog-post origin/main gives an agent its own isolated file system where it can stage and commit freely. Without remote push credentials in that worktree, the agent physically cannot push to origin, which is the entire enforcement mechanism of the Single-Push Protocol.
When should you NOT use the Single-Push Protocol?
Skip it for hotfixes: when production is down, a single engineer makes one commit and pushes directly. Also skip it when only one agent is doing meaningful work — the IL role collapses and the single agent can push normally. The protocol adds coordination overhead that only pays off when two or more agents are writing distinct files in parallel within the same session.
How does the Integration Leader handle barrel files like blog-posts.ts or tools-registry.ts?
Barrel files are explicitly off-limits to Produce Agents. Each PA writes only its own scoped data file and commits it to its worktree. The Integration Leader, after collecting all agent outputs in Phase 3, updates barrel files like src/data/blog-posts.ts and src/data/tools-registry.ts once — with the full picture of everything all PAs produced. This prevents duplicate-export TypeScript build errors that occur when two agents both append to the same index file.
Comments · 0
Beta: comments are stored locally on your device and not visible to other readers.
No comments yet. Be the first to share your thoughts.