feat: launch execution in tmux, orchestrator monitors progress
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.7.0",
|
"version": "0.8.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Sheldon"
|
"name": "Sheldon"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "agent-loop",
|
"name": "agent-loop",
|
||||||
"version": "0.7.0",
|
"version": "0.8.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,19 +1,17 @@
|
|||||||
---
|
---
|
||||||
name: run
|
name: run
|
||||||
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."
|
description: "Agent Loop — single entry point. Scaffolds .loop/ if missing, generates stories if no prd.json, then launches autonomous execution in tmux."
|
||||||
---
|
---
|
||||||
|
|
||||||
# /run — Agent Loop
|
# /run — Agent Loop
|
||||||
|
|
||||||
Single entry point for the agent loop. Handles setup, planning, and execution automatically based on what's already done.
|
Single entry point for the agent loop. Handles setup and planning interactively, then launches autonomous execution in a tmux session.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
/agent-loop:run # Full flow: setup → stories → loop
|
/agent-loop:run # Full flow: setup → stories → launch
|
||||||
/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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Instructions
|
## Instructions
|
||||||
@@ -88,151 +86,76 @@ Agent(
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 3: Validate
|
## Phase 3: Validate and Launch
|
||||||
|
|
||||||
1. Read `.loop/prd.json` and verify:
|
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 invalid, show the error and stop.
|
- If invalid, show the error and stop.
|
||||||
|
|
||||||
2. Read `.loop/config.json` for `mode`, `maxIterations`, `evalRetries`, `scopeBudgets`.
|
2. Read `.loop/config.json` for `mode`, `maxIterations`.
|
||||||
|
|
||||||
3. Find prompts. Check these paths (first match wins):
|
3. Verify `.loop/loop.sh` exists and is executable.
|
||||||
- `.loop/prompts/` (local)
|
|
||||||
- `~/.claude/plugins/cache/agent-loop/agent-loop/*/prompts/` (plugin cache)
|
|
||||||
|
|
||||||
If no prompts found, stop with error.
|
4. Parse arguments for any flags to pass through (e.g., `--skip-eval`).
|
||||||
|
|
||||||
4. Parse arguments: number → max iterations, `--skip-eval`, `--story <ID>`
|
5. Build the loop.sh command with any flags:
|
||||||
|
|
||||||
---
|
```bash
|
||||||
|
LOOP_CMD=".loop/loop.sh"
|
||||||
|
# Add --skip-eval if requested
|
||||||
|
# Add --max N if specified
|
||||||
|
```
|
||||||
|
|
||||||
## Phase 4: Execute Loop
|
6. Launch in tmux:
|
||||||
|
|
||||||
Report:
|
```bash
|
||||||
|
tmux new-session -d -s agent-loop -c <project_root> "$LOOP_CMD"
|
||||||
|
```
|
||||||
|
|
||||||
> **Loop Ready**
|
7. Report to the user:
|
||||||
|
|
||||||
|
> **Loop launched in tmux session `agent-loop`**
|
||||||
|
> - Stories: {total} to complete
|
||||||
> - Mode: {mode}
|
> - Mode: {mode}
|
||||||
> - Stories: {passed}/{total} complete
|
|
||||||
> - Max iterations: {N}
|
|
||||||
> - Eval: {on/off}
|
|
||||||
>
|
>
|
||||||
> Starting. Interrupt me at any time.
|
> **Monitor:**
|
||||||
|
> - Watch live: `tmux attach -t agent-loop`
|
||||||
For each iteration (1 to max iterations):
|
> - Check progress: read `.loop/progress.md`
|
||||||
|
> - Check status: read `.loop/prd.json`
|
||||||
### 4a. Find Next Story
|
> - Stop the loop: `tmux kill-session -t agent-loop`
|
||||||
|
>
|
||||||
Find the story with the lowest `priority` where `passes` is `false` and `blocked` is not `true`. If `--story` was specified, use that story.
|
> I can also check on progress for you — just ask "how's it going?"
|
||||||
|
|
||||||
**If no actionable story remains:**
|
|
||||||
- All `passes: true` → report success and stop
|
|
||||||
- Some `blocked: true` → report which ones
|
|
||||||
- Stop
|
|
||||||
|
|
||||||
### 4b. Report Iteration Start
|
|
||||||
|
|
||||||
> **Iteration {N}/{max} — {story.id}: {story.title}**
|
|
||||||
|
|
||||||
If the story has `[REJECTED]` in `notes`, summarize the feedback.
|
|
||||||
|
|
||||||
### 4c. Assemble Generator Prompt
|
|
||||||
|
|
||||||
Read and concatenate with `---` separator:
|
|
||||||
1. `{prompt_path}/generator/_base.md`
|
|
||||||
2. `{prompt_path}/generator/{mode}.md`
|
|
||||||
|
|
||||||
Substitute variables:
|
|
||||||
- `{{MAX_FILES_TO_READ}}` → from config scopeBudgets
|
|
||||||
- `{{MAX_LINES_TO_WRITE}}` → from config scopeBudgets
|
|
||||||
- `{{MAX_FILES_TO_MODIFY}}` → from config scopeBudgets
|
|
||||||
- `{{MODE}}` → mode
|
|
||||||
- `{{ITERATION}}` → current iteration
|
|
||||||
- `{{MAX_ITERATIONS}}` → max iterations
|
|
||||||
- `{{LOOP_DIR}}` → absolute path to `.loop/`
|
|
||||||
- `{{PROJECT_ROOT}}` → project root
|
|
||||||
- `{{CURRENT_STORY_ID}}` → story ID
|
|
||||||
|
|
||||||
### 4d. Capture Pre-Generator Git State
|
|
||||||
|
|
||||||
Run `git rev-parse HEAD` and save the SHA.
|
|
||||||
|
|
||||||
### 4e. Dispatch Generator Agent
|
|
||||||
|
|
||||||
```
|
|
||||||
Agent(
|
|
||||||
prompt: <assembled generator prompt>,
|
|
||||||
description: "Generator: {story.id}",
|
|
||||||
subagent_type: "general-purpose",
|
|
||||||
mode: "bypassPermissions"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4f. Check Completion Signal
|
|
||||||
|
|
||||||
If output contains `<promise>COMPLETE</promise>`, report done and stop.
|
|
||||||
|
|
||||||
### 4g. Evaluator (unless skipped)
|
|
||||||
|
|
||||||
If `--skip-eval` or `config.skipEval` is true, skip to 4h and treat as PASS.
|
|
||||||
|
|
||||||
Otherwise, read and concatenate:
|
|
||||||
1. `{prompt_path}/evaluator/_base.md`
|
|
||||||
2. `{prompt_path}/evaluator/{mode}.md`
|
|
||||||
|
|
||||||
Substitute same variables plus `{{PRE_GENERATOR_SHA}}` and `{{CURRENT_STORY_ID}}`.
|
|
||||||
|
|
||||||
```
|
|
||||||
Agent(
|
|
||||||
prompt: <assembled evaluator prompt>,
|
|
||||||
description: "Evaluator: {story.id}",
|
|
||||||
subagent_type: "general-purpose",
|
|
||||||
mode: "bypassPermissions"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Parse verdict:
|
|
||||||
- `<verdict>PASS</verdict>` → PASS
|
|
||||||
- `<verdict>REJECT</verdict>` → REJECT, extract reason
|
|
||||||
- No verdict → REJECT (fail-safe)
|
|
||||||
|
|
||||||
### 4h. Update State
|
|
||||||
|
|
||||||
**PASS:** Set `passes: true` in prd.json. Report: **{story.id} PASSED**
|
|
||||||
|
|
||||||
**REJECT:** Increment `rejections`, append `[REJECTED] {reason}` to `notes`. Report: **{story.id} REJECTED** — {reason}
|
|
||||||
|
|
||||||
If `rejections >= evalRetries`: set `blocked: true`. Report: **{story.id} BLOCKED**
|
|
||||||
|
|
||||||
### 4i. Append Progress
|
|
||||||
|
|
||||||
Append to `.loop/progress.md`:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
### {story.id} — {story.title}
|
|
||||||
Date: {date}
|
|
||||||
Iteration: {N}
|
|
||||||
Verdict: {verdict}
|
|
||||||
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4j. Continue
|
|
||||||
|
|
||||||
Show: `{passed}/{total} stories complete`
|
|
||||||
|
|
||||||
Continue to next iteration.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Loop Exit
|
## Monitoring
|
||||||
|
|
||||||
> **Loop Complete**
|
If the user asks about progress (e.g., "status", "how's it going", "check progress"):
|
||||||
> - Iterations: {N}
|
|
||||||
|
1. Read `.loop/prd.json` — count passed/failed/blocked stories
|
||||||
|
2. Read `.loop/progress.md` — show the latest session log entries
|
||||||
|
3. Capture recent tmux output:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux capture-pane -t agent-loop -p | tail -30
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Report:
|
||||||
|
|
||||||
|
> **Loop Status**
|
||||||
> - Stories: {passed}/{total} complete, {blocked} blocked
|
> - Stories: {passed}/{total} complete, {blocked} blocked
|
||||||
|
> - Current: {last story from progress.md}
|
||||||
|
> - tmux session: {running/stopped}
|
||||||
|
|
||||||
## Error Handling
|
---
|
||||||
|
|
||||||
- Agent fails or empty output → warn and continue
|
## When Loop Completes
|
||||||
- prd.json unparseable → stop
|
|
||||||
- User says "stop" → end loop, report status
|
The tmux session exits when `loop.sh` finishes. If the user asks for a summary:
|
||||||
|
|
||||||
|
1. Read `.loop/prd.json` for final story statuses
|
||||||
|
2. Read `.loop/progress.md` for the full session log
|
||||||
|
3. Check git log for commits made during the run
|
||||||
|
|
||||||
|
Report the final status and suggest `/agent-loop:triage` if any stories are blocked.
|
||||||
|
|||||||
Reference in New Issue
Block a user