# Headless Launch Script Template

This template is used by the session-decomposer agent to generate a launch script
for headless execution of decomposed sessions.

## Template

```bash
#!/usr/bin/env bash
# Headless launch script — generated by ultraplan-local
# Master plan: {plan_path}
# Generated: {date}
# Sessions: {total_sessions} ({parallel_count} parallel, {sequential_count} sequential)

set -euo pipefail

# Prevent accidental API billing — remove this line if you intend to use API credits
unset ANTHROPIC_API_KEY

REPO_ROOT="$(git rev-parse --show-toplevel)"
PLAN_DIR="{session_dir}"
LOG_DIR="{session_dir}/logs"
WORKTREE_BASE="{session_dir}/worktrees"
mkdir -p "$LOG_DIR" "$WORKTREE_BASE"

# Cleanup trap — always remove worktrees on exit (success or failure)
cleanup_worktrees() {
  echo ""
  echo "=== Cleaning up worktrees ==="
  cd "$REPO_ROOT"
  for wt in "$WORKTREE_BASE"/session-*; do
    [ -d "$wt" ] && git worktree remove "$wt" --force 2>/dev/null && echo "Removed: $wt"
  done
  git worktree prune
  git branch --list "ultraplan/{slug}/*" | while read b; do
    git branch -D "$b" 2>/dev/null
  done
  rmdir "$WORKTREE_BASE" 2>/dev/null
  echo "Cleanup complete."
}
trap cleanup_worktrees EXIT

# Pre-flight: verify clean working tree
if [ -n "$(git status --porcelain)" ]; then
  echo "ERROR: Working tree is not clean. Commit or stash changes before parallel execution."
  git status --short
  exit 1
fi

echo "=== Ultraplan Headless Execution (Worktree-Isolated) ==="
echo "Plan: {plan_path}"
echo "Sessions: {total_sessions}"
echo "Repo root: $REPO_ROOT"
echo ""

# --- Wave {N}: Parallel sessions (no dependencies) ---
echo "--- Wave {N}: {description} ---"

{# For each parallel session in this wave, create worktree: }
git worktree add -b "ultraplan/{slug}/session-{n}" "$WORKTREE_BASE/session-{n}" HEAD
echo "Worktree created: session-{n} (branch: ultraplan/{slug}/session-{n})"

{# Launch session in its worktree: }
cd "$WORKTREE_BASE/session-{n}" && claude -p "$(cat "$PLAN_DIR/session-{n}-{slug}.md")" \
  --allowedTools "Read,Write,Edit,Bash,Glob,Grep" \
  --permission-mode bypassPermissions \
  > "$LOG_DIR/session-{n}.log" 2>&1 &
PID_{n}=$!
cd "$REPO_ROOT"
echo "Started session {n}: {title} (PID $PID_{n})"

{# After all parallel sessions in this wave: }
echo "Waiting for Wave {N} to complete..."
wait $PID_{n1} $PID_{n2}
echo "Wave {N} complete."
echo ""

# --- Merge wave results (sequential) ---
echo "--- Merging Wave {N} ---"
cd "$REPO_ROOT"
{# For each session in the wave, merge its branch: }
git merge --no-ff "ultraplan/{slug}/session-{n}" \
  -m "merge: ultraplan session {n} — {title}"
if [ $? -ne 0 ]; then
  echo "MERGE CONFLICT: session {n}. Conflicting files:"
  git diff --name-only --diff-filter=U
  git merge --abort
  echo "Aborting. Earlier sessions in this wave are already merged."
  exit 1
fi
git worktree remove "$WORKTREE_BASE/session-{n}" --force
git branch -d "ultraplan/{slug}/session-{n}"
echo "Merged and cleaned: session {n}"

git worktree prune

# --- Verify wave results ---
echo "--- Verifying Wave {N} ---"
{# For each session in the wave, run its exit condition commands }
{verify_commands}

# --- Wave {N+1}: Sequential sessions (depends on previous wave) ---
{# Repeat wave pattern for dependent sessions }

echo ""
echo "=== All sessions complete ==="
echo "Review logs in $LOG_DIR/"
echo "Run final verification: {final_verify_command}"
```

## Rules for the session-decomposer

When generating a launch script from this template:

1. **Group sessions into waves** by dependency. Sessions with no dependencies
   or whose dependencies are all in earlier waves can run in the same wave.
2. **Each wave waits for completion** before the next wave starts.
3. **Verification runs after each wave** — if verification fails, the script
   stops and reports which session failed.
4. **Log each session** to a separate file for debugging.
5. **Use `claude -p`** with the session spec file as the prompt.
6. **Use `--allowedTools "Read,Write,Edit,Bash,Glob,Grep"`** with
   `--permission-mode bypassPermissions` for child sessions. This limits the
   tool surface to what the executor needs and prevents agent spawning, MCP
   access, and external web requests in headless sessions.
7. **Final verification** at the end runs the master plan's verification section.
8. **Never include secrets** in the generated script.
9. **Wave verification must be independent.** After each wave completes, run
   verification commands fresh via Bash — never parse session log files as proof
   of success. Log files contain executor self-reporting, not ground truth. The
   command's exit code is the only authoritative verification signal.
10. **Billing preamble.** Prepend `unset ANTHROPIC_API_KEY` with a comment at
    the top of the script to prevent accidental API billing. Users who intend
    to use API credits can remove this line.
11. **Worktree isolation is mandatory.** Every parallel wave MUST use git
    worktrees. Each session gets its own worktree and branch. Never launch
    parallel `claude -p` sessions in the same working directory.
12. **Cleanup trap on EXIT.** The generated script MUST include a `trap` on
    EXIT that removes all worktrees (`git worktree remove --force`) and prunes
    branches, even if the script fails or is interrupted.
13. **Sequential merge after each wave.** After all sessions in a wave complete,
    merge their branches back to the main branch one at a time. Abort on merge
    conflict — do not force-resolve.
14. **Clean working tree before worktrees.** Add a `git status --porcelain`
    check at the top of the script. Fail if the working tree is dirty.
15. **Absolute paths for logs.** Log file paths must be absolute (resolved from
    `$REPO_ROOT`), not relative to any worktree.
