Each /agent-loop:run now creates a git worktree for the feature branch before generating stories. This provides full isolation: - Multiple loops can run in parallel on different specs in the same project - Main working directory stays on main, always available - Each worktree has its own .loop/ state, tmux session, and branch - Completed runs are archived to main's .loop/archive/ with runs.log Changes: - setup.sh: add --init-worktree mode for initializing worktree .loop/ - archive.sh: add archive_from_worktree() for cross-directory archiving - loop.sh: replace branch checkout with validation (worktree is pre-checked-out) - agents/planner.md: accept absolute path prefix for worktree .loop/ writes - skills/run/SKILL.md: full rewrite — worktree creation in Phase 2, launch in Phase 3, archive on completion, .active-worktree tracking file - skills/stories/SKILL.md: worktree-aware, defer to /run for full flow Bump to 0.12.0.
320 lines
9.6 KiB
Markdown
320 lines
9.6 KiB
Markdown
---
|
|
name: run
|
|
description: "Agent Loop — single entry point. Scaffolds .loop/ if missing, creates a worktree, generates stories, then launches autonomous execution in tmux."
|
|
---
|
|
|
|
# /run — Agent Loop
|
|
|
|
Single entry point for the agent loop. Handles setup and planning interactively, then launches autonomous execution in a git worktree via tmux.
|
|
|
|
Each run gets its own worktree (isolated working directory on a feature branch). Multiple loops can run in parallel on different specs. Completed runs are archived to the main project's `.loop/archive/`.
|
|
|
|
## Usage
|
|
|
|
```
|
|
/agent-loop:run # Full flow: setup → worktree → stories → launch
|
|
/agent-loop:run --skip-eval # Skip evaluator pass
|
|
```
|
|
|
|
## Instructions
|
|
|
|
Follow this sequence. Each phase checks what exists and skips if already done.
|
|
|
|
---
|
|
|
|
## Phase 1: Scaffold Main .loop/ (if needed)
|
|
|
|
Check if `.loop/config.json` exists in the current project root.
|
|
|
|
**If it does NOT exist**, run the setup script:
|
|
|
|
Ask the user: **Mode?** (a) Implement (b) Explore (c) Fix — default is Implement.
|
|
|
|
Then run:
|
|
|
|
```bash
|
|
bash "$(ls -d ~/.claude/plugins/cache/agent-loop/agent-loop/*/setup.sh 2>/dev/null | tail -1)" <mode>
|
|
```
|
|
|
|
Show the output. If setup fails, stop.
|
|
|
|
**If it already exists**, check if the harness files need updating. Compare the installed harness version against the plugin version:
|
|
|
|
```bash
|
|
INSTALLED=$(cat .loop/.harness-version 2>/dev/null || echo "unknown")
|
|
PLUGIN=$(jq -r '.version // empty' "$(ls -d ~/.claude/plugins/cache/agent-loop/agent-loop/*/.claude-plugin/plugin.json 2>/dev/null | tail -1)" 2>/dev/null || echo "unknown")
|
|
echo "installed=$INSTALLED plugin=$PLUGIN"
|
|
```
|
|
|
|
If the versions differ (or installed is "unknown"), update the harness files:
|
|
|
|
```bash
|
|
bash "$(ls -d ~/.claude/plugins/cache/agent-loop/agent-loop/*/setup.sh 2>/dev/null | tail -1)" --update
|
|
```
|
|
|
|
Tell the user: *"Updated harness files to v{version}."*
|
|
|
|
---
|
|
|
|
## Phase 2: Create Worktree and Generate Stories
|
|
|
|
### 2a. Find the spec
|
|
|
|
Search for existing specs or plans:
|
|
- `docs/superpowers/specs/*.md`
|
|
- `docs/superpowers/plans/*.md`
|
|
- `docs/specs/*.md`
|
|
- `docs/plans/*.md`
|
|
- `SPEC.md`, `PRD.md`, `DESIGN.md`, `PLAN.md` at project root
|
|
- Any markdown file that looks like a feature spec or implementation plan
|
|
|
|
If found: "I found a spec at `{path}`. Using it to generate stories."
|
|
|
|
If NOT found, stop and tell the user:
|
|
|
|
> **No spec or plan found.** Agent Loop decomposes existing plans into stories — it doesn't create plans from scratch.
|
|
>
|
|
> Create a plan first, then re-run `/agent-loop:run`:
|
|
> - Describe your idea to Claude and ask it to write a spec
|
|
> - Use `/plan` if available
|
|
> - Or create a markdown file at `docs/specs/` or `SPEC.md`
|
|
>
|
|
> The plan should describe what to build, the tech stack, and key requirements.
|
|
|
|
**STOP here. Do NOT ask the user to describe the project in a few sentences. Do NOT proceed without a spec file.**
|
|
|
|
### 2b. Derive names and create worktree
|
|
|
|
Read the spec title or filename to derive a feature slug. Examples:
|
|
- `SPEC.md` with title "# Enhanced Spikes Editor" → slug: `enhanced-spikes-editor`
|
|
- `docs/specs/auth-system.md` → slug: `auth-system`
|
|
|
|
Derive paths:
|
|
|
|
```bash
|
|
PROJECT_DIR=$(basename "$(pwd)")
|
|
FEATURE_SLUG="<derived-slug>"
|
|
BRANCH_NAME="loop/${FEATURE_SLUG}"
|
|
WORKTREE_PATH="../${PROJECT_DIR}--loop-${FEATURE_SLUG}"
|
|
MAIN_LOOP_DIR="$(pwd)/.loop"
|
|
```
|
|
|
|
Check if the worktree already exists:
|
|
|
|
```bash
|
|
if [ -d "$WORKTREE_PATH" ]; then
|
|
echo "WORKTREE_EXISTS"
|
|
else
|
|
echo "WORKTREE_NEW"
|
|
fi
|
|
```
|
|
|
|
**If worktree exists**, check its state:
|
|
- Read `{WORKTREE_PATH}/.loop/prd.json` — are all stories passed?
|
|
- If all passed: ask user — "Previous run on `{BRANCH_NAME}` is complete. Archive and start fresh, or resume?"
|
|
- If in progress: ask user — "Run in progress on `{BRANCH_NAME}` ({passed}/{total}). Resume, or archive and start fresh?"
|
|
- If user says resume: skip to Phase 3 (launch in existing worktree)
|
|
- If user says archive/fresh: archive from worktree to main, remove worktree, then continue below
|
|
|
|
**If worktree is new**, create it:
|
|
|
|
```bash
|
|
git worktree add "$WORKTREE_PATH" -b "$BRANCH_NAME"
|
|
```
|
|
|
|
If the branch already exists (e.g., from a previous run):
|
|
|
|
```bash
|
|
git worktree add "$WORKTREE_PATH" "$BRANCH_NAME"
|
|
```
|
|
|
|
Initialize the worktree's `.loop/`:
|
|
|
|
```bash
|
|
bash "$(ls -d ~/.claude/plugins/cache/agent-loop/agent-loop/*/setup.sh 2>/dev/null | tail -1)" --init-worktree "$WORKTREE_PATH" "$MAIN_LOOP_DIR"
|
|
```
|
|
|
|
Initialize submodules if the project uses them:
|
|
|
|
```bash
|
|
git -C "$WORKTREE_PATH" submodule update --init --recursive 2>/dev/null || true
|
|
```
|
|
|
|
### 2c. Generate stories
|
|
|
|
Read the project root listing and tech stack info.
|
|
|
|
Dispatch the **agent-loop:planner** agent. Pass the **absolute worktree path** so the planner writes to the worktree's `.loop/`:
|
|
|
|
```
|
|
Agent(
|
|
subagent_type: "agent-loop:planner",
|
|
prompt: "Generate prd.json and sprint contracts.\n\nIMPORTANT: Write ALL files using absolute paths under: {WORKTREE_PATH}/.loop/\n- PRD: {WORKTREE_PATH}/.loop/prd.json\n- Contracts: {WORKTREE_PATH}/.loop/contracts/\n- Progress: {WORKTREE_PATH}/.loop/progress.md\n\nBranch name to use in prd.json: {BRANCH_NAME}\n\nMode: {mode}\nProject root: {WORKTREE_PATH}\n\nSpec:\n{spec content}\n\nTech stack: {detected stack}",
|
|
description: "Planning: generate stories"
|
|
)
|
|
```
|
|
|
|
### 2d. Present stories
|
|
|
|
After the planner finishes, read `{WORKTREE_PATH}/.loop/prd.json` and present:
|
|
|
|
> **Stories generated — Review before running**
|
|
>
|
|
> Worktree: `{WORKTREE_PATH}` (branch: `{BRANCH_NAME}`)
|
|
>
|
|
> 1. US-001: {title}
|
|
> 2. US-002: {title}
|
|
> ...
|
|
>
|
|
> **Review:**
|
|
> - `{WORKTREE_PATH}/.loop/prd.json` — stories and acceptance criteria
|
|
> - `{WORKTREE_PATH}/.loop/contracts/` — done conditions per story
|
|
>
|
|
> Let me know if you want changes, or say **go** to start the loop.
|
|
|
|
**STOP and wait for the user.** Do NOT start the loop automatically. The user must say "go", "start", "run", "looks good", or similar before proceeding to Phase 3.
|
|
|
|
---
|
|
|
|
## Phase 3: Validate and Launch
|
|
|
|
1. Read `{WORKTREE_PATH}/.loop/prd.json` and verify:
|
|
- Has a `userStories` array (NOT `sprints`, `stories`, or `tasks`)
|
|
- Each story has: `id`, `title`, `passes`, `priority`
|
|
- If invalid, show the error and stop.
|
|
|
|
2. Read `{WORKTREE_PATH}/.loop/config.json` for `mode`, `maxIterations`.
|
|
|
|
3. Verify `{WORKTREE_PATH}/.loop/loop.sh` exists and is executable.
|
|
|
|
4. Parse arguments for any flags to pass through (e.g., `--skip-eval`).
|
|
|
|
5. Build the loop.sh command and derive a unique tmux session name:
|
|
|
|
```bash
|
|
LOOP_CMD="{WORKTREE_PATH}/.loop/loop.sh"
|
|
# Add --skip-eval if requested
|
|
# Add --max N if specified
|
|
|
|
# Derive tmux session name from worktree directory name
|
|
WORKTREE_DIR=$(basename "$WORKTREE_PATH")
|
|
SESSION_NAME="agent-loop-${WORKTREE_DIR}"
|
|
```
|
|
|
|
6. Kill any existing tmux session with this name, then launch detached in the worktree:
|
|
|
|
```bash
|
|
tmux kill-session -t "$SESSION_NAME" 2>/dev/null; tmux new-session -d -s "$SESSION_NAME" -c "$WORKTREE_PATH" "$LOOP_CMD"
|
|
```
|
|
|
|
7. Save the worktree path and session name for the completion handler. Write a tracking file in main's .loop/:
|
|
|
|
```bash
|
|
cat > .loop/.active-worktree << EOF
|
|
WORKTREE_PATH={WORKTREE_PATH}
|
|
SESSION_NAME={SESSION_NAME}
|
|
BRANCH_NAME={BRANCH_NAME}
|
|
MAIN_LOOP_DIR={MAIN_LOOP_DIR}
|
|
EOF
|
|
```
|
|
|
|
8. Start a **background watcher** that waits for the loop to finish. Use the Bash tool with `run_in_background: true`:
|
|
|
|
```bash
|
|
while tmux has-session -t "$SESSION_NAME" 2>/dev/null; do sleep 10; done; echo "LOOP_COMPLETE"
|
|
```
|
|
|
|
9. Tell the user:
|
|
|
|
> **Loop launched** as tmux session `{SESSION_NAME}`. Watch it live:
|
|
> ```
|
|
> ! tmux attach -t {SESSION_NAME}
|
|
> ```
|
|
> (Type the above — it opens the session right here in your terminal.)
|
|
>
|
|
> - **Detach** (return to Claude Code): `Ctrl+B` then `D`
|
|
> - **Stop the loop**: `Ctrl+C`
|
|
> - Ask me "status" anytime and I'll check progress.
|
|
>
|
|
> I'll notify you when the loop finishes.
|
|
>
|
|
> When complete, merge with:
|
|
> ```
|
|
> git merge {BRANCH_NAME}
|
|
> git worktree remove {WORKTREE_PATH}
|
|
> git branch -d {BRANCH_NAME}
|
|
> ```
|
|
|
|
---
|
|
|
|
## When Background Watcher Completes
|
|
|
|
When you receive the background task notification (the watcher prints "LOOP_COMPLETE"), the loop has finished. Automatically:
|
|
|
|
1. Read the tracking file to get paths:
|
|
|
|
```bash
|
|
cat .loop/.active-worktree
|
|
```
|
|
|
|
2. Read `{WORKTREE_PATH}/.loop/prd.json` — count passed/failed/blocked stories
|
|
3. Read `{WORKTREE_PATH}/.loop/progress.md` — show the latest session log entries
|
|
4. Check `git log --oneline` on the feature branch for commits made during the run
|
|
|
|
5. Archive the run to main's `.loop/archive/`:
|
|
|
|
```bash
|
|
source .loop/lib/state.sh && source .loop/lib/archive.sh && archive_from_worktree "{WORKTREE_PATH}/.loop" "$(pwd)/.loop"
|
|
```
|
|
|
|
6. Clean up the tracking file:
|
|
|
|
```bash
|
|
rm -f .loop/.active-worktree
|
|
```
|
|
|
|
7. Present a summary:
|
|
|
|
> **Loop Complete**
|
|
> - Stories: {passed}/{total} complete, {blocked} blocked
|
|
> - Iterations: {from progress.md}
|
|
> - Commits: {list from git log}
|
|
> - Archived to: `.loop/archive/{date}-{feature}/`
|
|
>
|
|
> {If any stories blocked: "Some stories need human review. Run /agent-loop:triage for details."}
|
|
> {If all passed: "All stories complete. Review the code and test it."}
|
|
>
|
|
> **When ready to merge:**
|
|
> ```
|
|
> git merge {BRANCH_NAME}
|
|
> git worktree remove {WORKTREE_PATH}
|
|
> git branch -d {BRANCH_NAME}
|
|
> ```
|
|
|
|
---
|
|
|
|
## Monitoring (if user asks mid-run)
|
|
|
|
If the user asks about progress (e.g., "status", "how's it going"):
|
|
|
|
1. Check for active worktree tracking:
|
|
|
|
```bash
|
|
cat .loop/.active-worktree 2>/dev/null
|
|
```
|
|
|
|
If no tracking file, check for tmux sessions matching the pattern:
|
|
|
|
```bash
|
|
tmux list-sessions 2>/dev/null | grep "^agent-loop-"
|
|
```
|
|
|
|
2. Read `{WORKTREE_PATH}/.loop/prd.json` — count passed/failed/blocked
|
|
3. Capture recent tmux output:
|
|
|
|
```bash
|
|
tmux capture-pane -t "$SESSION_NAME" -p | tail -20
|
|
```
|
|
|
|
4. Report current status.
|