Agent Spawn
Spawn AI coding agents (Claude Code, Codex) in new Ghostty terminals via AppleScript, wrapped in tmux for output capture. Requires Ghostty 1.3.0+, tmux, and macOS.
Spawn
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh [OPTIONS]| Flag | Description | Default |
|---|---|---|
-a, --agent AGENT | Agent preset: claude, codex | claude |
-d, --directory DIR | Working directory | Current dir |
-p, --prompt PROMPT | Initial prompt for the agent | None |
-m, --mode MODE | window, tab, split-right, split-down | window |
-r, --resume ID | Resume conversation by ID (claude only) | None |
-c, --command CMD | Full custom command (overrides --agent) | Resolved from --agent preset |
-n, --name NAME | Tmux session name | agent-<timestamp> |
-w, --worktree | Force worktree isolation (claude only) | Auto (on in git repos) |
--no-worktree | Disable worktree isolation | — |
--no-park | Disable AeroSpace workspace auto-allocation | — |
--workspace NAME | Override auto-allocated workspace | Auto (3+) |
Monitor
agent-spawn.sh --status # List all agent sessions with workspace occupancy
agent-spawn.sh --focus NAME # Switch to agent's AeroSpace workspace
agent-spawn.sh --peek NAME # Last 50 lines of output
agent-spawn.sh --peek NAME -l 200 # Last 200 lines
agent-spawn.sh --send NAME [TEXT] # Send text + Enter (or bare Enter)
agent-spawn.sh --kill NAME # Kill tmux session only
agent-spawn.sh --close NAME # Kill tmux + close Ghostty window
agent-spawn.sh --close-all # Close all agent sessions and windowsModes
| Mode | When to Use |
|---|---|
window | Independent task in a separate window |
tab | Related task, keep in same window |
split-right | Side-by-side view, monitor while working |
split-down | Stacked view, log output below |
Agent Presets
The --agent flag selects a CLI with the correct unattended/yolo flags. Use -c to override with a fully custom command.
| Agent | Command |
|---|---|
claude (default) | claude --dangerously-skip-permissions --model opus |
codex | codex --dangerously-bypass-approvals-and-sandbox |
Feature support by agent
| Feature | claude | codex |
|---|---|---|
Worktree isolation (-w) | Yes (auto-detected) | No |
Resume (-r) | Yes | No |
Prompt (-p) | Yes | Yes |
Examples
# Claude Code (default agent)
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-d ~/Projects/my-api \
-p "fix the tests"
# Codex
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
--agent codex \
-d ~/Projects/my-api \
-p "fix the tests"
# Custom command (full override, no preset applied)
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-c "claude --dangerously-skip-permissions --model sonnet" \
-d ~/Projects/my-api \
-p "quick review"Examples
Spawn with prompt
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-d ~/Projects/my-api \
-p "fix the failing tests in pkg/auth"Named session for monitoring
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-n api-review \
-d ~/Projects/my-api \
-p "review error handling"
# Check progress
agent-spawn.sh --peek api-review
# Send follow-up prompt
agent-spawn.sh --send api-review "also check the retry logic"Multiple parallel agents
for dir in pkg/auth pkg/api pkg/storage; do
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-m tab \
-n "review-$(basename $dir)" \
-d ~/Projects/my-api \
-p "review $dir for error handling issues"
done
# Monitor all
agent-spawn.sh --status
agent-spawn.sh --peek review-auth
agent-spawn.sh --peek review-apiResume a previous conversation
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-r 01abc123-def4-5678-9012-abcdef345678Session Naming Convention
Always use descriptive -n names for spawned agents. Opaque default names like agent-1710329481 are meaningless in tmux ls output — you cannot tell which session is doing what without peeking into each one.
Keep the full -n name under 20 characters. Tmux truncates long session names in the status bar, making them unreadable. Use short slugs — 1–2 words is ideal.
Format
Use a prefix that encodes the work type, followed by a short slug:
| Prefix | When | Example |
|---|---|---|
task-<id>-<slug> | Working a task queue item | task-43-naming |
pr-<n>-<slug> | Reviewing or working a PR | pr-87-auth-flow |
fix-<slug> | Bug fix | fix-retry-timeout |
feat-<slug> | Feature work | feat-webhooks |
res-<slug> | Research / exploration | res-rate-limits |
Slug rules: 1–2 words, lowercase, hyphenated. Full name (prefix + slug) must be under 20 characters.
Before / After
# BAD — opaque names, impossible to manage at scale
$ tmux ls
agent-1710329481: 1 windows (created Fri Mar 13 09:31:21 2026)
agent-1710329522: 1 windows (created Fri Mar 13 09:32:02 2026)
agent-1710329558: 1 windows (created Fri Mar 13 09:32:38 2026)
agent-1710329601: 1 windows (created Fri Mar 13 09:33:21 2026)
# GOOD — short descriptive names, no truncation in tmux status bar
$ tmux ls
task-43-naming: 1 windows (created Fri Mar 13 09:31:21 2026)
pr-87-auth-flow: 1 windows (created Fri Mar 13 09:32:02 2026)
fix-retry-timeout: 1 windows (created Fri Mar 13 09:32:38 2026)
res-rate-limits: 1 windows (created Fri Mar 13 09:33:21 2026)Usage
# Task from the queue
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-n task-43-naming \
-d ~/Projects/claude-skills \
-p "/dev-task-queue claim and work on task #43"
# PR review
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-n pr-87-auth-flow \
-d ~/Projects/my-api \
-p "review PR #87"
# Peek and send by meaningful name
agent-spawn.sh --peek task-43-naming
agent-spawn.sh --send pr-87-auth-flow "also check error paths"Task Queue Transcript Linking
When spawning agents to work on task queue items, always include transcript linking in the completion step of the prompt. Without this, --jsonl-path is never passed to complete_task.py and the conversation transcript is lost.
The agent's completion step must:
- Find its transcript
.jsonlfile (most recently modified file in~/.claude/projects/) - Pass
--jsonl-pathtocomplete_task.py
Always include this completion block in task queue prompts:
After implementing, push your branch, create a PR, and complete the task with transcript linked:
JSONL_PATH=$(ls -t ~/.claude/projects/*/*.jsonl 2>/dev/null | head -1)
python3 ~/.agent-task-queue/scripts/complete_task.py <ID> --jsonl-path "$JSONL_PATH" --notes "PR: <url>"Full task queue spawn template
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-n task-43-naming \
-d ~/Projects/claude-skills \
-p 'You are working on task #43 from the agent task queue.
FIRST: Create a git worktree to work in isolation:
git worktree add .claude/worktrees/task-43-naming -b task-43-naming
cd .claude/worktrees/task-43-naming
Then claim the task:
python3 ~/.agent-task-queue/scripts/claim_task.py 43 --session-id $(uuidgen)
THE TASK: <description>
After implementing, push your branch, create a PR, and complete the task with transcript linked:
JSONL_PATH=$(ls -t ~/.claude/projects/*/*.jsonl 2>/dev/null | head -1)
python3 ~/.agent-task-queue/scripts/complete_task.py 43 --jsonl-path "$JSONL_PATH" --notes "PR: <url>"'Worktree Isolation
When spawning into a git repository, each agent automatically gets an isolated git worktree via Claude Code's /worktree command. This prevents branch conflicts and dirty working tree issues when multiple agents work in the same repo concurrently.
Behavior:
- Auto (default): Detects if the target directory is a git repo. If yes, enables worktree isolation.
-w, --worktree: Force worktree isolation on (even if auto-detect fails).--no-worktree: Disable worktree isolation (agent works directly on the repo).
The script prepends /worktree to the agent's prompt, so Claude Code creates a temporary worktree branch before starting work. Each agent gets its own branch and working directory — no coordination needed.
# Auto-enabled in git repos (default)
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
-d ~/Projects/my-api \
-p "fix the failing tests"
# Explicitly disable worktree for a quick read-only task
bash ~/.claude/skills/dev-agent-spawn/scripts/agent-spawn.sh \
--no-worktree \
-d ~/Projects/my-api \
-p "explain the auth flow"AeroSpace Workspace Integration
When AeroSpace is installed, spawned agents are automatically moved to dedicated workspaces to keep your main workspace clean.
Allocation Rules
- Workspaces 1–3 are reserved for the user/orchestrator
- Agent workspaces start at workspace 4 and go up (4, 5, 6,...)
- Max 3 agents per workspace (AeroSpace tiles them as a readable 3-way split)
- When workspace 4 is full, the next agent goes to workspace 5, etc.
- Dead sessions (tmux exited) don't count toward occupancy
Override or Disable
# Force agent to workspace 9
agent-spawn.sh --workspace 9 -n task-99-hotfix -d ~/Projects/app -p "urgent fix"
# Keep agent in the current workspace (old behavior)
agent-spawn.sh --no-park -n res-quick -d ~/Projects/app -p "quick lookup"Navigation
# Switch to an agent's workspace
agent-spawn.sh --focus task-43-naming
# See workspace occupancy for all agents
agent-spawn.sh --statusStatus Output
NAME WORKSPACE TMUX WINDOW
---- --------- ---- ------
task-43-naming 3 (2/3) attached window-aea3a4600
task-65-aero 3 (2/3) attached window-789908c00
pr-158-mise 4 (1/3) attached window-8e7de2700
res-quick - attached window-44aabb100Graceful Degradation
If AeroSpace is not installed, workspace allocation is silently skipped. All other features (tmux, peek, send, close) work unchanged.
How It Works
- Activate Ghostty (launches if not running)
- Create surface configuration with the target working directory
- Open a new window/tab/split using that configuration
- Send a tmux command that creates a named session and runs claude inside it
- Detect the new AeroSpace window by diffing
aerospace list-windowsbefore/after spawn - Move the window to the allocated workspace via
aerospace move-node-to-workspace
The input text + send key enter pattern is used instead of the command surface config property. The command property replaces the login shell, skipping .zshrc/.zprofile and losing PATH setup.
Tmux wrapping enables --peek (capture-pane), --send (send-keys), and --kill (kill-session) without Ghostty API limitations.
Troubleshooting
| Problem | Fix |
|---|---|
| "execution error" from osascript | Grant Automation permission: System Settings > Privacy & Security > Automation > allow your terminal to control Ghostty |
| Ghostty not found | Install Ghostty 1.3.0+ from https://ghostty.org |
| Claude not found in new terminal | Ensure claude is on PATH in your shell profile (.zshrc) |
| Split opens but no command runs | Increase delay — edit delay 0.3 in script if shell init is slow |
--peek shows empty | Session may not have started yet — wait a moment and retry |
| Agent not moving to workspace | Ensure AeroSpace is installed and running (aerospace --version) |