Swarming Claude Code and Codex in Parallel: Running Multiple Agents at Once with tmux and Git Worktrees A developer built a system to run multiple AI coding agents (Claude Code and Codex) in parallel using tmux and git worktrees. The three-layer protocol uses a plan.json declaration, an orchestrator script that creates isolated worktrees and launches tmux sessions, and worker scripts that execute tasks without interfering with each other. The approach eliminates branch conflicts and enables parallel execution of refactoring, cleanup, and testing tasks. In my previous post about a cost budget advisor https://zenn.dev/bokuwalily/articles/budget-cap-advisor , I built a mechanism that checks how much quota is left before it runs anything. This time I want to take that idea one step further: instead of cycling a single Codex through jobs one after another, run several of them at the same time as a swarm. I'll walk through the actual code for a three-layer protocol where workers declared in plan.json are expanded by orchestrate-worktrees.js into a tmux session plus git worktrees, so each Codex runs in parallel without interfering with the others. When you run Codex jobs one after another on a single repository, you hit issues like: Separating branches with git worktree reduces the conflict risk to zero. Combining that with tmux to launch everything in parallel is the design for this post. plan.json ← declaration layer what goes to which worker ↓ orchestrate-worktrees.js ← orchestrator layer creates worktrees, launches tmux ↓ orchestrate-codex-worker.sh ← worker layer runs Codex, writes artifacts The orchestrator doesn't know about the workers, and the workers don't know about each other. Artifacts are consolidated into three files under .orchestration/{session}/{worker slug}/ . | File | Role | |---|---| task.md | Work instructions for the worker generated by the orchestrator | status.md | State: not started → running → completed / failed | handoff.md | Codex output + git status written by the worker | { "sessionName": "refactor-sprint", "repoRoot": "~/my-project", "worktreeRoot": "~/worktrees", "coordinationRoot": "~/my-project/.orchestration", "baseRef": "HEAD", "replaceExisting": true, "launcherCommand": "bash ~/.claude/scripts/orchestrate-codex-worker.sh {task file} {handoff file} {status file}", "seedPaths": "package.json", "tsconfig.json" , "workers": { "name": "api-types", "task": "src/api/ のレスポンス型を zod スキーマに移行する。既存のテストが全て通ること。", "seedPaths": "src/api/" }, { "name": "ui-cleanup", "task": "src/components/ 内の PropTypes を削除し TypeScript 型に一本化する。", "seedPaths": "src/components/" }, { "name": "test-coverage", "task": "src/utils/ のユニットテストを追加しカバレッジ 80% 以上にする。", "seedPaths": "src/utils/" } } seedPaths can be specified in two places: globally and per worker. The global package.json / tsconfig.json are copied into every worker's worktree, while a worker's own seedPaths are dropped only into that worker. The entry point has three modes. ① dry-run default : show what would be created, as JSON node scripts/orchestrate-worktrees.js plan.json ② --write-only: no worktree creation; only writes task.md / status.md / handoff.md node scripts/orchestrate-worktrees.js plan.json --write-only ③ --execute: full run, including worktree creation and tmux launch node scripts/orchestrate-worktrees.js plan.json --execute When you invoke --execute , executePlan from lib/tmux-worktree-orchestrator.js runs, processing in this order: git rev-parse --is-inside-work-tree and tmux -V replaceExisting: true , clean up existing sessions, worktrees, and branches materializePlan writes the three-file set under .orchestration/ git worktree add -b