Skip to content

Pick up human generated plans from issues #22

Description

@ableinc

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.

Activity

  1. ableinc commented on Sep 6, 2026

    @ableinc
    OwnerAuthor

    Plan

    Pick up human-generated plans from issues (#22)

    Context

    Every issue currently goes through the same "plan" phase in internal/orchestrator/loop.go execute() (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 both agent-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)

    1. Scope: only phasePlan is short-circuited. phaseImplement is untouched — internal/orchestrator/phase.go (decidePhase, approvedPlan, extractPlan) needs no changes.
    2. 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.
    3. 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.
    4. 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):

    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): 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).

    6. Tests

    • internal/config/config_test.go: assert Default().GitHub.HumanPlannedLabel == "human-planned".
    • internal/orchestrator/report_test.go: assert extractPlan(humanPlanComment(...)) round-trips.
    • 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.

    Risk flags for reviewer


    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

  2. ableinc commented on Sep 6, 2026

    @ableinc
    OwnerAuthor

    implement

  3. ableinc commented on Sep 6, 2026

    @ableinc
    OwnerAuthor

    Opened a draft pull request for this issue: #24

    Tests failed (make test) — see the PR for output.

    Comment implement again if you want another attempt at this issue.

    coding-agent-loop run f85a9b37-859f-4072-9888-d233640c1afc

  4. added a commit that references this issue on Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions