· 7 min read

How to Run Multiple Claude Code Agents in Parallel on macOS (Without Losing Track)

Git worktrees, one terminal per repo, hooks for notifications, and a window manager that knows which agent is waiting on you.

The problem shows up around agent number three

One Claude Code session is easy. You type, it works, you read. Two is fine: one runs a migration while you review the other's diff. Somewhere around three, the workflow breaks in a specific way. Not because the agents get worse, but because you do. Every terminal looks the same. You cmd-tab through five identical windows to find the one that asked "Allow Bash(rm -rf ...)?" four minutes ago, and it has been sitting there the whole time while the other four also finished.

The waiting is the expensive part. An agent blocked on a permission prompt costs nothing in tokens and everything in wall-clock time. Running agents in parallel only pays off if you notice the moment one stops.

This guide is the setup I use on macOS to run four or five Claude Code sessions at once and stay on top of them. Parts of it are plain git and shell. The last part is where TileOrg comes in, because I built it for this.

Step 1: one git worktree per agent

Two agents editing the same checkout will step on each other. One of them runs git checkout -b while the other has half a refactor in the working tree, and now both are confused. Git worktrees solve this cleanly. Each worktree is a separate directory with its own branch, sharing one .git object store, so cloning five times is unnecessary.

cd ~/code/api
git worktree add ../api-auth -b feat/auth
git worktree add ../api-billing -b feat/billing
git worktree add ../api-perf -b perf/query-cache

Now you have ~/code/api-auth, ~/code/api-billing and ~/code/api-perf, each on its own branch. Start one agent in each. When a branch is merged, git worktree remove ../api-auth and the directory is gone.

Two habits make this work. Name the worktree directory after the task, not the branch type, so the terminal title tells you something. And keep a CLAUDE.md at the repo root; every worktree gets it for free, so all five agents start with the same context.

Step 2: one terminal window per worktree, not one tab

Tabs are the trap. Five tabs in one iTerm2 window means one window title, one Dock icon, and no way for macOS or any tool to tell the agents apart. Open a separate window per worktree. It feels wasteful for about a day, and then you stop noticing.

Separate windows give you three things. Each has its own title, and Claude Code updates that title as it works, which turns out to matter a lot in step 4. Each can be tiled next to the editor and browser for the same task. And each can be assigned to a project, which is the whole point of step 5.

If your terminal supports it, set the window title from the shell before launching the agent so it survives whatever the agent does to it:

cd ~/code/api-auth && printf '\033]0;api-auth\007' && claude

Ghostty, iTerm2, kitty, Warp and Terminal.app all honor that escape sequence. VS Code's integrated terminal does too, though the window title is the editor's.

Step 3: Claude Code hooks for the moments that matter

Claude Code can run a shell command on specific events. Two of them are the ones you care about when running agents in parallel: Notification, which fires when the agent hits a permission prompt or sits idle waiting for input, and Stop, which fires when it finishes a turn. Wire those to a desktop notification and you no longer need to look at the terminals at all.

The minimal version, in ~/.claude/settings.json:

{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"needs input\" with title \"Claude Code\"'"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"finished\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

This works, and it is also where the DIY approach hits a wall. The notification says "Claude Code needs input" and nothing else. Which one? The hook receives a JSON payload on stdin with cwd and session_id, so you can extract the directory and put it in the notification text. That gets you "api-auth needs input". What it cannot do is take you there. You still have to find the window.

It also does not help with Codex, Gemini CLI, aider or opencode, none of which have an equivalent hook system as of this writing. If you mix agents, hooks cover one of them.

Step 4: infer status from what is already visible

Every terminal agent leaks state through two channels without being asked. The window title changes as it works (Claude Code writes its current activity there, aider shows the model and files). And CPU usage drops to zero when it is blocked on a prompt. You can watch both from outside the process.

That is what TileOrg does. Every 3 seconds it walks the process tree under each terminal window on your Mac, finds claude, codex, gemini, aider and opencode processes, and reads the title of the window they live in. From the title and CPU pattern it assigns each one a status: working, waiting, idle, errored or done. If you let it install its Claude Code hooks (one click in settings, it merges into your existing settings.json without touching your other hooks), the Claude Code sessions get exact status from the events instead of inference.

The result is a menu bar icon with a green dot while everything is working and an orange dot the moment any agent needs you. Click it and you get every agent listed with its status. No polling terminals, no tab-cycling.

Step 5: group each worktree's windows into a project

Notification alone still leaves the jump. You know api-auth needs you; now you need its terminal, and probably the editor and the browser tab with the PR next to it. This is where a window manager that thinks in projects instead of windows earns its place.

In TileOrg you create a project per worktree (⌃⌥N), then open the picker (⌃⌥Space) and assign the terminal, the editor window and whatever browser window belongs to that task. Tile them into a pane once. From then on ⌃⌥1 through ⌃⌥9 swaps the whole context in under 100 ms, and the agent detected inside that terminal is attached to that project. The menu bar list groups agents by project, so "Claude Code, waiting" appears under "api-auth", not floating in a flat list.

The keystroke that closes the loop is ⌃⌥A. It switches to the project of the agent that needs attention and focuses its terminal window. If two are waiting, it goes to the one that has waited longest. Answer the prompt, press it again, and you are at the next one. That is the whole workflow for handling five parallel agents: work on whatever you are working on, hear the notification, press one key, answer, go back.

What this looks like on a normal afternoon

Three worktrees, three projects. Project 1 is a schema migration with Claude Code, a database client and the docs for the ORM. Project 2 is a frontend refactor with Codex in a Ghostty window and the dev server in Chrome. Project 3 is a bug hunt with aider and a log viewer. I am reading the migration diff in project 1. The menu bar dot turns orange. ⌃⌥A takes me to project 2, where Codex wants permission to run the test suite. I approve, ⌃⌥1 brings the migration back exactly as I left it. Total detour: eight seconds.

Without this setup the same interruption used to be a minute of cmd-tabbing, plus the twenty minutes I did not notice the prompt at all.

Things that still go wrong

Status inference from titles is a heuristic. Terminals that do not pass through title sequences (some tmux configurations) fall back to the CPU signal, which lags a few seconds. An agent that runs a long test suite can look "working" while it is really waiting for a subprocess. The hooks path avoids both for Claude Code; for the other agents, expect the occasional false idle.

Worktrees share one object store, so git gc or a rebase in one can briefly confuse another agent mid-fetch. Rare, but it happens. And five agents is a practical ceiling for me, not because of the tooling but because reviewing five diffs at once is where I become the bottleneck.

If you want to see how TileOrg's project grouping compares with tiling-only tools, the macOS window manager roundup covers Rectangle, Amethyst and yabai. For the non-agent side of organizing a Mac around projects, read how to organize your macOS workspace for deep work. Or go straight to the TileOrg homepage and try it for 30 days.

Try TileOrg

30-day free trial. All features included.

Download TileOrg

v0.2.0 · 3.3 MB · macOS 14 Sonoma