#!/usr/bin/env bash # Spawn 7 claude sessions in tmux, one per language loop. # Each runs in its own git worktree rooted at /root/rose-ash-loops/, # on branch loops/. No two loops share a working tree, so there's # zero risk of file collisions between languages. # # Usage: ./scripts/sx-loops-up.sh [interval] # interval defaults to self-paced (omit to let model decide) # # After the script prints done: # tmux a -t sx-loops # Ctrl-B + to switch (0=lua ... 6=hs) # Ctrl-B + d to detach (loops keep running, SSH-safe) # # Stop: ./scripts/sx-loops-down.sh # Wipe worktrees too: ./scripts/sx-loops-down.sh --clean set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" SESSION="sx-loops" WORKTREE_BASE="/root/rose-ash-loops" INTERVAL="${1:-}" # e.g. "15m", or empty for self-paced BOOT_WAIT=20 if tmux has-session -t "$SESSION" 2>/dev/null; then echo "Session '$SESSION' already exists." echo " Attach: tmux a -t $SESSION" echo " Kill: ./scripts/sx-loops-down.sh" exit 1 fi declare -A BRIEFING=( [lua]=lua-loop.md [prolog]=prolog-loop.md [forth]=forth-loop.md [erlang]=erlang-loop.md [haskell]=haskell-loop.md [js]=loop.md [hs]=hs-loop.md ) ORDER=(lua prolog forth erlang haskell js hs) mkdir -p "$WORKTREE_BASE" echo "Preparing per-language worktrees under $WORKTREE_BASE ..." for lang in "${ORDER[@]}"; do wt="$WORKTREE_BASE/$lang" branch="loops/$lang" if [ -d "$wt/.git" ] || [ -f "$wt/.git" ]; then echo " $lang: worktree exists at $wt" else # Create or reset the branch at current architecture HEAD, then add worktree if git show-ref --verify --quiet "refs/heads/$branch"; then git worktree add "$wt" "$branch" >/dev/null else git worktree add -b "$branch" "$wt" architecture >/dev/null fi echo " $lang: worktree created at $wt on $branch" fi done # Create tmux session with 7 windows, each cwd in its worktree tmux new-session -d -s "$SESSION" -n "${ORDER[0]}" -c "$WORKTREE_BASE/${ORDER[0]}" for lang in "${ORDER[@]:1}"; do tmux new-window -t "$SESSION" -n "$lang" -c "$WORKTREE_BASE/$lang" done echo "Starting 7 claude sessions..." for lang in "${ORDER[@]}"; do tmux send-keys -t "$SESSION:$lang" "claude" C-m done echo "Waiting ${BOOT_WAIT}s for claude to boot..." sleep "$BOOT_WAIT" for lang in "${ORDER[@]}"; do briefing="${BRIEFING[$lang]}" if [ -n "$INTERVAL" ]; then preamble="/loop $INTERVAL " else preamble="/loop " fi cmd="${preamble}Read plans/agent-briefings/$briefing and do ONE iteration per fire: pick the first unchecked [ ] from the plan, implement, test, commit with a short factual message, tick the box, append one dated line to the Progress log (newest first), then stop. You are on branch loops/$lang in worktree /root/rose-ash-loops/$lang; push commits to origin/loops/$lang (never main). Stay strictly in the briefing's scope." tmux send-keys -t "$SESSION:$lang" "$cmd" # tiny pause, then a second Enter — Claude's input box sometimes eats the first newline as a soft break sleep 0.5 tmux send-keys -t "$SESSION:$lang" Enter done echo "" echo "Done. 7 loops started in tmux session '$SESSION', each in its own worktree." echo "" echo " Attach: tmux a -t $SESSION" echo " Switch: Ctrl-B <0..6> (0=lua 1=prolog 2=forth 3=erlang 4=haskell 5=js 6=hs)" echo " List: Ctrl-B w" echo " Detach: Ctrl-B d" echo " Stop: ./scripts/sx-loops-down.sh" echo " Capture: tmux capture-pane -t $SESSION: -p | tail -40" echo "" echo "Worktrees:" git worktree list | grep -E "rose-ash-loops/" || true