The Built-in Review
With [review] interactive = "builtin" (the default), Enter on the brief
walks the hunks one at a time in heph's own screen. It needs no other program
and always works.
┌ review: main ───────────────────────────────────────────────────────────────┐
│[1/3] src/auth.rs (+14 -3) │
│hunk 1 (lines 23-31) │
│why: Read the JWT secret from the environment so the key never lands in the │
│ binary. (edit #4) │
│ │
│@@ -23,7 +23,9 @@ impl Auth { │
│- let secret = "s3cr3t"; │
│+ let secret = std::env::var("JWT_SECRET") │
│+ .expect("JWT_SECRET must be set"); │
│ │
│(a)ccept (r)eject (c)omment (e)dit (s)kip (q) reject rest (u)ndo Esc: stop │
└──────────────────────────────────────────────────────────────────────────────┘
The header counts the hunks and names the file with its total added and removed
lines. why: is the rationale, with the calls behind it in parentheses. The
diff is colored: additions green, removals red, hunk headers cyan. Up, Down,
PgUp, and PgDn scroll a long hunk.
The keys
| Key | Does |
|---|---|
a | Accept the hunk as it is. |
r | Reject it without comment. The model is told it was refused. |
c | Reject it with a comment. A line opens; type why, Enter sends, Esc cancels the comment (the hunk stays undecided). An empty comment is a plain rejection. |
e | Edit the file in your editor. The file opens as the model proposed it; what you save is the file as it will be applied. Quitting without saving leaves the hunk undecided. |
s | Skip. The hunk is rejected without comment, exactly as r. |
q | Reject everything not yet decided and end the review. |
u, Backspace | Undo: back to the previous hunk, its decision taken back. From the first hunk, back to the brief. |
Esc | Stop here. What you decided stands; the hunks you did not reach wait in the worktree for the next review. Before any decision, back to the brief. |
After the last hunk the review closes and heph does the rest: keeps what you accepted, records what you rejected, and either applies or sends the model another round (Rejections, Comments, and the Next Round).
Stopping partway
Esc in the middle of a review is not a cancel. The hunks you accepted are
kept, the ones you rejected are gone and become constraints, and the ones you
never reached are left in the worktree on top of what you accepted, still
unreviewed. The turn ends with the review waiting; the model gets no round
meanwhile, but is told what was decided so far. /review picks the review up
with exactly the undecided hunks, each with its reason; so does your next
prompt, before its turn starts. Nothing is lost by stepping away, and nothing
undecided is ever taken as accepted or rejected.
Editing a hunk
e is for when the model's change is nearly right. Heph copies the file as the
worktree holds it, with every hunk of the proposed change in it, to a temporary
file and opens $VISUAL (or $EDITOR, or vi) on the copy, suspending its
screen while the editor runs. Save and quit, and the saved text is the file as
it will be applied, committed on the turn's chain as user: edited in review.
Because the whole file is what you saved, an edit decides the file's other hunks
too: what is in the saved file is what lands, whatever you pressed on them. If
nothing else in the review was rejected or commented on, the turn ends there
with your version applied; the model is not consulted again. If something was,
the model's next round is told the hunk was
EDITED BY THE USER; the file now holds their version, and it works from your
text. Use e when you want the last word on a file, c when you want the model
to try again.
A comment is worth more than a rejection
r tells the model that a hunk was refused. c tells it why, in your
words, beside the reason it gave. The model converges in one round on a comment
where a bare rejection often takes two or three, because it can see which
reasoning was wrong. When you know why you are rejecting, say so.
Rendering diffs with a pager
[review] pager names a program that renders each hunk before it is shown, for
the review heph exec runs on a plain terminal:
[review]
pager = "delta"
There the hunk is piped through it and its output shown in place of heph's own coloring; anything that reads a unified diff on stdin and writes to stdout works, and a pager that fails falls back to the plain coloring. The interactive session draws its own diffs and does not use the pager yet.