Skip to content

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.