A fast review window for agent handoffs. When an agent would say "open X and review it", it runs
vjuu X instead: a window opens with the markdown or diff, you comment on lines and end with Approve, Redo
or Discard. The verdict and your comments come back to the agent as markdown on stdout, anchored to file:line.
Runs on Windows 10/11 (WebView2), Linux (WebKitGTK 4.1: Debian 12+, Ubuntu 22.04+) and macOS (WKWebView). On Windows the window is frameless with its own title bar; macOS and Linux keep the native frame. macOS builds are compiled and tested in CI but not by hand.
winget install vjuu
Not yet: the winget package is waiting for Microsoft's
approval. Until then, use cargo or a .zip (below).
brew install kimvais/tap/vjuu
Not signed or notarised. Homebrew installs work as is; a binary downloaded by hand needs
xattr -d com.apple.quarantine vjuu once.
curl -fsSL https://vjuu.it/apt/vjuu.gpg | sudo tee /usr/share/keyrings/vjuu.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/vjuu.gpg] https://vjuu.it/apt stable main" | sudo tee /etc/apt/sources.list.d/vjuu.list
sudo apt update && sudo apt install vjuu
cargo install --locked vjuu
Or a .zip, .tar.gz or .deb from GitHub Releases. Building needs a
Rust toolchain, and on Linux also libwebkit2gtk-4.1-dev and libgtk-3-dev.
However you installed it:
vjuu setup
It installs three skills for Claude Code (~/.claude/skills) and Codex (~/.agents/skills), whichever you have:
| Skill | What it does |
|---|---|
vjuu |
tells agents to run vjuu in the background instead of asking you to open files |
ship |
commits what is left, rebases, pushes, opens a ready PR (GitHub) or MR (GitLab) if there is none, watches CI; never merges |
sync |
rebases the branch onto the default branch and pushes it with --force-with-lease |
ship and sync are what the question gate tells Claude to run instead of asking "say ship". If you already have
your own (a skill without vjuu's marker line, or ~/.claude/commands/ship.md), setup keeps yours. Run it again after
an upgrade. The skills are also a Claude Code plugin (claude plugin install vjuu@vjuu after
claude plugin marketplace add kimvais/vjuu), where they are /vjuu:ship and /vjuu:sync; use one or the other,
not both.
| Command | What it does |
|---|---|
vjuu docs/design.md |
markdown |
vjuu a.md b.md change.diff |
several files in one window, stacked |
vjuu change.diff |
diff or patch file |
vjuu site/index.html |
HTML page or claude.ai artifact, rendered as it looks once loaded; file:// URLs work too |
vjuu src/main.rs |
any other file: line-numbered, syntax-highlighted source |
vjuu --git main...HEAD |
runs git diff main...HEAD in the current directory |
vjuu --previous old.md plan.md |
a file as its changes since an earlier copy; d shows it in full |
vjuu --comments c.json plan.md |
show the comments the last review kept in c.json, read-only, and keep this review's there |
git show HEAD | vjuu - |
stdin; diff or markdown is detected |
vjuu --session "fix login" plan.md |
name the asking session in the title bar (automatic under Claude Code) |
vjuu last |
print the most recent review again |
vjuu start |
start the resident instance in the tray, e.g. at login; double-clicking vjuu.exe does the same |
vjuu stop |
stop the resident instance (before upgrading the exe) |
vjuu setup |
install the vjuu, ship and sync skills for Claude Code and Codex, and the question gate |
vjuu config |
settings: which Claude Code hooks open vjuu (see below) |
vjuu --help, vjuu --version |
all of the above, briefly; the version |
vjuu blocks until you give a verdict or close the window:
| Verdict | Key | The agent |
|---|---|---|
| Approve | Ctrl+S |
proceeds without asking again; applies minor comments on the way |
| Redo | Ctrl+R |
addresses your comments, then opens vjuu again |
| Discard | Ctrl+Z, or closing the window or tab |
drops the comments and does nothing |
Every review is also saved to %LOCALAPPDATA%\vjuu\reviews\, a discarded one with its comments, so a later session
can pick it up with vjuu last.
The first vjuu opens its window itself (~400 ms, mostly WebView2 starting) and starts a hidden
resident instance that keeps a pre-warmed tab. Later calls hand the document to it over a named
pipe and the review appears almost at once. The spare tab preloads fonts and renderers. The resident instance costs roughly 300 MB working set across
its WebView2 processes; vjuu stop ends it. VJUU_COLD=1 skips it.
The resident instance keeps every review in one window, a tab each, with a session's tabs side by side. One review
shows no tab strip. Closing a tab (its × or Ctrl+W) discards its review; closing the window discards every
review.
It also has a tray icon. An orange dot on it means a review is still open, and hovering it says how many. Click it to
bring the oldest one forward. Right-click it for a list of the waiting reviews, oldest first: the asking session, what
it asks (plan, question, permission, turn, or the file names), the repository and branch, and how long it has waited.
Click one to bring it forward; on Windows, pressing its digit does the same. The same menu has the settings and stops
vjuu. If a review opens behind others (Windows refuses to hand over focus while you type elsewhere), a notification
says so. Switch the icon and notifications off with vjuu config tray off. On Linux the icon needs a desktop that
shows StatusNotifier icons (KDE, or GNOME with the AppIndicator extension).
A new review comes to the front and takes the keyboard, unless you are in the vjuu window already: then it opens as a
tab behind the one you are in, marked with a dot. If coming to the front interrupts you, vjuu config focus off (or
"Bring new windows to the front" in the settings) opens every new review behind, each with a notification when the
tray is on.
| Case | First paint |
|---|---|
| Markdown or diff, cold | ~400-450 ms |
| Markdown, resident | ~15 ms |
| 6,600-line diff, resident | ~100-130 ms (highlighting runs after paint) |
| Key | Action |
|---|---|
↑ / ↓ (or k / j) |
Previous / next line or block |
← / → (or p / n) |
Previous / next file; with a single markdown file, previous / next heading |
Enter (or c) |
Comment on the current line, or on the selected text |
Ctrl+Enter |
In a comment: save it. In the settings: Apply. Nothing anywhere else |
Ctrl+V |
In a comment: paste an image too. vjuu saves it under reviews/images and the comment links its file, for the agent to read |
Ctrl+S |
Approve: the agent proceeds without asking again |
Ctrl+R |
Redo: the agent addresses your comments, then opens vjuu again |
Ctrl+Z |
Discard: drop the comments, the agent does nothing; in a comment, undo |
Esc |
Cancel the comment being written; close the settings or the help |
1–9 |
Pick that option of the choice block under the cursor (or of the only one); again to take it back. In a block that takes several, tick each on or off |
v |
Toggle unified / side-by-side diff |
w |
Ignore whitespace changes in a diff: a reindented line shows as unchanged; again to show them |
d |
A revised plan (or --previous): toggle its changes / the full file |
x |
Mark the diff file under the cursor viewed: folds it and ticks it in the sidebar; again to unmark |
o |
Fold / open the diff file under the cursor; lock files, minified and generated files start folded |
f |
Hide / show the sidebar (file list, or table of contents for markdown) |
Ctrl+Tab / Ctrl+Shift+Tab |
Next / previous tab |
Ctrl+1–Ctrl+9 |
That tab |
Ctrl+W |
Close the tab: discards its review |
Ctrl+, (⌘, on macOS) |
Settings |
F1 |
Help: the version and these keys |
Click any line or block to comment on it. To comment on a range, select text (across lines, paragraphs or diff
rows) and click Comment or press c. Links still open, except on HTML pages, where only in-page links work; clicks
inside a comment edit it. In a diff, click a file's header to fold or open it, or tick its Viewed box.
Themes, picked in the settings (Ctrl+,, or the gear in the title bar): Light (GitHub) and Graphite (Monokai code colours on
neutral dark grey), GitHub Dark, GitLab Light and Dark, Dracula, One Dark, Nord, Tokyo Night, Solarized, Gruvbox and
Catppuccin (each light and dark), or any theme of your own. Auto, the default, follows the system: one theme while it is light,
another while it is dark, and the dark one when the system does not say. Picking previews the theme; Apply keeps it. See Themes to make your own.
redo
# Review: docs/design.md (2 comments)
## docs/design.md:12-14
> quoted source lines
The comment.
## Overall
General comment, if any.
The first line is the verdict: approved, redo or discard. A discarded review sends no comments.
Deleted diff lines are marked (old) and use the old file's line number. A rendered HTML page has no line numbers:
its comments quote the text and say where it is, as ## site/index.html (#install) (the nearest id) or
## site/index.html (under "Install") (the nearest heading).
A ```choice block in a markdown document shows its list items as buttons; the other lines are the question.
Text before the first : is the label, the rest an explanation. Click a button or press its digit to pick it, and do
it again to take the pick back. Picks come first in the review:
```choice
How should vjuu handle artifacts?
1. Snapshot (recommended): small change, one frozen state
2. Live page: interactive, much bigger
```
## Choice: How should vjuu handle artifacts?
Snapshot (recommended)
An unanswered choice reads No answer.
A ```choice multi block takes any number of options: each click or digit ticks one on or off, and the
review lists the ticked labels in the order they are listed, joined by , .
The vjuu plugin also hooks into Claude Code, so a few moments open in vjuu by themselves. All five are on by default. The first vjuu window after a fresh install opens on the settings panel, where you can switch each one off.
Plan review. When Claude finishes a plan in plan mode, the plan opens in vjuu. Approve and Claude leaves plan
mode and carries it out, applying minor comments on the way. Redo and Claude revises the plan and asks again.
A revised plan opens as its changes since the version you last saw, with your earlier comments on the lines they were
on; press d for the full plan. vjuu keeps the plan and the comments per session in its data folder, under
sessions/claude/<session id>.
Discard, or close the window, and Claude Code's own approval prompt follows as usual.
Questions. When Claude asks you something (its AskUserQuestion tool), the questions open in vjuu as buttons,
under the message that led to them. Pick an answer to each and Approve, and they go to Claude as if picked in the
terminal. Comment anywhere, or leave a question unanswered, and Claude gets your picks and comments to read instead, so
you can answer in your own words. Nothing times out. Discard, or close the window, and Claude Code's own picker
asks. A question that takes several answers ticks each one on its own.
Turn review. When Claude finishes a turn in which it edited files, the diff of those files opens in vjuu, new files
included. Files changed by a Bash or PowerShell command (sed, a formatter, a code generator) show too: those are
the files that changed on disk since the turn started, in the session's checkout and in any of its worktrees a command
names. Redo and Claude acts on your comments straight away, and the result opens again. Approve and Claude
goes on to the next step (commit, ship) without asking. Discard and the turn ends. Turns without edits, edits
outside the git repository, and a diff you already reviewed open nothing. The diff is the files'
uncommitted changes, so changes an earlier turn made to the same files show too. A file deleted by a command, rather
than an edit tool, does not show.
Permission prompts. When Claude Code would ask whether Claude may run a command, edit a file or use another tool,
the request opens in vjuu: the command in full, the edit as a diff. Pick Allow, Always allow (Claude Code's
suggested rule, such as every npm test from now on) or Deny. Without a pick, Approve allows it once and
Redo denies it with your comment as the reason, so Claude can try another way; a comment next to Allow does not
reach Claude. Discard, or close the window, and Claude Code's own prompt asks. Plans and questions keep their own
windows.
Each hook gives up after an hour, and Claude Code carries on as if vjuu were not there.
Question gate. Once a review ends with a verdict, a turn that closes with "say ship", "Want me to…?", "Reply
yes and I'll…", "waiting on your go" or any other question or request for a go-ahead in prose only costs you a turn: the OK already came through vjuu, or no decision was needed. When Claude ends
a turn like that, the gate sends it back once, telling Claude to take the step (in a worktree under your worktrees
folder, that means running /ship) or to put a real decision in a vjuu review. It does not judge whether a question
was real. If Claude asks again anyway, the turn ends and the closing line goes to gate.log in vjuu's data folder. It
works with or without a vjuu window open; vjuu config gate off switches it off.
Click the gear in the title bar and Apply (Esc cancels), or use the terminal:
vjuu config # open the settings panel
vjuu config list # print the settings and where the file is
vjuu config turn off # switch one: plan, ask, turn, permission, gate, tray or focus; on or off
vjuu config worktrees .wt # where your git worktrees live (default .claude/worktrees)
vjuu config theme graphite # a theme, or auto; theme.light and theme.dark set Auto's two picks
They live in config.toml in your config folder: %APPDATA%\vjuu on Windows, ~/.config/vjuu on Linux (or
$XDG_CONFIG_HOME/vjuu), ~/Library/Application Support/vjuu on macOS. A missing setting counts as on.
A theme is a CSS file in the themes folder next to config.toml; Open themes folder in the settings takes you
there. vjuu puts its shipped themes (light.css, graphite.css and the others above) in it, and puts them back if you delete them, but never overwrites them:
to get a newer shipped version, delete your copy. To make a theme, copy one under a new name and change its colours.
It shows up in the settings the next time you open them.
vjuu reads only the color-scheme (light or dark, which decides where the theme is offered for Auto; a theme without
one counts as dark) and the
--custom-properties; any other CSS in the file is ignored, so a theme can recolour everything but not move anything.
On Apply (or vjuu config theme ...) vjuu compiles the chosen themes into one theme.css next to the reviews, and
open windows switch to it. A new window loads that file, kept in memory by the resident instance, so a theme costs
nothing when a window opens. After editing the theme in use, pick it and Apply again.
vjuu setup installs the skills and the question gate; it leaves the gate out when the vjuu plugin is enabled, as the
plugin has its own. To get the other hooks too, add them to ~/.claude/settings.json; the settings above still
switch them:
{
"hooks": {
"PreToolUse": [
{ "matcher": "ExitPlanMode", "hooks": [{ "type": "command", "command": "vjuu hook plan", "timeout": 3600 }] },
{ "matcher": "AskUserQuestion", "hooks": [{ "type": "command", "command": "vjuu hook ask", "timeout": 3600 }] }
],
"PermissionRequest": [{ "hooks": [{ "type": "command", "command": "vjuu hook permission", "timeout": 3600 }] }],
"Stop": [
{ "hooks": [{ "type": "command", "command": "vjuu hook turn", "timeout": 3600 }] },
{ "hooks": [{ "type": "command", "command": "vjuu hook gate", "timeout": 10 }] }
]
}
}uvx pre-commit installonce: formats with rustfmt and ruff on every commit.cargo test: review formatter and diff detection.uv run --no-project --with playwright python tests/ui_test.py: drivesui/in headless Edge with a stubbedwindow.ipcand checks the review the page reports.tests/keyboard_focus.ps1 -HomeHwnd <hwnd>: manual check that a freshly opened window takes keyboard focus from another app (cold and resident). It types real keys, so run it by hand.site/is vjuu.it, deployed with the apt repository by.github/workflows/pages.yml.uv run --no-project --with playwright python tests/screenshots.pyre-renders its screenshots (not the demo video, which is a real recording). Each release does this too and opens a pull request when an image changed.VJUU_AUTOCLOSE=1 vjuu <file>exits as soon as the page has rendered and prints the time to stderr, for startup measurements.
UI libraries are vendored in ui/vendor (markdown-it 15.0.3, diff2html 3.4.56 base bundle, highlight.js
11.12.0 common languages, Inter and JetBrains Mono variable fonts) and embedded in the exe. Markdown is rendered with raw HTML off: documents are agent output and the page can talk to vjuu. For the same reason
an HTML page's scripts run only in a sandboxed iframe with an origin of its own, which cannot reach vjuu's page; vjuu
also ignores messages from anywhere but its own page. Once the page stops changing (or after 3 s), it sends back a copy
of itself, canvases drawn as images, and you comment on that copy in a second iframe with scripts off. So you review
one state of the page: buttons, tabs and timers do not work, and network requests the page makes still go out.
MIT, see LICENSE. Bundled libraries and fonts keep their own licenses, in ui/vendor/licenses: markdown-it and diff2html (MIT), highlight.js (BSD-3-Clause), Inter and JetBrains Mono (SIL Open Font License 1.1).

