review-ui
Skill3 starsChanged 24 days agoMITView on GitHub
Open a review in the browser and stay attached to it — the user comments on a diff, files or a transcript, asks about any of it while they read, and sends rounds you answer without the review ending
6 other projects use a version of this.
Adopted by
Most recently taken up by
- NVIDIA/kumo-enginetheir own version, first seen Oct 20, 2026
- XGENT-ai/skillstheir own version, first seen Oct 13, 2026
- dnywh/skillstheir own version, first seen Sep 16, 2026
- njt2810/claude-code-frameworktheir own version, first seen Sep 10, 2026
- kauffj/agent-configtheir own version, first seen Aug 28, 2026
- aaddrick/claude-pipelinetheir own version, first seen Feb 25, 2026
Other versions6 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 6
- aaddrick/claude-pipeline★ 128same name
- NVIDIA/kumo-engine★ 50same name
- kauffj/agent-config★ 8same name
- dnywh/skills★ 1same name
- njt2810/claude-code-framework★ 1same name
- XGENT-ai/skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
We split this skill into the rules it gives an agent
8 rules. 0 are common, 5 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
5
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 22
No argument: review current git changes
- Very specific: line 47
If that prints nothing, stop here and tell the user plainly: the review is installed with uv, which this machine does not have.
- Very specific: line 61
No argument, or diff → claude-review diff
- Distinctive: line 72
Start it in the background, with a log of its own, and note where the log is — your shell forgets the variable once the command returns.
- Distinctive: line 131
Run it in the background. It waits until the reader hands something over, prints it as one JSON object, and exits, and its exit is what …
- Very specific: line 252
Leave --message out and you are speaking first, which is worth as much as answering:
- Distinctive: line 298
After making the changes a round asked for, put the work line out and show them:
- Distinctive: line 321
Use it for what a paragraph in the panel would bury — where you did something other than what was asked, and why.
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Open the claude-review viewer so the user can read a change and mark it up.
It is a conversation, not a form. Every thread can be asked about while they are still reading, the panel on the right takes what no single line covers, and a round sends what they have written without ending the review — you answer, make the changes, take the diff again, and they carry on from where they were. None of that works unless something is there to answer, so the review runs in the background and you stay in its loop.
Waiting on it in the foreground is the other shape, and it is right only when there is nothing to talk about — it is at the end of this file. Do not start there: a review nobody is attached to tells the user on every thread that no agent is listening, where "Ask agent now" would stand, and gives them a panel they cannot write in.
Usage:
- No argument: review current git changes
last 3 commits,since v0.5.0,diff --base HEAD~3: review changes since a specific pointplan: review the current plan filetranscript: review the current conversation as a transcript
Three rules while a review is open
Answer questions as they arrive. A thread that goes quiet for ten minutes reads as a hang, and the reader is sitting in front of it.
Leave the changes for the round. Work through what the review asks when a round arrives, not the moment a question hints at it.
Say what you are doing while you do it (step 8). Everything you do to their code, the reader should be able to watch happening. A silent agent and a hung one look the same from a browser, and the difference matters to somebody who is waiting.
Steps
- Install or upgrade
claude-reviewto the latest version. It is installed with uv, so check first that uv is there:
If that prints nothing, stop here and tell the user plainly: the review is installed with uv, which this machine does not have; they can install it as https://docs.astral.sh/uv/getting-started/installation/ says, then runcommand -v uv/review-uiagain. Do not install uv yourself. Otherwise:uv tool install --upgrade claude-review Work out what is being reviewed:
plan→claude-review files <plan-file-path>(the path is in the "Plan File Info" section of your system prompt).transcript→claude-review transcript <path-to-jsonl>(the JSONL is at~/.claude/projects/<project-dir-hash>/<session-id>.jsonl).- Anything else is a diff review. Translate the argument into a
--base:- No argument, or
diff→claude-review diff last 3 commits→claude-review diff --base HEAD~3two last commits→claude-review diff --base HEAD~2since v0.5.0→claude-review diff --base v0.5.0- Any natural language describing a commit range → work out the git ref
and pass it as
--base
- No argument, or
The base is a starting point, not a commitment: the header lets the reader read the same working tree against a branch, a tag or an earlier round of this review.
Start it in the background, with a log of its own, and note where the log is — your shell forgets the variable once the command returns. It opens in their browser by itself:
log=$(mktemp -t claude-review.XXXXXX) setsid nohup claude-review diff > "$log" 2>&1 & for _ in $(seq 150); do grep -qE '^(Review ready at|Error|No )' "$log" && break; sleep 0.2; done echo "$log"; cat "$log"It waits until the log says where the review is — or why there is none: an error, or nothing to review — and gives up after about thirty seconds. A large tree can take git longer than that to read: if the log says neither yet, run the loop again. Detached, rather than a bare
&: started in the shell's own session, the review dies with that shell, and the next command you run takes the review down with it.setsidis the one that holds; where there is none — macOS ships nosetsid—nohup … &on its own is the fallback.The log then says
Review ready at http://127.0.0.1:<port>, whether or not a window opened. That port is the--port <port>every command below takes. Give them the address anyway: over ssh or in a container there is nothing to open, and a tab closed by accident needs the way back. Add--no-openafter the command only when you know a window would be wrong.The port is worked out from the repository and the base, so reopening the same review comes back to the same address — and to the draft left in it.
--portafter the command picks one yourself; if it is taken, the command says so. A review still open from before a/clear, or from another session, is not opened twice: the log saysError: this review is already open, at …with its address. Take its port, and go on with step 4 and the loop of step 5.The reader is in the review from the moment it opens, and until your first
waitthe panel tells them the agent has not joined yet. So start the loop from step 5 in your very next call, the moment you have the port, before catching up:waithands over only what happens after it, and nothing that step 4 prints goes away while you listen.- Catch up, if this review was already under way when you arrived:
claude-review catch-up --port <port>waithands over what happens next, never what already happened — so an agent that restarted mid-review knows nothing until somebody says something. This prints the round, a line per thread and the panel in short. It is an index on purpose:claude-review catch-up --thread comment-4gets that one thread in full, with its lines and every turn.--jsonis the same thing for a program to read rather than a person — worth it when you mean to count or filter rather than to catch up. The index lists each thread in short (thread_id,where,severity,body,turn_count, …); with--threadit is that thread in the same shape as a question'sthread. Reading a thread in full hands its images over to you; the index hands over nothing. - Stay in the loop until the review is over, one
waitat a time:
Run it in the background. It waits until the reader hands something over, prints it as one JSON object, and exits, and its exit is what brings you back to the review. Start it again after every event: waiting only between your own turns leaves the review unattended — the silence the first rule is about.claude-review wait --port <port> --until-event{"type":"question","question":{"question_id":"...","body":"...", "images":[...],"thread":{...}}}— answer it (step 6), then wait again.bodyandimagesare what is asked: the user's last reply in the thread, or the comment that opened it when they have said nothing since.threadis the whole thread it was asked in:thread_id;where, the place in plain words (src/a.py:42-47);anchor, the file, side and line range withquote, the lines it is about;bodyandimages, the comment that opened it;turns, everything said since, each with itsauthor,body,roundandimages— a question asked in a reply is the last of them; andseverity,resolvedandraised_by, which isauthoron a thread you opened yourself. Everyimagesholds absolute paths to screenshots the reader pasted, and the text beside it may be empty when a screenshot is all there is. A question about the story you told hangs on a block of its words instead:anchoris then{"kind":"story","block":{"at": "chapter","chapter":"images-kept","text":"doubt"},"quote":["<the words asked about>"],"outdated":false}, andwheresays it in words (story chapter images-kept, doubt). Answer it as any thread; to change the words, tell the story again.{"type":"message","message":{"message_id":"panel-1","body":"...", "threads":[...],"images":[...]}}— the user has said something in the agent panel, which is about the review rather than about one line: the plan, the tests, a file nobody commented on. Say what you do for it while you do it, withprogress --message(step 8), and answer it withsay(step 7). Any threads it points at come with it, in the same shape as a question'sthread.imagesare absolute paths to screenshots they attached, and the text may be empty when an image is the whole question: open each with your file reader before answering. They outlive the review in the system's temporary directory, so the last round's are still there. A message that beginsFeedback on claude-reviewis the user's feedback on this tool, not on the change: do as it says. Look for an issue like it (gh issue list --repo vrppaul/claude-review --search ...), answer with the title and body you will file and any issue you found, and rungh issue createonly once they say so.{"type":"round","round":{"number":1,"markdown":"..."}}— the user has sent a round. Say so first, withprogress(step 8): they wait on it. The markdown is the review itself; address it as you would a finished one, then take the diff again (step 9) and keep waiting. AnImage: /pathline under a comment or a turn is a screenshot pasted there: open it before answering what it came with.{"type":"cancel","cancel":{"message_id":"panel-1"}}— the user has taken back something they asked: a panel message, named by itsmessage_id, or a question asked in a thread, whosequestion_idthe same field then carries. Drop what you were doing for it if you still can, and say nothing about it unless it is already half done.{"type":"story_request","stale":null}— the change is wanted told as a story: the user asked for one, or has each review's story written as it opens, and is watching how long it takes. Say so first, withprogress(step 8), and put the line out with--doneonce the story is sent. It comes once nothing the user said is left for you, so the story is of the code their rounds left. Runclaude-review story --helponce: it shows the document whole, how long each of its texts may be, and what makes a story good for the person who reads it. Write the whole document to a file and send it withclaude-review story --port <port> --file <file>. A story the review refuses comes back with everything wrong at once, each fault at its field of the document: mend every one and send the document whole again. Then wait again. When it carriesstale({"round":2,"steps":[{"chapter":"…","file":"…","lines":"104-131"}],"left_out":5}), the story you told moved on in a round: these steps' lines changed, a step'slinesnull where its code is no longer found, andleft_outchanged lines are told by no step. Tell it again, whole, of the code as it now stands.{"type":"story_cancel"}— the user has stopped the story they asked for. Stop writing it, and send nothing.{"type":"timeout"}— nothing was asked. Only awaitwithout--until-eventprints it, after--seconds; wait again.{"type":"closed"}— the review is over. Stop waiting. The last round reached you as its own event just before this one; the background process also writes it to its log on the way out, which is where to look if you were not waiting at the time. Anything else you never took — a question, a panel message — follows it there, under "Left unread when the review ended": the server stops a moment after the review ends, so awaitmay find nobody listening rather thanclosed. A review no page opens within an hour ends by itself, and its log says "Nobody opened the review in time": the user did not close it. Tell them, and start it again as in step 3 when they want it.
Answer in the thread it belongs to, naming the question:
claude-review reply --port <port> --thread <thread_id> --question <question_id> - <<'EOF' ... EOFThe
-reads the answer from stdin, here a quoted heredoc closed byEOFalone at the start of its line, and everything you write below goes in the same way: inside double quotes the shell runs whatever sits in backticks and empties every$name, and an answer in Markdown is full of both.A thread can have more than one question waiting at once, which is why the answer names one: without it the answer is filed under the oldest question still waiting. Answer from what you know about this change — why you wrote it that way, what you considered and rejected. That context is the reason to route the question to you rather than to a fresh session.
Answer a panel message, naming the message:
claude-review say --port <port> --message <message_id> - <<'EOF' ... EOFThe panel is one conversation, so the answer lands under the message it names — and naming it is also what closes it: a message answered without its id goes on showing as worked on, with a Stop button, however much you have written about it elsewhere.
Optionally, say what only you can know about yourself — the panel shows it beside the review's own weight, with the time it was said:
claude-review status --port <port> --model opus-5 --context "53% of 1M"Report it when it changes, not on every turn. Say nothing and the panel shows nothing, which is better than a number that is a guess.
Leave
--messageout and you are speaking first, which is worth as much as answering:claude-review say --port <port> - <<'EOF' Both are green now — the second one needed the base read from the round rather than from the diff. EOFWork that finished while the reader was reading is news they would otherwise have to come and ask for. It arrives with a dot on the header chip and a count in the tab title, so it reaches them in another tab.
Say what you are doing, while you are doing it:
claude-review progress --port <port> --message <message_id> \ --file src/a.py --file src/b.py - <<'EOF' rewriting the answer handler EOFWaiting says only that something is happening; this says what. Send it again to change it — it replaces what was showing rather than adding to it.
--didand--stepare drawn as branches of the work, so three subagents read as three branches rather than as a sentence about three subagents; the files become chips the reader can jump by.It goes away when you answer the message it names, so a line started without
--messagehas nothing to clear it — send--donethe moment the work finishes. A spinner left running is the hang the third rule is about, with your name on it.--messageis optional here too: work you started for a round, or on your own, is worth showing under the same line. Send one whenever what you are doing changes — this is the third rule, and it is the only thing that makes a long silence readable as work.Two more, for what a paragraph cannot do:
claude-review say --port <port> --file src/a.py - <<'EOF' Renamed it here. EOF claude-review show --port <port> --file src/a.pysay --fileoffers a jump the reader takes when they want it.showtakes them there and marks the file for a moment — it moves somebody else's screen, so send it only when they asked to be shown something.- After making the changes a round asked for, put the work line out and
show them:
claude-review progress --port <port> --done claude-review retake --port <port>--donefirst, or the new diff lands under a spinner still saying what you were doing to the old one.retakeis for a diff review: files and a conversation have no diff to take again, so there tell them what changed withsayinstead. The open review reloads the diff and moves its threads onto it: one whose lines survived follows them, one whose lines are gone is marked outdated and keeps a copy of what it was written against. What comes back names the files that changed since the round began — read those again rather than the whole diff, and the reader can put that same list on screen alone. Point at a line, when what you have to say belongs on the code:
claude-review point --port <port> --file src/x.py --lines 118-130 \ --severity question - <<'EOF' I kept the old name here: renaming it broke two callers. EOFUse it for what a paragraph in the panel would bury — where you did something other than what was asked, and why. It becomes an ordinary thread the reader answers, settles or removes, drawn as yours rather than as one of their marks, and it does not count as their unsent work.
--side oldhangs it on a line the change removed, which is the one place the reader cannot always write themselves: under a narrower base the left of the diff belongs to that base, so their gutters are shut there. Yours is anchored in the review's own diff and is not.
While you work, the review says when the working tree has moved on and offers the user a "Retake" of its own. It never swaps the diff by itself, so nothing you change under a half-written comment throws it away.
The server says nothing on its own: claude-review --verbose <command> puts
its diagnostic log on stderr, which is the way to see what it is doing when
a review behaves oddly. Leave it off otherwise — the quiet is deliberate.
When there is nothing to talk about
A review you will not be attached to is one command, and it blocks until the user sends it:
claude-review diffThe review is printed to stdout when they send it; read it and address each comment. Everything above still exists on their screen — the threads, the panel, the offer of a round — but nothing answers, and the threads and the panel say so. So choose this only for a review you know will be one-way: a quick look at a small change, or a machine with no way to keep a process alive.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

