title: "Lane-Based Execution Queueing" description: "Isolate concurrent agent tasks into named queues with per-lane concurrency limits to prevent output interleaving, race conditions, and deadlocks." tags: - agent-design - tool-agnostic aliases: - execution lane isolation - named queue concurrency - per-lane concurrency limits
Lane-Based Execution Queueing¶
Organize agent task execution into named, isolated queues — each draining independently with configurable concurrency — to eliminate the three core hazards of concurrent agent systems.
The Problem¶
Concurrent agent systems face three failure modes that a single shared queue cannot prevent:
- Interleaving — simultaneous stdout/stdin writes corrupt terminal output
- Race conditions — unsynchronized shared state produces inconsistent results
- Deadlocks — cross-task dependencies with no structured resolution
Lane-based queueing addresses all three by giving each class of work its own isolated execution context.
Lane Structure¶
Each lane is an independent queue with a concurrency cap. A minimal TypeScript representation from the Clawdbot reference implementation:
type LaneState = {
queue: Task[];
active: number;
maxConcurrent: number;
draining: boolean;
};
Two operations drive each lane:
drainLane()— pumps tasks from the queue up tomaxConcurrent, then yieldsenqueueCommandInLane<T>()— schedules work and returns a promise the caller can await
Lanes never share state or communicate directly. Isolation is structural, not enforced by locks.
Lane Taxonomy¶
A typical multi-agent platform uses four lane types (nibzard/awesome-agentic-patterns):
| Lane | maxConcurrent |
Purpose |
|---|---|---|
main |
1 | Serial CLI default — one task at a time |
cron |
1 | Scheduled tasks — isolated from interactive work |
subagent |
N | Spawned agent work — parallelizable |
session:<id> |
1 | Per-user auto-reply — hierarchical ID |
The session:<id> pattern enables per-user isolation without cross-session interference. Use stable identifiers — dynamic lane proliferation with unstable IDs causes unbounded memory growth.
Hierarchical Composition¶
Nested lanes (a subagent lane spawning session lanes) prevent deadlocks through structured completion: inner lanes complete before outer lanes proceed. This replaces ad-hoc locking with a deterministic hierarchy. Direct cross-lane dependencies outside this hierarchy will deadlock.
graph TD
A[main lane] --> B[subagent lane]
B --> C[session:user1]
B --> D[session:user2]
C -->|completes| B
D -->|completes| B
B -->|completes| A
Observability¶
Each lane is independently monitorable. Key signals per lane (nibzard/awesome-agentic-patterns):
queue_size_per_lane— backlog depthactive_tasks_per_lane— in-flight countwait_time_p95— tail latency per work class
Per-lane metrics let you diagnose starvation (a busy subagent lane blocking cron tasks) without correlating across a unified queue.
Trade-offs¶
| Trade-off | Detail |
|---|---|
| Memory overhead | Idle lanes hold allocated state |
| Concurrency tuning | Each lane's maxConcurrent must be sized to available resources — over-parallelization exhausts file handles and memory |
| Starvation risk | High-priority lanes with unbounded throughput can starve low-priority ones without explicit priority controls |
This pattern draws on established foundations: Actor Model isolation (Hewitt, Bishop & Steiger, 1973), Work-Stealing scheduling (Blumofe & Leiserson, JACM 1999), and queue-based routing in Sidekiq, BullMQ, and Airflow pools. Per-queue concurrency without dedicated worker processes is a long-standing pain point in those systems — lane isolation makes the constraint explicit rather than emergent.
Relation to Worktree Isolation¶
Worktree isolation operates at the process and filesystem level — each agent gets its own working directory. Lane-based queueing operates at the task-scheduling level — each class of work gets its own queue. The two are complementary: worktrees prevent filesystem conflicts between parallel agents; lanes prevent scheduling conflicts between concurrent tasks within a platform. See Worktree Isolation and /batch and Worktrees for Claude Code's built-in worktree orchestration.
Key Takeaways¶
- Name lanes by workload class (
main,cron,subagent,session:<id>), not by caller identity - Set
maxConcurrent=1for any lane where ordering or serial execution matters - Enforce hierarchical composition — inner lanes complete before outer lanes proceed
- Expose per-lane metrics; a unified queue makes starvation invisible
- Avoid dynamic lane IDs — stable identifiers prevent memory leaks