toolkit/packages/skills/spawn-agent/SKILL.md
Spawn Claude Agent in tmux Session
npx skillsauth add stevengonsalvez/agents-in-a-box spawn-agentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Spawn a Claude Code agent in a separate tmux session with optional handover context.
/spawn-agent "implement user authentication"
/spawn-agent "refactor the API layer" --with-handover
/spawn-agent "implement feature X" --with-worktree
/spawn-agent "review the PR" --with-worktree --with-handover
#!/bin/bash
# Function: Wait for Claude Code to be ready for input
wait_for_claude_ready() {
local SESSION=$1
local TIMEOUT=30
local START=$(date +%s)
echo "Waiting for Claude to initialize..."
while true; do
# Capture pane output (suppress errors if session not ready)
PANE_OUTPUT=$(tmux capture-pane -t "$SESSION" -p 2>/dev/null)
# Check for Claude prompt/splash (any of these indicates readiness)
if echo "$PANE_OUTPUT" | grep -qE "Claude Code|Welcome back|------|Style:|bypass permissions"; then
# Verify not in error state
if ! echo "$PANE_OUTPUT" | grep -qiE "error|crash|failed|command not found"; then
echo "Claude initialized successfully"
return 0
fi
fi
# Timeout check
local ELAPSED=$(($(date +%s) - START))
if [ $ELAPSED -gt $TIMEOUT ]; then
echo "Timeout: Claude did not initialize within ${TIMEOUT}s"
echo "Capturing debug output..."
tmux capture-pane -t "$SESSION" -p > "/tmp/spawn-agent-${SESSION}-failure.log" 2>&1
echo "Debug output saved to /tmp/spawn-agent-${SESSION}-failure.log"
return 1
fi
sleep 0.2
done
}
# Parse arguments
TASK="$1"
WITH_HANDOVER=false
WITH_WORKTREE=false
shift
# Parse flags
while [[ $# -gt 0 ]]; do
case $1 in
--with-handover)
WITH_HANDOVER=true
shift
;;
--with-worktree)
WITH_WORKTREE=true
shift
;;
*)
shift
;;
esac
done
if [ -z "$TASK" ]; then
echo "Task description required"
echo "Usage: /spawn-agent \"task description\" [--with-handover] [--with-worktree]"
exit 1
fi
# Generate session info
TASK_ID=$(date +%s)
SESSION="agent-${TASK_ID}"
# Setup working directory (worktree or current)
if [ "$WITH_WORKTREE" = true ]; then
# Detect transcrypt (informational only - works transparently with worktrees)
if git config --get-regexp '^transcrypt\.' >/dev/null 2>&1; then
echo "Transcrypt detected - worktree will inherit encryption config automatically"
echo ""
fi
# Get current branch as base
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "HEAD")
# Generate task slug from task description
TASK_SLUG=$(echo "$TASK" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9 -]//g' | tr -s ' ' '-' | cut -c1-40 | sed 's/-$//')
# Source worktree utilities
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../utils/git-worktree-utils.sh"
# Create worktree with task slug
echo "Creating isolated git worktree..."
WORK_DIR=$(create_agent_worktree "$TASK_ID" "$CURRENT_BRANCH" "$TASK_SLUG")
AGENT_BRANCH="agent/agent-${TASK_ID}"
echo "Worktree created:"
echo " Directory: $WORK_DIR"
echo " Branch: $AGENT_BRANCH"
echo " Base: $CURRENT_BRANCH"
echo ""
else
WORK_DIR=$(pwd)
AGENT_BRANCH=""
fi
echo "Spawning Claude agent in tmux session..."
echo ""
# Generate handover if requested
HANDOVER_CONTENT=""
if [ "$WITH_HANDOVER" = true ]; then
echo "Generating handover context..."
# Get current branch and recent commits
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
RECENT_COMMITS=$(git log --oneline -5 2>/dev/null || echo "No git history")
GIT_STATUS=$(git status -sb 2>/dev/null || echo "Not a git repo")
# Create handover content
HANDOVER_CONTENT=$(cat << EOF
# Handover Context
## Current State
- Branch: $CURRENT_BRANCH
- Directory: $WORK_DIR
- Time: $(date)
## Recent Commits
$RECENT_COMMITS
## Git Status
$GIT_STATUS
## Your Task
$TASK
---
Please review the above context and proceed with the task.
EOF
)
echo "Handover generated"
echo ""
fi
# Create tmux session
tmux new-session -d -s "$SESSION" -c "$WORK_DIR"
# Verify session creation
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
echo "Failed to create tmux session"
exit 1
fi
echo "Created tmux session: $SESSION"
echo ""
# Start Claude Code in the session
tmux send-keys -t "$SESSION" "claude --dangerously-skip-permissions" C-m
# Wait for Claude to be ready (not just sleep!)
if ! wait_for_claude_ready "$SESSION"; then
echo "Failed to start Claude agent - cleaning up..."
tmux kill-session -t "$SESSION" 2>/dev/null
exit 1
fi
# Additional small delay for UI stabilization
sleep 0.5
# Send handover context if generated (line-by-line to handle newlines)
if [ "$WITH_HANDOVER" = true ]; then
echo "Sending handover context to agent..."
# Send line-by-line to handle multi-line content properly
echo "$HANDOVER_CONTENT" | while IFS= read -r LINE || [ -n "$LINE" ]; do
# Use -l flag to send literal text (handles special characters)
tmux send-keys -t "$SESSION" -l "$LINE"
tmux send-keys -t "$SESSION" C-m
sleep 0.05 # Small delay between lines
done
# Final Enter to submit
tmux send-keys -t "$SESSION" C-m
sleep 0.5
fi
# Send the task (use literal mode for safety with special characters)
echo "Sending task to agent..."
tmux send-keys -t "$SESSION" -l "$TASK"
tmux send-keys -t "$SESSION" C-m
# Small delay for Claude to start processing
sleep 1
# Verify task was received by checking if Claude is processing
CURRENT_OUTPUT=$(tmux capture-pane -t "$SESSION" -p 2>/dev/null)
if echo "$CURRENT_OUTPUT" | grep -qE "Thought for|Forming|Creating|Implement|*|~"; then
echo "Task received and processing"
elif echo "$CURRENT_OUTPUT" | grep -qE "error|failed|crash"; then
echo "Warning: Detected error in agent output"
echo "Last 10 lines of output:"
tmux capture-pane -t "$SESSION" -p | tail -10
else
echo "Task sent (unable to confirm receipt - agent may still be starting)"
fi
echo ""
echo "----------------------------------------------------------------"
echo "Agent spawned successfully!"
echo "----------------------------------------------------------------"
echo ""
echo "Session: $SESSION"
echo "Task: $TASK"
echo "Directory: $WORK_DIR"
echo ""
echo "To monitor:"
echo " tmux attach -t $SESSION"
echo ""
echo "To send more commands:"
echo " tmux send-keys -t $SESSION \"your command\" C-m"
echo ""
echo "To kill session:"
echo " tmux kill-session -t $SESSION"
echo ""
# Source spawn-agent-lib for enhanced metadata functions
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "$SCRIPT_DIR/../utils/spawn-agent-lib.sh" ]; then
source "$SCRIPT_DIR/../utils/spawn-agent-lib.sh"
# Save enhanced metadata with transcript path support
save_agent_metadata "$SESSION" "$TASK" "$WORK_DIR" "$WITH_HANDOVER" "$WITH_WORKTREE" "$AGENT_BRANCH"
# Try to update transcript path after a brief delay (transcript may not exist immediately)
(sleep 5 && update_agent_transcript "$SESSION" "$WORK_DIR" 2>/dev/null) &
else
# Fallback: save basic metadata if library not found
mkdir -p /.claude/agents
cat > /.claude/agents/${SESSION}.json <<EOF
{
"session": "$SESSION",
"task": "$TASK",
"directory": "$WORK_DIR",
"created": "$(date -Iseconds)",
"status": "running",
"with_handover": $WITH_HANDOVER,
"with_worktree": $WITH_WORKTREE,
"worktree_branch": "$AGENT_BRANCH"
}
EOF
fi
exit 0
Don't waste time debugging tool limits — switch immediately.
Claude Code (primary)
↓ capped / erroring / stuck after 3 retries
Codex CLI (secondary)
↓ erroring / unavailable
Manual intervention
# Check Claude Code
claude --print "reply with OK" --dangerously-skip-permissions 2>&1 | \
grep -qi "rate.limit\|capped\|exceeded\|429" && echo "CC_CAPPED" || echo "CC_OK"
# Check Codex
codex --help &>/dev/null && echo "CODEX_OK" || echo "CODEX_MISSING"
If Claude Code is unavailable, spawn with Codex instead:
# Instead of: claude --dangerously-skip-permissions
# Use: codex --yolo -m gpt-5.3-codex
tmux new-session -d -s "$SESSION" -c "$WORK_DIR"
tmux send-keys -t "$SESSION" "codex --yolo -m gpt-5.3-codex" C-m
sleep 2
tmux send-keys -t "$SESSION" -l "$TASK"
tmux send-keys -t "$SESSION" C-m
If Claude Code hits rate limits during a session:
# Kill the stuck session
tmux kill-session -t "$SESSION"
# Respawn with Codex, same worktree
SESSION="codex-${SESSION#agent-}" # rename prefix to match spawn convention
tmux new-session -d -s "$SESSION" -c "$WORK_DIR"
tmux send-keys -t "$SESSION" "codex --yolo -m gpt-5.3-codex" C-m
sleep 2
tmux send-keys -t "$SESSION" -l "$TASK"
tmux send-keys -t "$SESSION" C-m
--dangerously-skip-permissionsagent-{timestamp}tmux attach -t agent-{timestamp} to monitortmux send-keys to send additional prompts{{HOME_TOOL_DIR}}/agents/agent-{timestamp}.json/recover-sessions to resume--resume capability{{HOME_TOOL_DIR}}/agents/registry.jsonl/tmp/spawn-agent-{session}-failure.log on failures--with-worktree flag for isolated git workspaceworktrees/agent-{timestamp}-{task-slug}
worktrees/agent-1763250000-implement-user-authagent/agent-{timestamp} based on current branch/list-agent-worktrees to see all worktrees/cleanup-agent-worktree {timestamp} to remove when doneIf spawn-agent fails:
/tmp/spawn-agent-{session}-failure.logwhich claudewhich tmuxtmux list-sessionstmux attach -t agent-{timestamp}documentation
Report reflect drain spend over a time window — tokens split by cached (cache_read), uncached writes (cache_creation), and io (input+output), with a $ estimate, grouped by day / outcome / model / transcript. Reads the drainer's cost log and surfaces outlier runs and cache-reuse health (the 41.5M-token failure mode = low cache reuse + high cache writes). Use to answer "what is reflection costing me" for the last day / week.
development
Show fleet status — every claude session running on the host, merged across ainb + claude-peers broker + background jobs. Use when you need to enumerate sessions before composing an action, see which sessions have a peer registered (broker-routable) vs tmux-only, check the `summary` of each session, or pipe the list into jq for filtering. Default output: text table. Pass --format json for LLM consumption.
testing
Ordered multi-step prompts to fleet targets, ack-gated between steps via JSONL assistant-turn-end detection. Use for cycles like disconnect→reconnect→verify, or any flow where step N+1 requires step N to have completed first. The skill BLOCKS until each target's transcript shows the next assistant turn finishing OR per-step timeout fires (default 300s).
development
Center control panel — enumerate every claude session that is blocked waiting on something: a user answer (AskUserQuestion fired), an API error retry, an idle assistant turn-end with no follow-up, or an explicit WAITING: marker. Returns rich JSON with signal kind + context per session. Use this when you've stepped away from the fleet and want one place to see everything that wants your attention and answer it.