Appearance
Parallel agents are only safe when each run has disjoint scope on every collision axis — share dir, port, or id, and N concurrent agents collapse back to serial plus corruption.
Principle
Isolation Enables Parallelism
Why this matters
Parallelism is a property of architecture, not discipline.
Two agents. Same work. One setup collides — the other doesn't.
agent-Awrites./repo
agent-Bwrites./repo
Serial + corruption git lock serializes commits, logs interleave at line granularity, ports collide with EADDRINUSE.
agent-Awritestrees/abc1/
agent-Bwritestrees/f0a2/
True N-wide parallel Every path, port, and log stream is pre-partitioned. No agent ever waits on another.
"Just be careful" schedules runs serially — killing the parallelism the agent layer exists for.
The three isolation axes
Filesystem. Network. Identity. Miss one, leak collisions back.
🗂️
Filesystem
One worktree per run.
trees/{adw-id}/
├── branch
└── .ports.env
Miss it → git locks serialize everything. Parallel runs look slow.
🔌
Network
One port range per run.
backend =
9100 + (md5(id) % 15)
Miss it → EADDRINUSE silently falls back. Reviewer captures wrong app.
🏷️
Identity
One ADW ID per run.
adw-id on every
commit · log · PR
· state file
Miss it → Logs interleave. Audit trails overwrite. Reports blend two runs.
All three axes must be present simultaneously.
Two out of three degrades you back to one-at-a-time.
Each axis plugs a distinct leak — they are not substitutes for each other.
Why the port hash is load-bearing
Allocation has to be a pure function of the ID.
Not sequential. Not random. Recomputable without reading state.
adw-id
f0a2-b331
→
md5 % 15
9100 + (md5 % 15)
→
backend port
9107
The state file is exactly what gets corrupted when a run crashes.
Cleanup scripts (purge_tree.sh) need to kill the right processes without reading state. The hash is the fallback — a pure function recomputes the port from the ID alone.
If cleanup needs state that crashes corrupt, cleanup itself becomes unreliable.
What breaks if you violate it
Failures look like intermittent weirdness.
ViolationWhat it looks likeWhat's actually happening
Shared
working dir
Parallel runs take the same wall-clock time as serial. "my 4-way parallel isn't any faster"
Git locks are serializing every commit, rebase, and checkout across agents.
Shared
port
Screenshots show the wrong UI state. "the reviewer says the button is gone but I see it"
Second instance hit EADDRINUSE and silently shadowed the first — reviewer captured the other run's app.
Shared
adw-id
Logs read like gibberish. "whose turn was turn 7?"
Two runs' turns interleave at line granularity. The audit trail is readable by no one.
Shared
session log
Replay produces nonsense traces. "this decision doesn't follow from the previous turn"
Two agents wrote to the same .claude/ stream — causal chain is broken.
Every symptom here is easy to misdiagnose as "the model is being weird."
The degradation truth table
Two-of-three is not mostly-parallel.
Axes present → actual behavior
🗂️ fs · 🔌 net · 🏷️ id
N-wide
All three. True parallelism.
Serial
No fs → git locks linearize.
Wrong state
No net → port shadowing.
Blind
No id → unreadable audit.
The scaling ring of agentic coding — the thing that multiplies — requires all three, simultaneously.
The discipline
Design the collision away — don't schedule around it.
Every axis where two runs could touch the same resource is a latent serialization. Partition filesystem, network, and identity up front — or pay for it in intermittent weirdness you can't reproduce.