Skip to content

Iterate on open feedback PRs (same branch, more commits) #3

Description

@ezzcodeezzlife

Summary

When the first PR is close but not right, let the same feedback continue on the same branch / same PR instead of opening a duplicate. Today every widget submit is a brand-new sandbox, branch feedback/f2c-{id}, and PR.

“Iterate” here means follow-up instructions → more commits on the existing PR, not “merge everything into one mega-branch” (that idea is covered — and rejected — in the base-branch issue).

Current behavior

One submission = one isolated run:

Step Implementation
Branch branchNameForFeedback(id)feedback/f2c-{safeId} (lib/feedback-agent/e2b-feedback-pipeline-core.ts)
Clone Always from GitHub default branch (bootstrap-clone.sh + e2b-github.mjs default-branch)
PR finalize-feedback.sh pushes that unique head and opens a PR onto the default base
Status CODINGWAITING_FOR_REVIEW / FAILED / MERGED (WidgetFeedbackStatus)
GitHub webhook app/api/github/webhook/route.ts matches prUrl and sets MERGED or WAITING_FOR_REVIEW
Widget Local history in iframe localStorage only; no “add more context” on an in-flight item
Dashboard List + link to PR (components/repo/repo-feedbacks-panel.tsx); no retry / amend

There is no way to send a second prompt that checks out the existing feedback/f2c-… branch and pushes another commit.

Problem

Client: “the button is still too small.” Owner today either:

  1. Asks them to submit again → second quota hit, second PR, two diffs to reconcile, or
  2. Fixes it by hand, which is the job we claimed to automate.

Duplicate PRs also fight if they touch the same files. Iteration on the open PR is how a human intern would work.

Proposed design

Product rule

Iterate = same WidgetFeedback row, same head branch, same PR. New agent run, additional commit(s). New widget submits that are unrelated still create new feedback rows (current behavior).

Do not dump follow-ups onto a shared feedback branch. Independent heads are what keep PRs reviewable.

Who can iterate

v1: the repo owner, from the dashboard (and later the widget if we can identify the same browser).

Reasons:

  • Widget submitters are anonymous. Auto-attaching a stranger’s second message to a PR is a moderation / prompt-injection problem.
  • Owners already review PRs; “Add instructions and re-run” next to WAITING_FOR_REVIEW / FAILED is the natural control.
  • Quota still decrements (another sandbox). Show remaining quota on the button.

v2 (optional): widget local history, if status is WAITING_FOR_REVIEW and localStorage has that id, show “Add a note for the developer”. Treat as untrusted extra context; owner still has to press Run, or auto-run only if we add a per-repo “allow visitor follow-ups” toggle (default off).

States

Current status Iterate allowed?
CODING No — queue or disable; one sandbox per feedback at a time
WAITING_FOR_REVIEW Yes — checkout existing branch (not default base), apply new instructions, push
FAILED Yes — retry with extra instructions or retry as-is
MERGED No — tell them to submit new feedback (base has moved). Avoid rewriting history on main.

If the GitHub PR is closed unmerged, treat like FAILED / allow reopen or new PR from same branch (GitHub allows reopen). Prefer: reopen if still the same head SHA relationship.

Pipeline changes

bootstrap-clone.sh today: git clone --depth 1 -b "$BASE" then checkout -b "$F2C_BRANCH".

For iterate:

  1. Clone default (or configured base) or fetch the existing head: git clone --depth 1 -b "$F2C_BRANCH" if the remote branch exists.
  2. Prompt includes original feedback + follow-up thread (append-only list).
  3. Finalize: push to the same F2C_BRANCH. If PR already exists, do not create-pr again; just push. e2b-github.mjs create-pr will 422 on duplicates — detect existing PR by prUrl on the row.
  4. Status: set back to CODING while running, then WAITING_FOR_REVIEW.
  5. Email: either a distinct “agent updated the PR” template or skip (owner is the one who clicked). Do not spam send-pr-created-email again.

Store follow-ups on the row, e.g. followUps Json as [{ body, createdAt, source: "owner" | "widget" }], and include them in buildOpencodeFeedbackPrompt.

Dashboard UX

On a feedback card with an open PR:

  • Textarea: “Tell the agent what to change…”
  • Button: Update PR (uses 1 quota)
  • Disable while CODING
  • After click, existing auto-refresh (RouteAutoRefresh) already polls

Widget (v1 stretch / v2)

Only if local history id matches a still-open item. Otherwise too easy to attach noise to the wrong PR.

Assumptions

  • Follow-ups count against quota (UserFeedbackLimitEvent). Each run costs an E2B VM + MiniMax tokens (agentLlmCostUsd already on the row — append or store last-run; do not overwrite history blindly; a small AgentRun child table is nicer if we are touching schema anyway, but v1 can overwrite last-run metrics and keep the follow-up text list).
  • We never force-push to main / the base branch.
  • If the owner has merged locally and the remote PR is merged, GitHub webhook already sets MERGED — iterate button disappears.
  • Custom agent instructions on the repo still apply on every run.

Acceptance criteria

  • Dashboard: for WAITING_FOR_REVIEW and FAILED, owner can submit follow-up text and trigger a new sandbox.
  • New commits land on feedback/f2c-{id}; existing PR updates; no second PR.
  • Status returns to CODING then WAITING_FOR_REVIEW (or FAILED).
  • Original body + follow-ups appear in the new prompt and in a “Follow-ups” section on the PR (append to PR body via GitHub API, or a comment — comment is simpler and does not fight with the original markdown).
  • Quota increments by 1 per iterate; 429 path same as POST /f.
  • Concurrent iterate while CODING is rejected.
  • Merged items cannot iterate.

Out of scope

  • Chat-with-the-agent inside the widget for anonymous visitors (v2).
  • Reading GitHub review comments and auto-replying (nice, separate issue).
  • Stacking unrelated tickets on one branch.

Implementation notes

  • lib/feedback-agent/run-e2b-feedback-agent.ts — add mode: "create" | "iterate", skip create-pr when prUrl set.
  • lib/feedback-agent/e2b/bootstrap-clone.sh — clone/fetch existing head when F2C_ITERATE=1.
  • lib/feedback-agent/e2b/e2b-github.mjs — optional find-pr by head ref.
  • app/api/e2b/webhook/route.ts — already keyed by feedback id; should keep working.
  • New dashboard server action or POST /api/feedback/[id]/iterate.
  • Prompt builder: thread the conversation.

Risks

  • Stale iterate: owner iterates after they already pushed extra commits by hand on that branch. Agent should git pull the head first.
  • Shallow clone (--depth 1) may be insufficient to iterate if we need merge-base. For iterate, clone the head branch at depth 1 (the branch already contains the first commit) rather than rebasing from default each time. If default has moved, do not auto-rebase in v1 (conflict hell). Document that iterate is “continue this branch”, not “replay on latest main”.
  • Prompt injection via visitor follow-ups if we enable widget v2 — keep owner-gated in v1.

See also

  • Configurable PR base branch (orthogonal: where the PR targets; iteration still uses unique heads)
  • Element picker (follow-up can keep the same selected node)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:agentE2B sandbox, OpenCode, GitHub PRsarea:widgetEmbeddable widget, iframe, parent scriptenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions