What comes back
Prose by default: a review is read more often than it is parsed — by the
person who wrote it and by the agent it is for, which reads prose as readily
as anything else and pays fewer tokens for it. --format json prints the
same review as structure, for the program that parses it:
{
"decision": "request_changes",
"summary": "The rename parser is the only part I'd hold up.",
"vcs": "jj",
"revset": "trunk()..@",
"repo_root": "/home/you/projects/slop-review",
"comments": [
{
"id": "c1",
"commits": [
{
"id": "rlrmnkssuyyv",
"short_id": "6b2964ad",
"subject": "Read commits without binding to a VCS"
}
],
"location": {
"path": "crates/core/src/vcs.rs",
"lines": {
"side": "new",
"start": 287,
"end": 291,
"quoted": " match (spec.find('{'), spec.find('}')) {"
}
},
"body": "This assumes the brace form. jj also emits a bare `a => b`.",
"first_sent": null
},
{
"id": "c2",
"commits": [{ "id": "kwpoztqyzznm", "short_id": "9c1f0b32", "subject": "Add .envrc" }],
"location": null,
"body": "Fix this up into the commit that added the file.",
"first_sent": "2026-09-17T16:13:05Z"
}
]
}
Every field is there so the agent can act without going back to the VCS: a
commit carries its subject, not just an ID, and quoted echoes the reviewed
source so the annotation can be found without re-reading a diff it never
received. side matters — new line numbers are valid in the file as of the
last commit in commits, old ones belong to before the first, so quoted
is the only reliable anchor for those.
commits has more than one entry when the reviewer was looking at an
accumulated range; the comment is then about the combined change, and line
numbers are relative to the parent of the first commit.
The two nullable anchors say how wide the remark is. location is null for
one about the commits themselves; location.lines is null for one about a
whole file. summary is null rather than "" when the reviewer left it
blank.
The prose that --format md prints — the default — carries the same
content, and is cheaper to read and harder to machine-handle. Pick per
agent.
Remarks sent before
first_sent is when a remark first reached an agent, as a UTC timestamp of
the form YYYY-MM-DDTHH:MM:SSZ, and null for one going out for the first
time. A remark is kept against the commits it was written over and comes back
for as long as they are unchanged — see progress — so a second
review of a stack the agent only partly rewrote carries remarks the agent has
already read. They are sent again rather than dropped: a second review with
two standing remarks and nothing new would otherwise look like a clean
approval, and the reviewer saw them come back in the window and chose to let
them stand. But a reader that acts on each remark once — a script that files
them somewhere, a log of what was said — needs to tell the two apart, and
this field is how.
Three things pin its meaning down. It is set once the review has left the
process, printed or written to the -o file, so a run that failed on the way
out has sent nothing. It is the first sending: a third review of the same
remark carries the same date as the second. And editing a remark's wording
clears it, because new words are a new remark to whoever reads them; the id
stays. The prose rendering says the same thing as a line under the summary
counting them and an italic Already sent on … line on each.