I built a subagent delegation framework. Weighted scope checks, cognitive trap detection, context economics, the whole thing. Four specialist personas forming a virtual feature crew. It works.
Until it doesn’t.
The failure mode isn’t subtle. You’re coordinating four parallel tasks from one session. Each subagent returns results. The coordinator session — your session — has to hold all of it: the clone results, the status tracking, the synthesis, the decisions about what to do next. You’re paying for five context windows but the bottleneck is one.
So I built something different. And the tool that built it was… Claude Code.
The wall
Here’s the scenario that broke my subagent workflow. I had four independent tasks to run in parallel:
mai_kernelsPR iteration — addressing review commentslib/busOption A — pure Python rewrite experimentlib/busOption B — Docker-based approach- Blog posts about the dep graph work
These are fully independent. Different repo clones, different branches, different concerns. The textbook case for parallelism.
With subagents, the orchestrator spawns four background Task agents, each doing their thing. Beautiful in theory. But the coordinator still needs to:
- Pass full context to each agent (repo conventions, task briefs, branch info)
- Receive and parse each agent’s output
- Track status across all four
- Synthesize results into a coherent report
- Make decisions when something goes sideways
That’s a lot of tokens flowing through one funnel. Four tasks means four rounds of context accumulation in the session that matters most — yours. Hit 70-80% context usage and the coordinator starts degrading. Hit 90% and you’re doing emergency handoffs instead of actual work.
The math doesn’t close. You can’t coordinate N parallel streams from a single 200k window when each stream generates 20-30k tokens of output.
The alternative: just open more terminals
The obvious answer is embarrassingly simple. Don’t coordinate from one session. Open N independent Claude Code sessions, each with their own fresh 200k context window.
No coordinator. No synthesis bottleneck. Each session is fully autonomous — reads its own CLAUDE.md, has its own conversation history, manages its own context budget.
The trade-off is real: you lose centralized coordination. Nobody’s tracking the big picture. Nobody’s synthesizing results into a neat status table. That’s on you now — the human with the multiple terminal panes.
But you gain something better: full context budget per task, and the ability to talk to each session directly.
That last part matters more than it sounds. Subagent tasks are fire-and-forget. You spawn them, wait for results, and hope they made the right decisions. If an agent goes sideways on step 3 of a 10-step task, you don’t find out until it returns a mess and you’ve already burned the context to process it.
Interactive sessions give you speech-to-interrupt. You’re watching the output scroll in real time. You see it start going wrong. You type “stop, different approach” and redirect — in the moment, with full context, no wasted tokens.
Building the launcher
So I needed a way to spin up N parallel Claude sessions quickly. Each in its own repo clone, on its own branch, with a context prompt to get it started.
This is an iTerm2 + AppleScript problem. And I built the solution in a Claude Code session, because of course I did.
The result is two slash commands that work together:
-
/user:zparallel-work— creates the repo clones and branches. Takes a semicolon-separated list of task descriptions, derives clone paths and branch names, runsgh repo clonefor each, checks out branches. Outputs a status table. -
/user:zparallel-monitor— opens an iTerm2 tab with N panes, each running an independent Claude Code session. This is the interesting one.
The monitor command generates an AppleScript that:
- Creates a new tab in the current iTerm2 window
- Splits it into a grid of panes (layout depends on count)
- Each pane gets two commands, sequentially
Here’s the critical design choice — each pane runs Claude in interactive mode, not headless:
tell pane1
write text "cd ~/mcode/yolo-bus-pyrewrite && claude --dangerously-skip-permissions"
delay 3
write text "You are working on lib/bus pure Python rewrite. Branch: shiyuanzheng/lib-bus-pure-python. Check git status and any TASK-BRIEF.md, then continue working."
end tell
Two write text calls per pane. The first launches Claude. The second — after a 3-second delay for startup — types the context prompt as the first conversational message.
Why interactive and not -p with a direct prompt? Because -p runs headless and exits. You get output but no conversation. No ability to steer. No “wait, actually, try the other approach.” Interactive mode keeps the session open and responsive. You’re not dispatching work orders — you’re opening parallel conversations.
Why --dangerously-skip-permissions? Because autonomous work sessions shouldn’t pause every time they want to run git diff or uv run pytest. The flag name is designed to scare you, and that’s fine. These are isolated clones on local branches. The blast radius of a bad command is one directory.
The pane layout problem
iTerm2’s AppleScript interface for splitting panes is… functional. You can split vertically or horizontally. But building a grid requires splitting panes that were themselves created by splitting other panes, and the reference tracking gets weird fast.
The command handles this with a layout table:
| Panes | Layout | How |
|---|---|---|
| 2 | [1] [2] side by side |
1 vertical split |
| 3 | [1] [2] on top, [3] below |
1 vertical + 1 horizontal on pane 1 |
| 4 | [1] [2] / [3] [4] 2x2 grid |
1 vertical + 2 horizontal |
| 5 | [1] [2] [3] / [4] [5] |
2 vertical, then horizontal splits |
| 6 | [1] [2] [3] / [4] [5] [6] |
2 vertical, then 3 horizontal |
Beyond 6 panes, iTerm2 gets unusable anyway. If you have 7+ parallel tasks, you’ve got a project management problem, not a terminal layout problem.
The AppleScript for a 4-pane 2x2 grid looks like:
tell application "iTerm2"
tell current window
set newTab to (create tab with default profile)
tell newTab
tell current session
write text "cd ~/mcode/clone-1 && claude --dangerously-skip-permissions"
delay 3
write text "context prompt 1"
end tell
tell current session
set pane2 to (split vertically with default profile)
end tell
tell pane2
write text "cd ~/mcode/clone-2 && claude --dangerously-skip-permissions"
delay 3
write text "context prompt 2"
end tell
tell current session
set pane3 to (split horizontally with default profile)
end tell
tell pane3
write text "cd ~/mcode/clone-3 && claude --dangerously-skip-permissions"
delay 3
write text "context prompt 3"
end tell
tell pane2
set pane4 to (split horizontally with default profile)
end tell
tell pane4
write text "cd ~/mcode/clone-4 && claude --dangerously-skip-permissions"
delay 3
write text "context prompt 4"
end tell
end tell
end tell
end tell
The split logic: start with pane 1, split vertically to make pane 2. Then split pane 1 horizontally for pane 3, and pane 2 horizontally for pane 4. You end up with a 2x2 grid. The key insight is that horizontal splits subdivide an existing pane — so you need to reference the right pane, not just “the current session.”
Shell quoting is its own circle of hell
The context prompts get typed into AppleScript write text strings, which means they’re strings inside strings inside a shell command. Double quotes inside the AppleScript need escaping. Single quotes in the context prompt text will break the outer quoting. Newlines behave differently depending on whether iTerm2 is interpreting them as Enter keypresses or literal newlines.
The rule I landed on: keep context prompts short and quote-free. No single quotes, no double quotes in the prompt content. If you need to reference a file path with spaces (you shouldn’t, but), rephrase to avoid it. This isn’t the place for complex instructions — that’s what TASK-BRIEF.md in each clone is for.
The command also accepts flexible input formats: numbered lists, semicolon-separated, markdown tables. This sounds like over-engineering until you realize the person generating the task list might also be a Claude session that formats things its own way.
The delay 3 hack
Claude Code takes a moment to start up — loading CLAUDE.md, scanning the project, showing the initial prompt. If you type the context prompt immediately after launching, iTerm2 buffers the keystrokes and they arrive as the first message once Claude is ready.
Usually.
Sometimes the keystroke buffer gets weird and the context prompt arrives truncated or garbled. A 3-second delay is enough for Claude to finish its startup dance in every case I’ve tested. If your machine is slower, bump it to 5.
This is a hack. I’m not going to pretend it’s elegant. But it works, and the alternative — some kind of process-ready detection through AppleScript — is a yak-shaving expedition I’m not interested in.
The meta moment
Here’s the part that keeps landing for me. The /zparallel-monitor command — the AppleScript that opens N iTerm2 panes, each running an independent Claude Code session — was itself built in a Claude Code session.
I described what I wanted. Claude generated the AppleScript. I tested it, found edge cases (the 3-pane L-shape layout was wrong on the first try), described the fix, got a new version. The whole thing took maybe 20 minutes.
A tool building a tool that makes the tool more effective. This is the real unlock of AI-assisted development, and it has nothing to do with “generate a React component.” It’s automation of your own workflow — the meta-layer that most people don’t think to automate because it feels too personal, too specific to how you work.
The command accepts flexible input because I knew a Claude session might be the one generating the task list. The TASK-BRIEF.md convention exists because I knew each parallel session needs to bootstrap from a file, not from conversation history. The whole design is shaped by the constraint that AI sessions have no memory across invocations — and that constraint is the same one I’ve been building infrastructure around for months.
When to use which
This isn’t a “subagents are dead” post. They’re not. Here’s when each approach wins:
Subagents win when:
- Tasks are small (under 10k tokens of output each)
- You need synthesized results — one coherent answer from multiple perspectives
- The work is review-like: “have the architect check this design and the engineer check the implementation”
- Total parallel output fits comfortably in the coordinator’s context budget
Parallel sessions win when:
- Tasks are large and independent
- Each task needs its own deep context (reading lots of files, iterating on code)
- You want real-time steering — the ability to redirect a session mid-task
- Combined output would overwhelm a single context window
- Tasks might take 30+ minutes each
The heuristic: if you’d be comfortable with a subagent returning a 2-paragraph summary, use subagents. If each task is a full working session with exploration, iteration, and commits — open parallel terminals.
What I actually see on my screen
Four panes. Four Claude sessions. Each scrolling independently. One is iterating on PR review comments for mai_kernels. One is exploring lib/bus internals for a pure Python rewrite. One is trying the Docker approach for the same library. One is writing a blog post.
I’m not coordinating any of them. I’m monitoring — glancing at each pane, watching for the moment one of them makes a questionable decision or gets stuck. When that happens, I click into that pane and steer. “No, don’t modify that file — it’s generated. Look at the template instead.” Then I go back to watching.
It’s more like being a floor manager than a programmer. Four workers, each competent, each with their own desk and their own context. I’m not doing the work. I’m making sure the work is going in the right direction.
And the context budget? Each session is using maybe 40-50% of its 200k window. The coordinator session that would have been tracking all four would be at 95% and gasping.
The actual insight
The best AI workflow isn’t one tool doing everything. It’s the right tool at the right scale.
Subagent delegation is the right tool when the orchestrator can hold the full picture. It gives you synthesis, coordination, and a single thread of conversation. It’s elegant.
Parallel sessions are the right tool when the work outgrows a single context window. You lose elegance and gain capacity. The human becomes the orchestrator — which, in retrospect, is probably where the human should have been all along.
The meta-game — building tools that build tools — is what makes both approaches work. A slash command that opens four terminal panes isn’t impressive technology. But it collapses 5 minutes of manual setup into 3 seconds, which means you actually use it, which means parallel sessions become a practical workflow instead of a theoretical one.
Friction is the enemy of good workflows. Reduce friction enough and the workflow changes qualitatively, not just quantitatively. That’s what happened here.