Repository navigation
Pick up human generated plans from issues #22
Description
Activity
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)
- Scope: only
phasePlanis short-circuited.phaseImplementis untouched —internal/orchestrator/phase.go(decidePhase,approvedPlan,extractPlan) needs no changes. - Re-plan after feedback:
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. - Empty body: if
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. - Discovery: no change to
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):if phase == phasePlan && issue.HasLabel(cfg.GitHub.HumanPlannedLabel) { return o.adoptHumanPlan(ctx, log, cand, runID, issue, ref) }
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 test- Optional manual check:
go 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
- Empty-body → hard failure (decision Require a human-approved plan before implementing an issue #3) is a judgment call; reviewer may prefer a silent fallback to Claude-drafted planning instead.
- 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
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.4086- Scope: only
- addedagent-plannedManaged by coding-agent-loopManaged by coding-agent-loopand removed
on Sep 6, 2026 implement
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-d233640c1afc- added and removedagent-plannedManaged by coding-agent-loopManaged by coding-agent-loop
on Sep 6, 2026 - added a commit that references this issue
on Sep 6, 2026
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.