Repository navigation
Iterate on open feedback PRs (same branch, more commits) #3
Description
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 | CODING → WAITING_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:
- Asks them to submit again → second quota hit, second PR, two diffs to reconcile, or
- 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/FAILEDis 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:
- Clone default (or configured base) or fetch the existing head:
git clone --depth 1 -b "$F2C_BRANCH"if the remote branch exists. - Prompt includes original feedback + follow-up thread (append-only list).
- Finalize: push to the same
F2C_BRANCH. If PR already exists, do notcreate-pragain; just push.e2b-github.mjs create-prwill 422 on duplicates — detect existing PR byprUrlon the row. - Status: set back to
CODINGwhile running, thenWAITING_FOR_REVIEW. - Email: either a distinct “agent updated the PR” template or skip (owner is the one who clicked). Do not spam
send-pr-created-emailagain.
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 (agentLlmCostUsdalready on the row — append or store last-run; do not overwrite history blindly; a smallAgentRunchild 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_REVIEWandFAILED, 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
CODINGthenWAITING_FOR_REVIEW(orFAILED). - 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
CODINGis 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— addmode: "create" | "iterate", skip create-pr whenprUrlset.lib/feedback-agent/e2b/bootstrap-clone.sh— clone/fetch existing head whenF2C_ITERATE=1.lib/feedback-agent/e2b/e2b-github.mjs— optionalfind-prby 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 pullthe 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)
Activity
ezzcodeezzlife commentedon Aug 18, 2026
Related: PR base branch #6 (orthogonal — unique heads stay), element picker #1