From 1601ad75c0c47b58be5a54c2fb903a8dd28e78de Mon Sep 17 00:00:00 2001 From: Prateek Date: Fri, 13 Feb 2026 15:44:17 +0530 Subject: [PATCH] feat: add agent-orchestrator (ao) as a self-hosting project - Create claude-ao-session: worktree-based session manager for ao (Linear tickets, GitHub PRs, AO_SESSION env var) - Add ao|agent-orchestrator case to all shared scripts: claude-batch-spawn, claude-spawn, claude-status, claude-open-all, claude-review-check, claude-bugbot-fix - Rewrite CLAUDE.orchestrator.md with full self-hosting instructions: commands reference, workflows, architecture, tips - Session prefix: ao, metadata: ~/.ao-sessions/, worktrees: ~/.worktrees/ao/ Co-Authored-By: Claude Sonnet 4.5 --- CLAUDE.orchestrator.md | 248 +++++++++++++++++++++++++----------- scripts/claude-ao-session | 235 ++++++++++++++++++++++++++++++++++ scripts/claude-batch-spawn | 8 +- scripts/claude-bugbot-fix | 7 +- scripts/claude-open-all | 10 +- scripts/claude-review-check | 6 +- scripts/claude-spawn | 9 +- scripts/claude-status | 68 +++++++++- 8 files changed, 506 insertions(+), 85 deletions(-) create mode 100755 scripts/claude-ao-session diff --git a/CLAUDE.orchestrator.md b/CLAUDE.orchestrator.md index 23241f52c..481ecba47 100644 --- a/CLAUDE.orchestrator.md +++ b/CLAUDE.orchestrator.md @@ -1,90 +1,158 @@ -# CLAUDE.local.md - Agent Orchestrator Development +# CLAUDE.orchestrator.md - Agent Orchestrator -You are working on **agent-orchestrator**, an open-source multi-agent orchestrator for Claude Code. This tool manages parallel coding agents across projects from a single control plane. +You are the **orchestrator agent** for the agent-orchestrator project. You manage parallel Claude Code agents that build this very tool (dog-fooding). -> **Dog-fooding**: This orchestrator is being built using a copy of itself. The `~/` home directory orchestrator manages sessions that work on this very repo. +## Project Info -## Project Overview +- **Repo**: ComposioHQ/agent-orchestrator (GitHub) +- **Issue Tracker**: Linear (AO team) +- **Main Branch**: `main` +- **Session Prefix**: `ao` +- **Session Naming**: `ao-1`, `ao-2`, etc. +- **Metadata Dir**: `~/.ao-sessions/` +- **Worktrees**: `~/.worktrees/ao/` -Agent Orchestrator lets you: -- Spawn and manage dozens of Claude Code agents working in parallel -- Track progress via a live HTML dashboard with PR status, CI checks, and merge actions -- Send commands to agents, kill/cleanup sessions, and view terminals in-browser -- Organize agents by project with worktree-based isolation +## Quick Start + +```bash +# See all sessions +~/claude-status + +# Spawn sessions for Linear tickets +~/claude-batch-spawn ao AO-1 AO-2 AO-3 + +# Spawn single session (new iTerm2 tab) +~/claude-spawn ao AO-1 + +# List ao sessions +~/claude-ao-session ls + +# Attach to a session +~/claude-ao-session attach ao-1 + +# Kill a session +~/claude-ao-session kill ao-1 + +# Cleanup completed work (merged PRs / done tickets) +~/claude-ao-session cleanup +``` + +## Agent Hierarchy + +``` +~/agent-orchestrator/ <- YOU (Orchestrator) +└── ao agents <- Managed via ~/claude-ao-session + ├── ao-1 (~/.worktrees/ao/ao-1) + ├── ao-2 (~/.worktrees/ao/ao-2) + └── ao-N +``` + +## Commands Reference + +| Task | Command | +|------|---------| +| **See all sessions** | `~/claude-status` | +| **Batch spawn** | `~/claude-batch-spawn ao AO-1 AO-2 AO-3` | +| **Single spawn** | `~/claude-spawn ao AO-1` | +| **List sessions** | `~/claude-ao-session ls` | +| **Attach** | `~/claude-ao-session attach ao-1` | +| **Kill** | `~/claude-ao-session kill ao-1` | +| **Cleanup** | `~/claude-ao-session cleanup` | +| **Open all tabs** | `~/claude-open-all ao` | +| **PR review fixes** | `~/claude-review-check ao` | +| **Peek at screen** | `tmux capture-pane -t "ao-1" -p -S -30` | +| **Send message** | `~/send-to-session ao-1 "your message"` | +| **Spawn with context** | `~/claude-spawn-with-context ao AO-1 /tmp/prompt.txt --open` | + +## Typical Workflows + +### Spawn Work for Linear Tickets +```bash +# 1. Check what's already running +~/claude-status + +# 2. Spawn sessions (auto-deduplicates) +~/claude-batch-spawn ao AO-1 AO-2 AO-3 + +# 3. Open all in iTerm2 +~/claude-open-all ao +``` + +### Check Progress +```bash +~/claude-status # Quick overview +~/claude-ao-session ls # AO sessions only +tmux capture-pane -t "ao-1" -p -S -30 # Peek at session +``` + +### Ask a Session to Do Something +```bash +# Short message +~/send-to-session ao-1 "address the unresolved comments on your PR" + +# Long prompt via file +cat > /tmp/prompt.txt << 'PROMPT' +Your detailed instructions here... +PROMPT +~/claude-spawn-with-context ao AO-1 /tmp/prompt.txt --open +``` + +### Cleanup +```bash +~/claude-ao-session cleanup # Kills sessions with merged PRs / completed tickets +~/claude-ao-session kill ao-3 # Kill specific session +``` + +## Session Data + +### Metadata Files +Each session has a flat file at `~/.ao-sessions/ao-N`: +``` +worktree=/Users/equinox/.worktrees/ao/ao-1 +branch=feat/AO-1 +status=starting +issue=https://linear.app/composio/issue/AO-1 +pr=https://github.com/ComposioHQ/agent-orchestrator/pull/5 +``` + +### Environment Variables (inside sessions) +- `AO_SESSION` — e.g., `ao-1` +- `LINEAR_API_KEY` — required for cleanup to check ticket status ## Repo Structure ``` agent-orchestrator/ -├── scripts/ # Core orchestrator scripts -│ ├── claude-status # Unified dashboard (CLI) -│ ├── claude-batch-spawn # Spawn multiple sessions at once -│ ├── claude-spawn # Spawn single session in new terminal tab -│ ├── claude-dashboard # HTML dashboard with live PR status (web UI) -│ ├── claude-open-all # Open terminal tabs for all sessions -│ ├── claude-review-check # Trigger agents to address PR review comments -│ ├── claude-bugbot-fix # Fix bugbot comments across sessions -│ ├── claude-session-status # Health monitor (working/idle/blocked/waiting) +├── scripts/ # All orchestrator scripts +│ ├── claude-ao-session # Session manager for this project +│ ├── claude-status # Unified CLI dashboard +│ ├── claude-batch-spawn # Spawn multiple sessions +│ ├── claude-spawn # Spawn single session (new tab) +│ ├── claude-dashboard # HTML dashboard with live PR status +│ ├── claude-open-all # Open iTerm2 tabs for sessions +│ ├── claude-review-check # Trigger PR review fixes +│ ├── claude-bugbot-fix # Fix bugbot comments +│ ├── claude-session-status # Health monitor │ ├── claude-spawn-with-context # Spawn with custom prompt file │ ├── claude-spawn-on-branch # Spawn on existing branch -│ ├── claude-spawn-with-prompt # Spawn and deliver prompt after ready +│ ├── claude-spawn-with-prompt # Spawn + deliver prompt after ready │ ├── get-claude-session-info # Extract session metadata from tmux -│ ├── open-tmux-session # Switch to terminal tab for tmux session +│ ├── open-tmux-session # Switch to terminal tab │ ├── open-iterm-tab # iTerm2 tab management -│ ├── notify-session # iTerm2 notifications from sessions -│ ├── send-to-session # Smart message delivery to tmux sessions -│ ├── claude-integrator-session # Example: project session manager (Linear/integrator) -│ └── claude-splitly-session # Example: project session manager (GitHub Issues/SafeSplit) -├── CLAUDE.local.md # This file (dev instructions) -├── CLAUDE.md # Repo-level instructions for contributors -└── README.md # Project README +│ ├── notify-session # iTerm2 notifications +│ ├── send-to-session # Smart message delivery to sessions +│ ├── claude-integrator-session # Example: Linear-based session manager +│ └── claude-splitly-session # Example: GitHub Issues session manager +├── CLAUDE.orchestrator.md # This file (orchestrator instructions) +├── CLAUDE.md # Repo instructions for contributors +└── README.md # Project README ``` -## Current State - -The scripts in `scripts/` are direct copies from the production orchestrator (`~/`). They currently have hardcoded paths and project-specific references (integrator, splitly). The work ahead is to: - -1. **Generalize** — Remove hardcoded project names, make scripts project-agnostic -2. **Configuration** — Add a config file (e.g., `orchestrator.yaml`) that defines projects, repos, branches, issue trackers -3. **Installation** — Create an install script that symlinks scripts to `~/` or adds them to PATH -4. **Documentation** — Write a comprehensive README with setup guide and examples -5. **Self-hosting** — Make this repo use its own orchestrator for development - -## Project Info - -- **Repo**: ComposioHQ/agent-orchestrator (GitHub) -- **Issue Tracker**: Linear -- **Visibility**: Internal (ComposioHQ org) -- **Everything runs locally** — no Datadog, no cloud infra - -## Development Workflow - -```bash -# This repo is managed by the home directory orchestrator -# Sessions are spawned via: -~/claude-spawn-with-context i TICKET /tmp/prompt.txt --open - -# Linear tickets for this project -# (use Rube MCP LINEAR_CREATE_LINEAR_ISSUE to create tickets) - -# GitHub issues (secondary): -gh issue list --repo ComposioHQ/agent-orchestrator --state open -``` - -## Key Design Principles - -1. **tmux-based** — All agent sessions run in tmux. This gives persistence, detach/attach, and scriptability. -2. **Metadata files** — Each session has a flat metadata file (`key=value` format) tracking branch, PR, issue, status, notes. -3. **Live dashboard** — HTML dashboard served locally with real-time activity detection via Claude's JSONL session files. -4. **Project-agnostic shared scripts** — Core scripts (spawn, status, dashboard) take project as an argument. -5. **Project-specific session managers** — Each project gets a session manager script that handles worktrees, naming, and cleanup. -6. **iTerm2 integration** — AppleScript-based tab management for macOS (should be made terminal-agnostic). - -## Architecture Notes +## Architecture ### Session Lifecycle ``` -spawn → tmux session created → Claude started → working on issue +spawn → tmux session created → Claude started → working on ticket ↓ metadata file written (branch, issue, status) ↓ @@ -101,10 +169,38 @@ The dashboard detects if agents are working/idle/exited by: 2. Walking the process tree from tmux pane PID to find `claude` processes 3. Polling every 5 seconds via `/api/sessions` endpoint -### Dashboard Server -- Python HTTP server serving static HTML + JSON API -- `/api/sessions` — live activity status -- `/api/terminal/:name` — spawn ttyd web terminal for session -- `/api/kill/:name` — kill session + close iTerm tab + archive metadata -- `/api/merge/:repo/:num` — merge PR via `gh` -- `/api/send/:name` — send message to agent via `send-to-session` +### Key Design Principles +1. **tmux-based** — persistence, detach/attach, scriptability +2. **Flat metadata files** — `key=value` format, easy to parse and update +3. **Worktree isolation** — each session gets its own git worktree +4. **Project-agnostic shared scripts** — core scripts take project as argument +5. **Project-specific session managers** — each project gets its own (e.g., `claude-ao-session`) + +## Roadmap + +1. **Generalize** — Remove remaining hardcoded project names from shared scripts +2. **Configuration** — `orchestrator.yaml` defining projects, repos, branches, issue trackers +3. **Installation** — Install script that symlinks scripts to `~/` or adds to PATH +4. **Documentation** — Comprehensive README with setup guide and examples +5. **Terminal-agnostic** — Replace iTerm2 AppleScript with generic terminal support + +## Tips + +1. **Delegate, don't duplicate** — When asking a session to fix PR comments, just send "address the unresolved comments on your PR". The session has `gh` access. +2. **Check before spawning** — `~/claude-status` to avoid duplicate sessions. +3. **Detach, don't kill** — `Ctrl-b d` detaches from tmux. Session keeps running. +4. **Peek without attaching** — `tmux capture-pane -t "ao-1" -p -S -30` +5. **Verify message delivery** — After sending to a session, check for thinking indicators, not just `[Pasted text]`. + +## Linear Integration + +Create tickets via Rube MCP: +``` +RUBE_SEARCH_TOOLS: queries=[{use_case: "create an issue in Linear"}] + +LINEAR_CREATE_LINEAR_ISSUE: + team_id: "" + title: "Your ticket title" + description: "Markdown description" + priority: 2 # 1=Urgent, 2=High, 3=Normal, 4=Low +``` diff --git a/scripts/claude-ao-session b/scripts/claude-ao-session new file mode 100755 index 000000000..0e3ce4605 --- /dev/null +++ b/scripts/claude-ao-session @@ -0,0 +1,235 @@ +#!/bin/bash +# claude-ao-session - Worktree-based session manager for agent-orchestrator + +set -e + +MAIN_REPO=~/agent-orchestrator +WORKTREE_DIR=~/.worktrees/ao +SESSION_DIR=~/.ao-sessions +DEFAULT_BRANCH="main" +GITHUB_REPO="ComposioHQ/agent-orchestrator" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +usage() { + echo "Usage: ~/claude-ao-session [args]" + echo "" + echo "Commands:" + echo " new [LINEAR-ID] [--open] Create new session (optionally with Linear ticket)" + echo " ls List all sessions" + echo " attach Attach to session" + echo " kill Kill session and remove worktree" + echo " cleanup Kill sessions where PR is merged or ticket is done" + echo " update Update current session metadata" + exit 1 +} + +get_next_session_number() { + local max=0 + for session in $(tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^ao-[0-9]*$" | sed 's/ao-//'); do + if [ "$session" -gt "$max" ] 2>/dev/null; then + max=$session + fi + done + echo $((max + 1)) +} + +cmd_new() { + local linear_id="" + local open_tab=false + + # Parse args + for arg in "$@"; do + if [ "$arg" = "--open" ]; then + open_tab=true + elif [ -z "$linear_id" ] && [ "$arg" != "--open" ]; then + linear_id="$arg" + fi + done + + local session_num=$(get_next_session_number) + local session_name="ao-$session_num" + local worktree_path="$WORKTREE_DIR/$session_name" + + echo -e "${BLUE}Creating session: $session_name${NC}" + + cd "$MAIN_REPO" + git fetch origin --quiet + + if [ -n "$linear_id" ]; then + local branch_name="feat/$linear_id" + git worktree add -b "$branch_name" "$worktree_path" "origin/$DEFAULT_BRANCH" 2>/dev/null || \ + git worktree add "$worktree_path" "origin/$DEFAULT_BRANCH" + else + git worktree add "$worktree_path" "origin/$DEFAULT_BRANCH" --detach + fi + + echo -e "${GREEN}✓ Created worktree at $worktree_path${NC}" + + # Symlink shared resources from main repo + [ -f "$MAIN_REPO/CLAUDE.local.md" ] && ln -sf "$MAIN_REPO/CLAUDE.local.md" "$worktree_path/CLAUDE.local.md" + [ -d "$MAIN_REPO/.claude" ] && rm -rf "$worktree_path/.claude" && ln -s "$MAIN_REPO/.claude" "$worktree_path/.claude" + + # Create tmux session and start Claude (unset CLAUDECODE to avoid nested session detection) + tmux new-session -d -s "$session_name" -c "$worktree_path" -e "AO_SESSION=$session_name" -e "DIRENV_LOG_FORMAT=" + tmux send-keys -t "$session_name" "unset CLAUDECODE && claude --dangerously-skip-permissions" Enter + + # Create metadata file + mkdir -p "$SESSION_DIR" + cat > "$SESSION_DIR/$session_name" << EOF +worktree=$worktree_path +branch=$(cd "$worktree_path" && git branch --show-current || echo "detached") +status=starting +EOF + [ -n "$linear_id" ] && echo "issue=https://linear.app/composio/issue/$linear_id" >> "$SESSION_DIR/$session_name" + + echo -e "${GREEN}✓ Created tmux session: $session_name${NC}" + echo -e "${GREEN}✓ Started Claude in session${NC}" + echo "" + echo "Attach with: tmux attach -t $session_name" + echo "Or open in iTerm2: ~/open-iterm-tab $session_name" + + # Clean output for scripting (no ANSI codes) + echo "SESSION=$session_name" + + # Open in iTerm2 if requested + if [ "$open_tab" = true ]; then + ~/open-iterm-tab "$session_name" + fi +} + +cmd_ls() { + echo -e "${BLUE}Agent-Orchestrator Sessions:${NC}" + echo "" + + for session in $(tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^ao-" | sort -V); do + local meta_file="$SESSION_DIR/$session" + local worktree="" branch="" status="" pr="" + + if [ -f "$meta_file" ]; then + worktree=$(grep "^worktree=" "$meta_file" 2>/dev/null | cut -d= -f2-) + branch=$(grep "^branch=" "$meta_file" 2>/dev/null | cut -d= -f2-) + status=$(grep "^status=" "$meta_file" 2>/dev/null | cut -d= -f2-) + pr=$(grep "^pr=" "$meta_file" 2>/dev/null | cut -d= -f2-) + fi + + [ -d "$worktree" ] && branch=$(cd "$worktree" && git branch --show-current 2>/dev/null || echo "$branch") + + echo -e "${GREEN}$session${NC}" + [ -n "$branch" ] && echo " Branch: $branch" + [ -n "$status" ] && echo " Status: $status" + [ -n "$pr" ] && echo " PR: $pr" + echo "" + done +} + +cmd_attach() { + [ -z "$1" ] && echo "Usage: ~/claude-ao-session attach " && exit 1 + tmux attach -t "$1" +} + +cmd_kill() { + local session="$1" + [ -z "$session" ] && echo "Usage: ~/claude-ao-session kill " && exit 1 + + local meta_file="$SESSION_DIR/$session" + local worktree="" + [ -f "$meta_file" ] && worktree=$(grep "^worktree=" "$meta_file" 2>/dev/null | cut -d= -f2-) + + # Close iTerm tab BEFORE killing tmux (tab name changes after tmux dies) + osascript -e " + tell application \"iTerm2\" + repeat with w in windows + repeat with t in tabs of w + repeat with s in sessions of t + if name of s contains \"$session\" then + close t + return + end if + end repeat + end repeat + end repeat + end tell + " 2>/dev/null && echo -e "${GREEN}✓ Closed iTerm tab: $session${NC}" + + tmux kill-session -t "$session" 2>/dev/null && echo -e "${GREEN}✓ Killed tmux session: $session${NC}" + + if [ -n "$worktree" ] && [ -d "$worktree" ]; then + cd "$MAIN_REPO" + git worktree remove --force "$worktree" 2>/dev/null && echo -e "${GREEN}✓ Removed worktree: $worktree${NC}" + fi + + # Archive metadata instead of deleting + if [ -f "$meta_file" ]; then + mkdir -p "$SESSION_DIR/archive" + mv "$meta_file" "$SESSION_DIR/archive/${session}_$(date +%Y%m%d-%H%M%S)" + echo -e "${GREEN}✓ Archived metadata${NC}" + fi +} + +cmd_cleanup() { + echo "Checking for completed sessions..." + + for session in $(tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^ao-"); do + local meta_file="$SESSION_DIR/$session" + local pr="" issue="" + + [ -f "$meta_file" ] && { + pr=$(grep "^pr=" "$meta_file" 2>/dev/null | cut -d= -f2-) + issue=$(grep "^issue=" "$meta_file" 2>/dev/null | cut -d= -f2-) + } + + if [ -n "$pr" ]; then + local pr_num=$(echo "$pr" | grep -o '[0-9]*$') + if [ -n "$pr_num" ]; then + local state=$(gh pr view "$pr_num" --repo "$GITHUB_REPO" --json state -q '.state' 2>/dev/null) + [ "$state" = "MERGED" ] && echo -e "${YELLOW}PR #$pr_num merged - killing $session${NC}" && cmd_kill "$session" && continue + fi + fi + + # Check Linear ticket status if we have an issue URL + if [ -n "$issue" ] && [ -n "${LINEAR_API_KEY:-}" ]; then + local ticket_id=$(echo "$issue" | grep -o 'AO-[0-9]*') + if [ -n "$ticket_id" ]; then + local ticket_state=$(curl -s -X POST https://api.linear.app/graphql \ + -H "Authorization: $LINEAR_API_KEY" \ + -H "Content-Type: application/json" \ + -d "{\"query\": \"{ issueSearch(filter: { identifier: { eq: \\\"$ticket_id\\\" } }) { nodes { state { type } } } }\"}" \ + 2>/dev/null | jq -r '.data.issueSearch.nodes[0].state.type // empty' 2>/dev/null) + if [ "$ticket_state" = "completed" ] || [ "$ticket_state" = "canceled" ]; then + echo -e "${YELLOW}$ticket_id $ticket_state - killing $session${NC}" + cmd_kill "$session" && continue + fi + fi + fi + done + echo "Cleanup complete." +} + +cmd_update() { + local session="${AO_SESSION:-}" + [ -z "$session" ] && echo "Error: Not in an ao session" && exit 1 + + local meta_file="$SESSION_DIR/$session" + local worktree=$(grep "^worktree=" "$meta_file" 2>/dev/null | cut -d= -f2-) + [ -z "$worktree" ] || [ ! -d "$worktree" ] && worktree="$PWD" + + local branch=$(cd "$worktree" && git branch --show-current 2>/dev/null) + [ -n "$branch" ] && sed -i '' "s|^branch=.*|branch=$branch|" "$meta_file" 2>/dev/null + + echo "Updated metadata for $session" +} + +case "${1:-}" in + new) shift; cmd_new "$@" ;; + ls) cmd_ls ;; + attach) cmd_attach "$2" ;; + kill) cmd_kill "$2" ;; + cleanup) cmd_cleanup ;; + update) cmd_update ;; + *) usage ;; +esac diff --git a/scripts/claude-batch-spawn b/scripts/claude-batch-spawn index 1cfda311c..107e59394 100755 --- a/scripts/claude-batch-spawn +++ b/scripts/claude-batch-spawn @@ -35,9 +35,15 @@ case "$PROJECT" in SESSION_DATA_DIR="$HOME/.splitly-sessions" GITHUB_REPO="UniverseOfThings/SafeSplit" ;; + agent-orchestrator|ao) + SESSION_PREFIX="ao" + SESSION_MANAGER="$HOME/claude-ao-session" + SESSION_DATA_DIR="$HOME/.ao-sessions" + GITHUB_REPO="ComposioHQ/agent-orchestrator" + ;; *) echo "Unknown project: $PROJECT" - echo "Use 'integrator' (or 'i') or 'splitly' (or 's')" + echo "Use 'integrator' (or 'i'), 'splitly' (or 's'), or 'agent-orchestrator' (or 'ao')" exit 1 ;; esac diff --git a/scripts/claude-bugbot-fix b/scripts/claude-bugbot-fix index 71c4a0f6f..6e071e016 100755 --- a/scripts/claude-bugbot-fix +++ b/scripts/claude-bugbot-fix @@ -24,8 +24,13 @@ case "$PROJECT" in SESSIONS_DIR="$HOME/.splitly-sessions" SESSION_PREFIX="splitly" ;; + agent-orchestrator|ao) + REPO="ComposioHQ/agent-orchestrator" + SESSIONS_DIR="$HOME/.ao-sessions" + SESSION_PREFIX="ao" + ;; *) - echo "Usage: $0 [integrator|splitly] [--dry-run]" + echo "Usage: $0 [integrator|splitly|ao] [--dry-run]" exit 1 ;; esac diff --git a/scripts/claude-open-all b/scripts/claude-open-all index ba6162806..221233abb 100755 --- a/scripts/claude-open-all +++ b/scripts/claude-open-all @@ -12,12 +12,12 @@ for arg in "$@"; do --new-window|-w) NEW_WINDOW=true ;; - integrator|i|splitly|s|safesplit|all) + integrator|i|splitly|s|safesplit|agent-orchestrator|ao|all) PROJECT="$arg" ;; *) echo "Unknown argument: $arg" - echo "Usage: ~/claude-open-all [--new-window] [integrator|splitly|all]" + echo "Usage: ~/claude-open-all [--new-window] [integrator|splitly|ao|all]" exit 1 ;; esac @@ -94,8 +94,12 @@ case "$PROJECT" in SESSIONS=($(get_sessions "splitly")) echo "Opening ${#SESSIONS[@]} splitly sessions..." ;; + agent-orchestrator|ao) + SESSIONS=($(get_sessions "ao")) + echo "Opening ${#SESSIONS[@]} ao sessions..." + ;; all|"") - SESSIONS=($(get_sessions "integrator") $(get_sessions "splitly")) + SESSIONS=($(get_sessions "integrator") $(get_sessions "splitly") $(get_sessions "ao")) echo "Opening ${#SESSIONS[@]} total sessions..." ;; esac diff --git a/scripts/claude-review-check b/scripts/claude-review-check index 70b447418..2f581d2ab 100755 --- a/scripts/claude-review-check +++ b/scripts/claude-review-check @@ -14,8 +14,12 @@ case "$PROJECT" in SESSION_PREFIX="splitly" SESSION_DATA_DIR="$HOME/.splitly-sessions" ;; + agent-orchestrator|ao) + SESSION_PREFIX="ao" + SESSION_DATA_DIR="$HOME/.ao-sessions" + ;; *) - echo "Usage: ~/claude-review-check [integrator|splitly]" + echo "Usage: ~/claude-review-check [integrator|splitly|ao]" exit 1 ;; esac diff --git a/scripts/claude-spawn b/scripts/claude-spawn index f70d3c691..ea99ce66e 100755 --- a/scripts/claude-spawn +++ b/scripts/claude-spawn @@ -75,20 +75,25 @@ case "$PROJECT" in SESSION_SCRIPT="$HOME/claude-splitly-session-v2" PROJECT_NAME="splitly" ;; + agent-orchestrator|ao) + SESSION_SCRIPT="$HOME/claude-ao-session" + PROJECT_NAME="ao" + ;; "") - echo "Usage: ~/claude-spawn [issue]" + echo "Usage: ~/claude-spawn [issue]" echo "" echo "Examples:" echo " ~/claude-spawn integrator" echo " ~/claude-spawn integrator https://linear.app/composio/issue/INT-1020" echo " ~/claude-spawn splitly 294" + echo " ~/claude-spawn ao AO-1" echo "" echo "Run '~/claude-spawn help' for more information." exit 1 ;; *) echo "Unknown project: $PROJECT" - echo "Use 'integrator' (or 'i') or 'splitly' (or 's')" + echo "Use 'integrator' (or 'i'), 'splitly' (or 's'), or 'agent-orchestrator' (or 'ao')" exit 1 ;; esac diff --git a/scripts/claude-status b/scripts/claude-status index b26d15e45..6bb8e56ed 100755 --- a/scripts/claude-status +++ b/scripts/claude-status @@ -54,7 +54,8 @@ echo "" # Count sessions INTEGRATOR_COUNT=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -c "^integrator-" || echo 0) SPLITLY_COUNT=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -c "^splitly-" || echo 0) -TOTAL=$((INTEGRATOR_COUNT + SPLITLY_COUNT)) +AO_COUNT=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -c "^ao-" || echo 0) +TOTAL=$((INTEGRATOR_COUNT + SPLITLY_COUNT + AO_COUNT)) # Count empty checkouts INTEGRATOR_EMPTY=0 @@ -76,6 +77,7 @@ done echo "📊 SUMMARY: $TOTAL active sessions" echo " Integrator: $INTEGRATOR_COUNT sessions, $INTEGRATOR_EMPTY empty checkouts" echo " Splitly: $SPLITLY_COUNT sessions, $SPLITLY_EMPTY empty checkouts" +echo " AO: $AO_COUNT sessions" echo "" # Show integrator sessions @@ -201,12 +203,76 @@ else done fi +echo "" + +# Show ao sessions +echo "┌──────────────────────────────────────────────────────────────────────────────┐" +echo "│ AGENT-ORCHESTRATOR │" +echo "└──────────────────────────────────────────────────────────────────────────────┘" + +if [ "$AO_COUNT" -eq 0 ]; then + echo " (no active sessions)" +else + for session in $(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep "^ao-" | sort); do + activity=$(tmux display-message -t "$session" -p '#{session_activity}' 2>/dev/null) + now=$(date +%s) + if [ -n "$activity" ]; then + diff=$((now - activity)) + if [ $diff -lt 60 ]; then + last_active="${diff}s ago" + elif [ $diff -lt 3600 ]; then + last_active="$((diff / 60))m ago" + elif [ $diff -lt 86400 ]; then + last_active="$((diff / 3600))h ago" + else + last_active="$((diff / 86400))d ago" + fi + else + last_active="-" + fi + + data_file="$HOME/.ao-sessions/$session" + meta_branch=$(grep "^branch=" "$data_file" 2>/dev/null | cut -d'=' -f2-) + meta_status=$(grep "^status=" "$data_file" 2>/dev/null | cut -d'=' -f2-) + meta_summary=$(grep "^summary=" "$data_file" 2>/dev/null | cut -d'=' -f2- | cut -c1-60) + + # Get live Claude session info + eval "$(get_claude_info "$session" 2>/dev/null)" + + echo " 📍 $session ($last_active)" + + # Show branch - prefer live, show if different from metadata + if [ -n "$claude_branch" ]; then + if [ -n "$meta_branch" ] && [ "$claude_branch" != "$meta_branch" ]; then + echo " Branch: $claude_branch (meta: $meta_branch)" + else + echo " Branch: $claude_branch" + fi + elif [ -n "$meta_branch" ]; then + echo " Branch: $meta_branch (stale)" + fi + + # Show summary - prefer Claude's auto-generated, fall back to metadata + if [ -n "$claude_summary" ]; then + echo " Claude: ${claude_summary:0:65}" + fi + if [ -n "$meta_summary" ]; then + echo " Status: ${meta_summary}..." + fi + + # Show session ID if available (useful for resuming) + [ -n "$claude_session_id" ] && echo " Session: ${claude_session_id:0:8}..." + done +fi + echo "" echo "┌──────────────────────────────────────────────────────────────────────────────┐" echo "│ QUICK ACTIONS │" echo "└──────────────────────────────────────────────────────────────────────────────┘" echo " ~/claude-spawn i [linear-url] - New integrator session in new iTerm2 tab" echo " ~/claude-spawn s [issue-num] - New splitly session in new iTerm2 tab" +echo " ~/claude-spawn ao [linear-id] - New agent-orchestrator session" echo " ~/claude-integrator-session cleanup" echo " ~/claude-splitly-session cleanup" +echo " ~/claude-ao-session cleanup" echo ""