diff --git a/README.md b/README.md index 1237d82..1140822 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,13 @@ gh search issues --label agent-ready ## What this is -You label a GitHub issue `agent-ready`. The daemon finds it, checks out a fresh git worktree, hands -the issue to Claude Code running headless, runs the repository's own test suite against whatever -Claude wrote, pushes a branch, and opens a **draft** PR that says what happened — including if the -tests failed. A human reviews and merges (or doesn't). The daemon never pushes to `main`, never -merges, and never touches an issue that isn't opted in. +You label a GitHub issue `agent-ready`. The daemon finds it, checks out a fresh git worktree, and +first has Claude Code produce a **plan** — posted as an issue comment, no edits made. A human reviews +the plan and replies `implement` to approve it (or anything else, which sends it back for a +revision). Only then does the daemon run the actual change, run the repository's own test suite +against whatever Claude wrote, push a branch, and open a **draft** PR that says what happened — +including if the tests failed. A human reviews and merges (or doesn't). The daemon never pushes to +`main`, never merges, and never touches an issue that isn't opted in. **Use case:** a backlog of well-scoped, low-risk issues (bug fixes, small features, chores) across repositories you own, that you'd rather review as a diff than write yourself — worked on @@ -98,7 +100,8 @@ sudo systemctl status coding-agent-loop.service # check status of process sudo journalctl -u coding-agent-loop # check system daemon logs (or at ~/.agent-loop/logs/) ``` -Label an issue `agent-ready` in one of the repositories you own, and the next poll picks it up. +Label an issue `agent-ready` in one of the repositories you own. The next poll posts a plan as a +comment on the issue; reply `implement` on that comment to have the daemon carry it out. ## CLI flags @@ -125,9 +128,23 @@ An issue is worked only if **all** of these hold: - no previous run delivered a PR for it, and it is not currently backing off after a failure (`run.retry_backoff`) - no open pull request already closes it +- the issue's comment history says it's this issue's turn to be worked (see below) -Labels mirror the state (`agent-working` → `agent-done` / `agent-failed`), but the SQLite claim -table is the source of truth — labels can be edited by humans mid-run, leases cannot. +**The issue's own comments are what decide the phase**, not a label or a database column. Every +comment the daemon posts is tagged with an invisible HTML marker, so it can tell its own narration +apart from a human reply: + +- No plan comment yet → **plan**: post a plan, then stop. +- A plan is posted and nothing from a human has followed it → **wait**: do nothing this poll. This + costs one `gh issue view` per poll, never a claim, a worktree, or a Claude run. +- The newest human reply after the plan is exactly `implement` (trimmed, case-insensitive) → + **implement**: run the actual change. +- The newest human reply after the plan is anything else → **plan**: treat it as feedback and post a + revised plan. + +Labels mirror this state (`agent-planned` while waiting on a reply, `agent-working` → +`agent-done` / `agent-failed` around a run), but the SQLite claim table and the issue's own comments +are the source of truth — labels can be edited by humans mid-run, leases and comment history cannot. Label edits are reconciled rather than fired blindly: the issue's current labels are read first, the edit is reduced to what actually changes, a status label the repository does not define yet is @@ -142,24 +159,33 @@ flight at a time), controlled by `run.max_concurrent_repos`. ## Lifecycle of one issue 1. **Discover** — `gh search issues --label