#!/usr/bin/env bash # autoresearch tmux session orchestrator # Usage: start.sh [start|stop|status] set -euo pipefail SESSION="autoresearch" CONFIG="${HOME}/.claude/autoresearch.yaml" LOGDIR="${HOME}/.claude/autoresearch" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" get_projects() { python3 -c " import yaml, os, sys try: cfg = yaml.safe_load(open('${CONFIG}')) for p in cfg.get('projects', []): print(os.path.expanduser(p['path'])) except Exception as e: print(f'ERROR: {e}', file=sys.stderr) sys.exit(1) " } cmd_start() { if tmux has-session -t "$SESSION" 2>/dev/null; then echo "autoresearch: session '$SESSION' already running" echo " attach: tmux attach -t $SESSION" return 0 fi mkdir -p "$LOGDIR" # Window 0: overview — left: log viewer, right (30%): metrics tmux new-session -d -s "$SESSION" -n "overview" -x 220 -y 50 tmux split-window -h -t "${SESSION}:overview" -p 30 tmux send-keys -t "${SESSION}:overview.left" \ "watch -n5 python3 '${SCRIPT_DIR}/log_view.py'" Enter tmux send-keys -t "${SESSION}:overview.right" \ "watch -n10 python3 '${SCRIPT_DIR}/metrics.py'" Enter # One window per project local win=1 while IFS= read -r project_path; do local project_name project_name=$(basename "$project_path") tmux new-window -t "${SESSION}:${win}" -n "$project_name" # Start claude in the project directory tmux send-keys -t "${SESSION}:${win}" \ "cd '${project_path}' && claude --name 'autoresearch-${project_name}'" Enter # Wait for claude to initialize, then invoke the loop skill sleep 3 tmux send-keys -t "${SESSION}:${win}" \ "/ralph-loop Run one autoresearch experiment iteration per the autoresearch-loop skill. --completion-promise STOP" Enter win=$((win + 1)) done < <(get_projects) tmux select-window -t "${SESSION}:0" local project_count=$(( win - 1 )) echo "autoresearch: started — ${project_count} project window(s)" echo " attach: tmux attach -t $SESSION" } cmd_stop() { if ! tmux has-session -t "$SESSION" 2>/dev/null; then echo "autoresearch: not running" return 0 fi tmux kill-session -t "$SESSION" echo "autoresearch: stopped" } cmd_status() { if ! tmux has-session -t "$SESSION" 2>/dev/null; then echo "autoresearch: not running" return 1 fi echo "autoresearch: running" tmux list-windows -t "$SESSION" echo "" echo "Last experiment per project:" python3 - <<'PYEOF' import json, os from collections import OrderedDict log = os.path.expanduser('~/.claude/autoresearch/log.jsonl') if not os.path.exists(log): print(" (no experiments yet)") else: latest = OrderedDict() with open(log) as f: for line in f: try: e = json.loads(line) latest[e.get('project')] = e except Exception: pass for proj, e in latest.items(): kept = '✓' if e.get('kept') else '✗' desc = (e.get('description') or '')[:50] print(f" {proj}: exp {e.get('exp', '?')} {kept} — {desc}") PYEOF } case "${1:-start}" in start) cmd_start ;; stop) cmd_stop ;; status) cmd_status ;; *) echo "Usage: $(basename "$0") [start|stop|status]" exit 1 ;; esac