feat: single entry point /agent-loop:run handles setup, planning, and execution
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
"name": "agent-loop",
|
"name": "agent-loop",
|
||||||
"source": "./",
|
"source": "./",
|
||||||
"description": "Autonomous generator-evaluator agent loop for long-running coding tasks. Plan interactively, then execute with full visibility.",
|
"description": "Autonomous generator-evaluator agent loop for long-running coding tasks. Plan interactively, then execute with full visibility.",
|
||||||
"version": "0.5.0",
|
"version": "0.6.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Sheldon"
|
"name": "Sheldon"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "agent-loop",
|
"name": "agent-loop",
|
||||||
"version": "0.5.0",
|
"version": "0.6.0",
|
||||||
"description": "Autonomous generator-evaluator agent loop for long-running coding tasks. Plan with /agent-loop:init, then execute with /agent-loop:run.",
|
"description": "Autonomous generator-evaluator agent loop for long-running coding tasks. Plan with /agent-loop:init, then execute with /agent-loop:run.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Sheldon"
|
"name": "Sheldon"
|
||||||
|
|||||||
@@ -1,45 +1,113 @@
|
|||||||
---
|
---
|
||||||
name: run
|
name: run
|
||||||
description: Execute the generator-evaluator loop interactively inside Claude Code. Dispatches subagents with full visibility. Run /agent-loop:init and /agent-loop:stories first.
|
description: "Agent Loop — single entry point. Scaffolds .loop/ if missing, generates stories if no prd.json, then runs the generator-evaluator loop with full visibility."
|
||||||
---
|
---
|
||||||
|
|
||||||
# /run — Execute Agent Loop Inside Claude Code
|
# /run — Agent Loop
|
||||||
|
|
||||||
Run the generator-evaluator loop natively in Claude Code. You see every tool call and can intervene at any point.
|
Single entry point for the agent loop. Handles setup, planning, and execution automatically based on what's already done.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
/agent-loop:run # Run until all stories pass or max iterations
|
/agent-loop:run # Full flow: setup → stories → loop
|
||||||
/agent-loop:run 3 # Run at most 3 iterations
|
/agent-loop:run 3 # Limit to 3 loop iterations
|
||||||
/agent-loop:run --skip-eval # Skip evaluator pass
|
/agent-loop:run --skip-eval # Skip evaluator pass
|
||||||
/agent-loop:run --story US-003 # Run only a specific story
|
/agent-loop:run --story US-003 # Run only a specific story
|
||||||
```
|
```
|
||||||
|
|
||||||
## Instructions
|
## Instructions
|
||||||
|
|
||||||
Follow this orchestration sequence exactly.
|
Follow this sequence. Each phase checks what exists and skips if already done.
|
||||||
|
|
||||||
### Step 0: Validate Prerequisites
|
---
|
||||||
|
|
||||||
1. Check `.loop/config.json` exists. If not: tell user to run `/agent-loop:init` and stop.
|
## Phase 1: Scaffold (if needed)
|
||||||
2. Check `.loop/prd.json` exists. If not: tell user to run `/agent-loop:stories` and stop.
|
|
||||||
3. **Validate prd.json schema.** Read the file and verify:
|
Check if `.loop/config.json` exists.
|
||||||
|
|
||||||
|
**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 | head -1)" <mode>
|
||||||
|
```
|
||||||
|
|
||||||
|
Show the output. If setup fails, stop.
|
||||||
|
|
||||||
|
**If it already exists**, skip to Phase 2.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: Generate Stories (if needed)
|
||||||
|
|
||||||
|
Check if `.loop/prd.json` exists.
|
||||||
|
|
||||||
|
**If it does NOT exist**, generate it:
|
||||||
|
|
||||||
|
1. Search for existing specs:
|
||||||
|
- `docs/superpowers/specs/*.md`
|
||||||
|
- `docs/specs/*.md`
|
||||||
|
- `SPEC.md`, `PRD.md`, `DESIGN.md` at project root
|
||||||
|
|
||||||
|
If found: "I found a spec at `{path}`. Using it to generate stories."
|
||||||
|
If not found: ask "What do you want to build? 1-3 sentences."
|
||||||
|
|
||||||
|
2. Read the project root and tech stack info.
|
||||||
|
|
||||||
|
3. Dispatch the **agent-loop:planner** agent:
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent(
|
||||||
|
subagent_type: "agent-loop:planner",
|
||||||
|
prompt: "Generate prd.json and sprint contracts.\n\nMode: {mode}\nProject root: {path}\n\nSpec:\n{spec content}\n\nTech stack: {detected stack}",
|
||||||
|
description: "Planning: generate stories"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
4. After the planner finishes, read `.loop/prd.json` and present:
|
||||||
|
|
||||||
|
> **Stories generated — Review before running**
|
||||||
|
>
|
||||||
|
> 1. US-001: {title}
|
||||||
|
> 2. US-002: {title}
|
||||||
|
> ...
|
||||||
|
>
|
||||||
|
> **Review:**
|
||||||
|
> - `.loop/prd.json` — stories and acceptance criteria
|
||||||
|
> - `.loop/contracts/` — done conditions per story
|
||||||
|
>
|
||||||
|
> Let me know if you want changes, or say **go** to start the loop.
|
||||||
|
|
||||||
|
5. **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.
|
||||||
|
|
||||||
|
**If `prd.json` already exists**, skip to Phase 3.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: Validate
|
||||||
|
|
||||||
|
1. Read `.loop/prd.json` and verify:
|
||||||
- Has a `userStories` array (NOT `sprints`, `stories`, or `tasks`)
|
- Has a `userStories` array (NOT `sprints`, `stories`, or `tasks`)
|
||||||
- Each story has: `id`, `title`, `passes`, `priority`
|
- Each story has: `id`, `title`, `passes`, `priority`
|
||||||
- If validation fails, show the error and stop. Do NOT attempt to fix it automatically.
|
- If invalid, show the error and stop.
|
||||||
4. Check prompts exist. Look for `.loop/prompts/generator/_base.md` in these locations (first match wins):
|
|
||||||
- `.loop/prompts/` (local project copy)
|
2. Read `.loop/config.json` for `mode`, `maxIterations`, `evalRetries`, `scopeBudgets`.
|
||||||
- `${CLAUDE_PLUGIN_ROOT}/prompts/` (plugin install)
|
|
||||||
|
3. Find prompts. Check these paths (first match wins):
|
||||||
|
- `.loop/prompts/` (local)
|
||||||
- `~/.claude/plugins/cache/agent-loop/agent-loop/*/prompts/` (plugin cache)
|
- `~/.claude/plugins/cache/agent-loop/agent-loop/*/prompts/` (plugin cache)
|
||||||
|
|
||||||
Save the resolved prompt base path for later use. If no prompts found, tell user to run `/agent-loop:init` and stop.
|
If no prompts found, stop with error.
|
||||||
|
|
||||||
### Step 1: Parse Arguments and Load State
|
4. Parse arguments: number → max iterations, `--skip-eval`, `--story <ID>`
|
||||||
|
|
||||||
- Parse arguments: number → max iterations, `--skip-eval`, `--story <ID>`
|
---
|
||||||
- Read `.loop/config.json` for defaults
|
|
||||||
- Read `.loop/prd.json` for story list
|
## Phase 4: Execute Loop
|
||||||
|
|
||||||
Report:
|
Report:
|
||||||
|
|
||||||
@@ -51,47 +119,45 @@ Report:
|
|||||||
>
|
>
|
||||||
> Starting. Interrupt me at any time.
|
> Starting. Interrupt me at any time.
|
||||||
|
|
||||||
### Step 2: Iteration Loop
|
|
||||||
|
|
||||||
For each iteration (1 to max iterations):
|
For each iteration (1 to max iterations):
|
||||||
|
|
||||||
#### 2a. Find Next Story
|
### 4a. Find Next Story
|
||||||
|
|
||||||
Find the story with the lowest `priority` number where `passes` is `false` and `blocked` is not `true`. If `--story` was specified, use that story.
|
Find the story with the lowest `priority` where `passes` is `false` and `blocked` is not `true`. If `--story` was specified, use that story.
|
||||||
|
|
||||||
**If no actionable story remains:**
|
**If no actionable story remains:**
|
||||||
- All `passes: true` → report success and stop
|
- All `passes: true` → report success and stop
|
||||||
- Some `blocked: true` → report which and suggest `/agent-loop:triage`
|
- Some `blocked: true` → report which ones
|
||||||
- Stop the loop
|
- Stop
|
||||||
|
|
||||||
#### 2b. Report Iteration Start
|
### 4b. Report Iteration Start
|
||||||
|
|
||||||
> **Iteration {N}/{max} — {story.id}: {story.title}**
|
> **Iteration {N}/{max} — {story.id}: {story.title}**
|
||||||
|
|
||||||
If the story has `[REJECTED]` in its `notes`, summarize the feedback.
|
If the story has `[REJECTED]` in `notes`, summarize the feedback.
|
||||||
|
|
||||||
#### 2c. Assemble Generator Prompt
|
### 4c. Assemble Generator Prompt
|
||||||
|
|
||||||
Read and concatenate with `---` separator:
|
Read and concatenate with `---` separator:
|
||||||
1. `{prompt_base_path}/generator/_base.md`
|
1. `{prompt_path}/generator/_base.md`
|
||||||
2. `{prompt_base_path}/generator/{mode}.md`
|
2. `{prompt_path}/generator/{mode}.md`
|
||||||
|
|
||||||
Substitute template variables:
|
Substitute variables:
|
||||||
- `{{MAX_FILES_TO_READ}}` → from config scopeBudgets
|
- `{{MAX_FILES_TO_READ}}` → from config scopeBudgets
|
||||||
- `{{MAX_LINES_TO_WRITE}}` → from config scopeBudgets
|
- `{{MAX_LINES_TO_WRITE}}` → from config scopeBudgets
|
||||||
- `{{MAX_FILES_TO_MODIFY}}` → from config scopeBudgets
|
- `{{MAX_FILES_TO_MODIFY}}` → from config scopeBudgets
|
||||||
- `{{MODE}}` → mode from config
|
- `{{MODE}}` → mode
|
||||||
- `{{ITERATION}}` → current iteration
|
- `{{ITERATION}}` → current iteration
|
||||||
- `{{MAX_ITERATIONS}}` → max iterations
|
- `{{MAX_ITERATIONS}}` → max iterations
|
||||||
- `{{LOOP_DIR}}` → absolute path to `.loop/`
|
- `{{LOOP_DIR}}` → absolute path to `.loop/`
|
||||||
- `{{PROJECT_ROOT}}` → project root absolute path
|
- `{{PROJECT_ROOT}}` → project root
|
||||||
- `{{CURRENT_STORY_ID}}` → story ID
|
- `{{CURRENT_STORY_ID}}` → story ID
|
||||||
|
|
||||||
#### 2d. Capture Pre-Generator Git State
|
### 4d. Capture Pre-Generator Git State
|
||||||
|
|
||||||
Run `git rev-parse HEAD` and save the SHA.
|
Run `git rev-parse HEAD` and save the SHA.
|
||||||
|
|
||||||
#### 2e. Dispatch Generator Agent
|
### 4e. Dispatch Generator Agent
|
||||||
|
|
||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
@@ -102,27 +168,19 @@ Agent(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Wait for completion.
|
### 4f. Check Completion Signal
|
||||||
|
|
||||||
#### 2f. Check for Completion Signal
|
If output contains `<promise>COMPLETE</promise>`, report done and stop.
|
||||||
|
|
||||||
If output contains `<promise>COMPLETE</promise>`, report all stories complete and stop.
|
### 4g. Evaluator (unless skipped)
|
||||||
|
|
||||||
#### 2g. Skip Evaluator (if configured)
|
If `--skip-eval` or `config.skipEval` is true, skip to 4h and treat as PASS.
|
||||||
|
|
||||||
If `--skip-eval` or `config.skipEval` is true, skip to 2j and treat as PASS.
|
Otherwise, read and concatenate:
|
||||||
|
1. `{prompt_path}/evaluator/_base.md`
|
||||||
|
2. `{prompt_path}/evaluator/{mode}.md`
|
||||||
|
|
||||||
#### 2h. Assemble Evaluator Prompt
|
Substitute same variables plus `{{PRE_GENERATOR_SHA}}` and `{{CURRENT_STORY_ID}}`.
|
||||||
|
|
||||||
Read and concatenate:
|
|
||||||
1. `{prompt_base_path}/evaluator/_base.md`
|
|
||||||
2. `{prompt_base_path}/evaluator/{mode}.md`
|
|
||||||
|
|
||||||
Substitute same variables plus:
|
|
||||||
- `{{PRE_GENERATOR_SHA}}` → SHA from step 2d
|
|
||||||
- `{{CURRENT_STORY_ID}}` → story ID
|
|
||||||
|
|
||||||
#### 2i. Dispatch Evaluator Agent
|
|
||||||
|
|
||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
@@ -133,52 +191,48 @@ Agent(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Parse the verdict:
|
Parse verdict:
|
||||||
- `<verdict>PASS</verdict>` → PASS
|
- `<verdict>PASS</verdict>` → PASS
|
||||||
- `<verdict>REJECT</verdict>` → REJECT, extract `<rejection_reason>...</rejection_reason>`
|
- `<verdict>REJECT</verdict>` → REJECT, extract reason
|
||||||
- No verdict tag → REJECT (fail-safe)
|
- No verdict → REJECT (fail-safe)
|
||||||
|
|
||||||
#### 2j. Update State
|
### 4h. Update State
|
||||||
|
|
||||||
**On PASS:**
|
**PASS:** Set `passes: true` in prd.json. Report: **{story.id} PASSED**
|
||||||
1. Read `.loop/prd.json`, set `passes: true` for the story, write it back
|
|
||||||
2. Report: **{story.id} PASSED**
|
|
||||||
|
|
||||||
**On REJECT:**
|
**REJECT:** Increment `rejections`, append `[REJECTED] {reason}` to `notes`. Report: **{story.id} REJECTED** — {reason}
|
||||||
1. Read `.loop/prd.json`, increment `rejections`, append `[REJECTED] {reason}` to `notes`, write back
|
|
||||||
2. Report: **{story.id} REJECTED** — {reason}
|
|
||||||
3. If `rejections >= evalRetries`: set `blocked: true`, append `[BLOCKED]` to notes
|
|
||||||
- Report: **{story.id} BLOCKED** — rejected {N} times, needs human review
|
|
||||||
|
|
||||||
#### 2k. Append Progress
|
If `rejections >= evalRetries`: set `blocked: true`. Report: **{story.id} BLOCKED**
|
||||||
|
|
||||||
|
### 4i. Append Progress
|
||||||
|
|
||||||
Append to `.loop/progress.md`:
|
Append to `.loop/progress.md`:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
### {story.id} — {story.title}
|
### {story.id} — {story.title}
|
||||||
Date: {current date and time}
|
Date: {date}
|
||||||
Iteration: {N}
|
Iteration: {N}
|
||||||
Verdict: {PASS/REJECT/SKIP-EVAL}
|
Verdict: {verdict}
|
||||||
|
|
||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2l. Report and Continue
|
### 4j. Continue
|
||||||
|
|
||||||
Show: `{passed}/{total} stories complete`
|
Show: `{passed}/{total} stories complete`
|
||||||
|
|
||||||
Continue to next iteration.
|
Continue to next iteration.
|
||||||
|
|
||||||
### Step 3: Loop Exit
|
---
|
||||||
|
|
||||||
|
## Loop Exit
|
||||||
|
|
||||||
> **Loop Complete**
|
> **Loop Complete**
|
||||||
> - Iterations used: {N}
|
> - Iterations: {N}
|
||||||
> - Stories: {passed}/{total} complete, {blocked} blocked
|
> - Stories: {passed}/{total} complete, {blocked} blocked
|
||||||
|
|
||||||
If incomplete, suggest `/agent-loop:triage`.
|
## Error Handling
|
||||||
|
|
||||||
### Error Handling
|
- Agent fails or empty output → warn and continue
|
||||||
|
- prd.json unparseable → stop
|
||||||
- Agent fails or empty output → warn and continue to next iteration
|
- User says "stop" → end loop, report status
|
||||||
- prd.json unparseable → stop immediately
|
|
||||||
- User says "stop" → end loop, report current status
|
|
||||||
|
|||||||
Reference in New Issue
Block a user