Skip to content

feat: REST review sessions for agent handoff - #3

Draft
jscheid wants to merge 5 commits into
fix/open-in-editor-guardfrom
feat/review-snapshot
Draft

feat: REST review sessions for agent handoff#3
jscheid wants to merge 5 commits into
fix/open-in-editor-guardfrom
feat/review-snapshot

Conversation

@jscheid

@jscheid jscheid commented Sep 4, 2026

Copy link
Copy Markdown

Stacked on #2, which is stacked on #1. The diff below is only this branch's own changes.

Lets an agent start a review, hand the person its URL, and read their comments back over plain HTTP while it waits: bounded waits, an event journal, replies, non-destructive resolution, and a completion snapshot. This replaces the stdout NDJSON protocol this PR first proposed; the fork's waysact branch carries this series merged with the --title contribution.

What it adds

  • An authoritative in-memory review store: a version for the comment collection, a cursor over an event journal, and a completion latch with a reason (browser_idle, review_timeout, agent_stop).
  • Seven session-checked routes under /api (X-Difit-Session required), waits capped at 25 s, pages of at most 100 events, one error envelope. docs/agent-review-rest.md documents them with runnable examples for an event loop and a batch loop.
  • --background prints one JSON handshake (sessionId, port, pid, publicUrl, apiUrl, cursor) and exits. The review finishes on its own deadline and the server exits after --cleanup-grace. --timeout defaults to one hour for background reviews only; a foreground launch has no deadline unless one is set, and a foreground --keep-alive stays open for later rounds.
  • The browser keeps queued edits apart from the acknowledged snapshot, shows conflicts with retry and discard, resends once when a conflict refresh replays cleanly, and renders thread resolution.
  • The comment CLI pins to the launch review and tolerates non-JSON error bodies; legacy writes on other selections keep their version check. Test files drop non-null assertions in favour of a must(value, reason) helper, and startServer types its server as present.

Commits

Five, each signed: the shared public-url and port helpers and the bounded shutdown (unchanged from the earlier series), the REST protocol, the foreground lifecycle policy, and the once-only resend after a clean conflict refresh. The last one is separate so it can be dropped if the strict explicit-retry policy is preferred.

Verification

pnpm test 78 files, 1232 passed, 2 skipped · tsc, oxlint, oxfmt, knip and pnpm build clean. A cold review of the whole diff at high effort produced 10 correctness findings, all fixed with red-first tests. A person reviewed a real diff in the browser while an agent drove the loop over REST: the comment arrived as events, two replies and a resolution appeared in the open page without a reload, closing the tab finished the review with browser_idle, and stop returned the final snapshot with that reason kept. An earlier tip of the series was also driven through the sandbox's TLS edge with headless Chromium.

Notes for the reviewer

  • Agent routes and the selection-less comment CLI are pinned to the launch selection; a person switching revisions in the page cannot redirect them. Other revision pairs keep upstream's behaviour and are addressed by naming them.
  • Completion moves the journal cursor without moving the comment version. The two numbers are never derived from each other.
  • Replies carry a client-chosen id, so a retry after an ambiguous failure replays the original instead of duplicating it.
  • Nothing is persisted. A sessionId from a dead process is gone, and the guide says to report a lost server rather than infer completion.

🤖 Generated with Claude Code

jscheid and others added 5 commits September 7, 2026 12:28
The reverse proxy encodes the port in the hostname and the port is not known until the server binds, so --public-url takes a {port} template rather than a literal.
A shutdown path that claims the right to exit must not be able to trap the process if the work it does first stalls.
An authoritative in-memory review store with a comment version, an
event-journal cursor and a completion latch, exposed through seven
session-checked routes with waits bounded at 25 seconds. --background
prints one JSON handshake and exits; completion, cleanup and process
exit are separate steps set by --timeout, --idle-grace and
--cleanup-grace. The browser queues edits against the acknowledged
snapshot and shows conflicts instead of merging over an agent's reply.
Replaces the stdout NDJSON protocol. See docs/agent-review-rest.md.

Co-Authored-By: Claude Code c/o Julian Scheid <julian+claude-code@evergiving.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two regressions against upstream's foreground behaviour, which the plan
says to keep. A foreground --keep-alive closed comment input once the
browser went idle, which breaks the documented multi-round flow with
`difit comment add`; idling now only latches completion when the
process would exit anyway. And every foreground launch inherited the
background one-hour default deadline, ending an open review under the
person; the default now applies to background reviews only, and
limits.timeoutMs reports null when no deadline is armed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
After a 409 the hook refreshed and then always parked the queue in
'conflict', even when every pending edit replayed cleanly onto the
refreshed snapshot, so concurrent user writes sat browser-only until
the user noticed. Each edit records the value it was made against, so
a clean replay never resends a stale collection: send it once without
asking. A second 409, or a replay that does not apply, parks the queue
as before so continuous contention cannot livelock.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@jscheid
jscheid force-pushed the feat/review-snapshot branch from aea29cd to c748447 Compare September 7, 2026 11:07
@jscheid jscheid changed the title feat(cli): emit the review as NDJSON for agent handoff feat: REST review sessions for agent handoff Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant