You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Some issues will be created with the plan already attached and the plan wasn’t created by the agent. Whenever you see the labels agent-ready and human-planned together that means you should grab the plan that already exists in the issue. Once you’ve updated your database with the plan, reply to the issue telling the user to type “implement” to continue with the plan and create the PR.
Every issue currently goes through the same "plan" phase in internal/orchestrator/loop.goexecute() (line 594): clone the repo, open a worktree, run Claude with --permission-mode plan to draft a plan, post it as an issue comment, cache it in the plans SQLite table. A human replies implement to proceed. Issue #22 wants a shortcut: when an issue carries bothagent-ready and a new human-planned label, the plan already exists in the issue body (written by a person), so the daemon should skip the Claude planning run, adopt the issue body as the plan, save/post it the same way a Claude-drafted plan would be, and stop — leaving the same "reply implement" call to action. Everything downstream (approval detection, the implement trigger, plan recovery, the actual implement run) is phase/marker-driven and already agnostic to how the plan was produced, so none of it needs to change.
Design decisions (issue is ambiguous on these — flagging the chosen readings)
Scope: only phasePlan is short-circuited. phaseImplement is untouched — internal/orchestrator/phase.go (decidePhase, approvedPlan, extractPlan) needs no changes.
Re-plan after feedback: decidePhase re-enters phasePlan when a human comments anything other than implement after a plan (phase.go line 114). For a human-planned issue this naturally re-fires the same short-circuit and re-reads the (possibly edited) issue body — no special-casing.
Empty body: if human-planned is set but the body is blank, that's a misconfiguration — return a real error so it goes through the normal failure path (failureComment, agent-failed, backoff retry), rather than silently falling back to a Claude-drafted plan.
Discovery: no change to gh.Client.SearchIssues (internal/gh/gh.go:221) — it still searches only on the single trigger label. human-planned is checked post-fetch via the existing gh.Issue.HasLabel (gh.go:155), same pattern already used for the trigger label itself (loop.go lines 607, 495).
Changes
1. internal/config/config.go — add HumanPlannedLabel string \json:"human_planned_label"`toGitHubConfig(nearPlanLabel, line 67), default "human-planned"inDefault()(near line 215). No migration bump needed —internal/config/migrate.go's Migrate` diffs JSON trees generically.
2. config.example.json — add "human_planned_label": "human-planned", next to "plan_label" (line 7).
3. internal/orchestrator/report.go — add humanPlanComment(plan, runID string) string, mirroring planComment (line 218): same markerPlan + "## Plan\n\n" + plan + "\n\n---\n\n" structure (so extractPlan/decidePhase in phase.go can't tell it apart from a Claude-drafted comment), but no model/cost line, and text noting the plan came from the issue body. Reuses truncate/maxPlanCommentChars already in this file.
4. internal/orchestrator/loop.go — in execute(), right after the phase switch (after lines 624-632) and before cloning/worktree setup (line 634):
New method adoptHumanPlan, modeled directly on the existing plan-posting block (loop.go 803-827): trims issue.Body, errors if empty, posts humanPlanComment via o.opts.GH.Comment, saves via o.opts.Store.SavePlan, swaps labels via o.setLabels (add PlanLabel, remove WorkingLabel), sets store.StatusPlanned, records an o.event, and calls o.opts.Discord.PlanPosted(ref, nil, 0) — confirmed PlanPosted (internal/discord/notifier.go:341) tolerates a nil *claude.Result. Crucially this makes no call to repoMetadata/EnsureRepo/AddWorktree/Runner.Run.
5. README.md — document github.human_planned_label in the labels table (~414-418) and config reference (~489), and add a sentence to the Plan lifecycle step (~245-292).
internal/orchestrator/adopt_test.go: new integration test using existing testOrchestrator/stubGH/openTestStore fixtures (lines 27-106), shaped like TestADeliveredIssueLosesItsTriggerLabel (line 314). testOrchestrator already points cfg.Claude.Binary at a nonexistent path specifically so any accidental fallthrough into the real Claude-invoking path fails loudly — this is the test's main value. Assert: plan comment posted, no pr create, LatestPlan matches the issue body. Add a second case for the empty-body path asserting agent-failed and no saved plan.
Verification
go build ./..., go vet ./...
go test -race ./internal/config/... ./internal/orchestrator/..., then full make test
Optional manual check: go run ./cmd/agent --once --dry-run against a repo/issue carrying both labels with a plan in the body; confirm the comment posts verbatim and no worktree is created.
Re-reading the issue body on every feedback round (decision Flow Enhancements (#1) #2) assumes humans edit the body to revise; if the intent was "only ever adopt once," that needs an extra guard checking no plan comment exists yet.
Reply with exactly implement to approve this plan and start the change. Reply with anything else and the plan will be revised to address it.
coding-agent-loop run dd75a1c5-7ec9-4d9f-99c3-15d7d2915bb8, model claude-sonnet-5, cost $1.4086
Activity
ableinc commentedon Sep 6, 2026
Plan
Pick up human-generated plans from issues (#22)
Context
Every issue currently goes through the same "plan" phase in
internal/orchestrator/loop.goexecute()(line 594): clone the repo, open a worktree, run Claude with--permission-mode planto draft a plan, post it as an issue comment, cache it in theplansSQLite table. A human repliesimplementto proceed. Issue #22 wants a shortcut: when an issue carries bothagent-readyand a newhuman-plannedlabel, the plan already exists in the issue body (written by a person), so the daemon should skip the Claude planning run, adopt the issue body as the plan, save/post it the same way a Claude-drafted plan would be, and stop — leaving the same "replyimplement" call to action. Everything downstream (approval detection, theimplementtrigger, plan recovery, the actual implement run) is phase/marker-driven and already agnostic to how the plan was produced, so none of it needs to change.Design decisions (issue is ambiguous on these — flagging the chosen readings)
phasePlanis short-circuited.phaseImplementis untouched —internal/orchestrator/phase.go(decidePhase,approvedPlan,extractPlan) needs no changes.decidePhasere-entersphasePlanwhen a human comments anything other thanimplementafter a plan (phase.go line 114). For a human-planned issue this naturally re-fires the same short-circuit and re-reads the (possibly edited) issue body — no special-casing.human-plannedis set but the body is blank, that's a misconfiguration — return a realerrorso it goes through the normal failure path (failureComment,agent-failed, backoff retry), rather than silently falling back to a Claude-drafted plan.gh.Client.SearchIssues(internal/gh/gh.go:221) — it still searches only on the single trigger label.human-plannedis checked post-fetch via the existinggh.Issue.HasLabel(gh.go:155), same pattern already used for the trigger label itself (loop.go lines 607, 495).Changes
1.
internal/config/config.go— addHumanPlannedLabel string \json:"human_planned_label"`toGitHubConfig(nearPlanLabel, line 67), default"human-planned"inDefault()(near line 215). No migration bump needed —internal/config/migrate.go'sMigrate` diffs JSON trees generically.2.
config.example.json— add"human_planned_label": "human-planned",next to"plan_label"(line 7).3.
internal/orchestrator/report.go— addhumanPlanComment(plan, runID string) string, mirroringplanComment(line 218): samemarkerPlan+"## Plan\n\n"+ plan +"\n\n---\n\n"structure (soextractPlan/decidePhasein phase.go can't tell it apart from a Claude-drafted comment), but no model/cost line, and text noting the plan came from the issue body. Reusestruncate/maxPlanCommentCharsalready in this file.4.
internal/orchestrator/loop.go— inexecute(), right after the phase switch (after lines 624-632) and before cloning/worktree setup (line 634):New method
adoptHumanPlan, modeled directly on the existing plan-posting block (loop.go 803-827): trimsissue.Body, errors if empty, postshumanPlanCommentviao.opts.GH.Comment, saves viao.opts.Store.SavePlan, swaps labels viao.setLabels(addPlanLabel, removeWorkingLabel), setsstore.StatusPlanned, records ano.event, and callso.opts.Discord.PlanPosted(ref, nil, 0)— confirmedPlanPosted(internal/discord/notifier.go:341) tolerates a nil*claude.Result. Crucially this makes no call torepoMetadata/EnsureRepo/AddWorktree/Runner.Run.5. README.md — document
github.human_planned_labelin the labels table (~414-418) and config reference (~489), and add a sentence to the Plan lifecycle step (~245-292).6. Tests
internal/config/config_test.go: assertDefault().GitHub.HumanPlannedLabel == "human-planned".internal/orchestrator/report_test.go: assertextractPlan(humanPlanComment(...))round-trips.internal/orchestrator/adopt_test.go: new integration test using existingtestOrchestrator/stubGH/openTestStorefixtures (lines 27-106), shaped likeTestADeliveredIssueLosesItsTriggerLabel(line 314).testOrchestratoralready pointscfg.Claude.Binaryat a nonexistent path specifically so any accidental fallthrough into the real Claude-invoking path fails loudly — this is the test's main value. Assert: plan comment posted, nopr create,LatestPlanmatches the issue body. Add a second case for the empty-body path assertingagent-failedand no saved plan.Verification
go build ./...,go vet ./...go test -race ./internal/config/... ./internal/orchestrator/..., then fullmake testgo run ./cmd/agent --once --dry-runagainst a repo/issue carrying both labels with a plan in the body; confirm the comment posts verbatim and no worktree is created.Risk flags for reviewer
Reply with exactly
implementto approve this plan and start the change. Reply with anything else and the plan will be revised to address it.coding-agent-loop run
dd75a1c5-7ec9-4d9f-99c3-15d7d2915bb8, modelclaude-sonnet-5, cost $1.4086ableinc commentedon Sep 6, 2026
implement
ableinc commentedon Sep 6, 2026
Opened a draft pull request for this issue: #24
Tests failed (
make test) — see the PR for output.Comment
implementagain if you want another attempt at this issue.coding-agent-loop run
f85a9b37-859f-4072-9888-d233640c1afcMerge pull request #24 from ableinc/agent/issue-22-pick-up-human-gene…