PR Monitoring for T3 Code
A first-class "babysit the PR" mode for agent threads — UX, terminology, and flows.
1 · Why this should exist
Transcript history on this machine shows the request made ~27 times in four weeks (~22 Claude Code sessions, ~5 Codex-via-T3 sessions), sometimes four times in a single evening. The phrasing is nearly a template, and the failure mode is always the same: the agent silently stops monitoring and the user becomes the babysitter — re-nudging with "More comments", "You broke CI. Fix it", "Are you still going?". One session even hand-rolled the feature with self-scheduled wakeups every ~4.5 minutes, re-serializing PR state into each continuation prompt.
Two findings that should shape the design more than anything else: (1) the reviewers are bots (Bugbot, Macroscope, CodeRabbit) plus CI — a 10–40 minute active loop with a machine-checkable end state, not a days-long human wait. (2) The stop condition is never "merged" — it is always "all review bots approve + CI green". Merging stays with the user, every time. Monitoring therefore has a success state that is not the PR's terminal state, and that success moment is exactly when the thread should demand attention.
2 · Where it fits: a mode, not a status
Thread state in T3 Code today is three orthogonal axes: session status (running / idle / …), the settled lifecycle (settledOverride + the warm-thread rules from #4309), and the derived sidebar status (working / approval / input / failed / ready).
Monitoring should be a thread-level mode that wraps the existing statuses, not a fifth sidebar status. While babysitting, the thread genuinely alternates between existing states — it is working while addressing a comment and is idle between events. What's new is the wrapper: "this thread has an unfinished goal tied to an external signal, so don't treat idle as done."
What the mode does
- Mode on: suppresses the "Completed" pill and unread-completion treatment when a fix-up turn ends (a finished fix-up is not news), suppresses auto-settle, and keeps the agent session alive watching for PR events. The pill shows the mode instead: Monitoring PR #123 — and it stays that pill for the whole mode, including during fixes (activity goes in the sub-line).
- Inside the mode: normal statuses still surface. If the agent hits a permission prompt or genuinely needs a decision, the thread shows
approval/inputwith full prominence — monitoring must never swallow a blocked state. Silent stalling is precisely the failure mode this feature exists to kill. - Mode ends: on all-green (→ Ready to merge, loud), on PR merged/closed (existing auto-settle takes over — the #4309 warm logic already handles the post-merge follow-up burst), on explicit user stop, or when the session dies (see decision D2 — session-scoped, with a visible "Monitoring stopped" marker).
Inbox-zero alignment: a monitoring thread is the ultimate "in-flight, don't look at me" row — it recedes exactly like working threads do. But no running elapsed counter ("Working 2h 14m" reads as stuck). Show what it's waiting on instead. Legibility of the loop is the feature as much as the loop itself — it answers the recurring "Are you still going?".
3 · Terminology
| Candidate | For | Against |
|---|---|---|
| Babysit | The user's natural word (typed ~12×); memorable; Cursor precedent proves the concept | Borrowing a competitor's coined term reads as chasing; slightly jokey in a status pill |
| Monitoring ✓ | The user's other natural word; accurate; boring in a good way; works as pill label and prompt verb ("monitor the PR" triggers it naturally) | Generic — but generic is fine for a state label |
| Watching | Shortest pill text | Collides with GitHub "watch" semantics |
Recommendation: "Monitoring" as the formal state/pill. Don't fight the colloquialism — the agent enters the mode whenever the user says babysit / monitor / watch in a prompt. The terminology that matters more is the exit state: "Ready to merge" — it names the moment the user actually cares about, and it's the label that makes the feature feel magical.
4 · Mock UIs
4a · Sidebar
Monitoring rows recede like working rows; the sub-line replaces an elapsed counter with what it's waiting on. When gates go green, the row flips to full prominence.
Note the third row: an agent mid-fix keeps the steady Monitoring pill, with the activity spelled out in the sub-line ("addressing 2 review comments"). One calm pill for the whole mode — no state-flicker in the sidebar. (Decided in review: the pill does not flip to Working during fixes.)
4b · Thread header — monitoring strip
Lives at the top of the thread while the mode is active. Shows the gates (editable), the current wait state, and an always-visible stop.
a41c2f94c · All green — the payoff moment
Decided (D1): the Merge… button ships, always behind a confirmation dialog. Never auto-merge — the merge decision stays human, it just happens at the payoff moment without a tab switch.
4d · The one notification
History shows a consistent preference: quiet handling, one final report. No play-by-play pushes. Two push-worthy events only: all green, and stuck/escalated.
5 · Example end-to-end flow
Thread enters the normal working state. The babysit instruction is parsed from the prompt — no special UI needed to opt in.
Real PR, never a draft (drafts don't trigger review bots — encoded as default policy, §6). Conventional title, minimal description. Gates are inferred: CI + the three named bots.
Row recedes in the sidebar. Header strip shows gates. No "Completed" pill fires — the turn ending is not news. Sub-line: "2 checks pending · waiting on Bugbot".
The pill stays Monitoring throughout; the sub-line shows the activity ("addressing 2 review comments"). Agent verifies each claim against source before acting (default policy): fixes the legitimate null-check finding, replies to the false positive with a one-line dismissal, pushes. Sub-line returns to waiting-on. Still receded, still quiet.
Agent inspects: flaky ios-e2e job (fails on main too) → re-runs it with escalating suspicion. If it failed 3× with the same real assertion instead, the thread would escalate to Awaiting Input — full prominence, push notification, monitoring paused. It never fails silently.
The one success notification fires. Row flips to prominent/unread. Header strip shows the summary: 3 comments addressed, 1 dismissed, 2 fix commits. Monitoring mode ends.
Existing machinery takes over untouched: merged PR triggers auto-settle, and the #4309 warm-thread rule keeps it un-settled through any follow-up burst before it files itself away.
6 · Default policies (things the user currently re-types every time)
- Real PR, never draft — drafts don't trigger review bots (bit at least once in Codex).
- Verify bot claims against source before applying — no blind compliance; the user explicitly delegates judgment.
- Dismiss false positives with a brief reply, don't silently ignore and don't silently comply.
- Flaky-CI protocol: compare against main's CI, re-run once or twice with escalating suspicion, escalate on a repeated real failure.
- Rebase when the PR falls behind main — a staleness failure mode the user currently catches manually.
- Default gate: all requested reviewers/bots approve + all checks green. Never "until merged".
7 · Entry, exit, and control
- Entry (primary): natural language — the flow is always bundled into the initial prompt in practice, so the agent invokes a "start monitoring" transition itself when the user says babysit/monitor/watch.
- Entry (secondary): a "Monitor after creating" checkbox on the create-PR dialog, and a toggle in the thread header — for discoverability and for attaching monitoring to an already-open PR ("Bugbot left comments. babysit this" happened multiple times).
- Control: always-visible "Stop monitoring"; gates visible and editable in the strip.
- Time budget: optional, not the default gate — one historical request said "at least 30 minutes", but the bot-approval gate is what's actually used.
- Escalation: a defined "I'm stuck" transition into the existing
inputstate (repeated real CI failure, merge conflict needing judgment, a bot comment the agent disagrees with but can't dismiss). Loud, never silent.
8 · Decisions (resolved with Theo, July 23)
9 · Feasibility note (one paragraph, as promised)
The 30-second VCS poller already delivers PR state, and there's a clean changeRequestState → settled pipeline to extend. What does not exist yet: review-comment ingestion. The session-scoped decision (D2) makes the other big gap — a server-side re-wake mechanism — unnecessary for v1: the live agent session is the watcher, so "monitoring" is closer to a structured, first-class version of the wakeup loop one agent already improvised, with the mode/pill/gates/circuit-breaker living in thread state around it. The exit path deliberately hands off to the untouched #4309 warm/settle logic. Server-side durability (surviving restarts) remains the natural v2 upgrade if dead-session stops turn out to hurt in practice.
10 · Proposed v1 scope
V1 = the actual observed loop, tightly scoped: natural-language entry · bot reviews + CI as universal gates (D3, D4) · quiet fix-up cycles under a steady Monitoring pill (D6) with a visible waiting-on strip · wake-cycle circuit breaker (~10) escalating into the existing input state (D5) · one "Ready to merge" notification · confirm-to-merge button, never auto-merge (D1) · session-scoped monitoring with a simple "Monitoring stopped" marker on death (D2) · hand-off to existing warm/settle on merge. Defer: per-repo gate config, human-reviewer gates, spend display, server-side durability/auto-resume.