← back to writing

Onceover: Reviewing AI-Generated Code Without Losing Your Mind

·4 min read·ai · side-projects · developer-tools · open-source

Here's the loop I live in now: I give an agent a task, it works for a few minutes, it tells me it's done. Then I have to actually look at what it did — and every time I hit that step, I'd feel a tiny bit of friction.

git diff in the terminal? Fine for ten lines, miserable for a hundred. Color-wrapped, line-wrapped, no easy way to navigate. Open the IDE? That's a whole context switch — I have to find the changed files, click through them, mentally hold the diff in my head while scrolling. GitHub-style review? There's no PR yet, the work is sitting in my working tree.

So I'd squint at the terminal, half-review the changes, and ask the agent to keep going. Every time I did that I knew I was being lazy, and I knew it was going to bite me later.

I wanted something that felt like a GitHub PR review, but for uncommitted code, with zero setup, that I could close and forget about as soon as I was done.

That's Onceover.

npx onceover

A browser tab opens on a local HTML file with a clean diff of your working tree — file tree, syntax highlighting, split or unified view, light and dark mode. The CLI exits immediately. Nothing left running, no server, no port, no daemon. Close the tab and it's gone.

The Part That Actually Closes the Loop

A pretty diff viewer would be nice, but the whole point of this tool is what happens after you spot something wrong.

Click the + next to any line. A little inline comment box pops open. Type your feedback ("handle the empty case", "extract this into a helper", "this breaks types", "add a test for this branch"). Hit save. Repeat for every spot you want to flag.

A review sidebar builds up as you go. When you're done, hit Copy Review. It dumps a structured prompt to your clipboard:

I have the following feedback on these changes:

## src/auth.ts (line 42)
this should handle the empty case

## src/utils.ts (line 88)
extract this into a helper

Paste it back into your agent (I use Claude Code). The agent fixes everything. npx onceover again. Repeat until clean.

That's the whole flow. Spot, comment, copy, paste, fix. The agent does the work. You do the judgment. Onceover is the bridge between those two things — and that bridge is the part that used to be friction.

How It Actually Works

The implementation is deliberately simple, which is the part I'm most proud of.

  1. The CLI runs git diff in your repo
  2. It does a string replacement on a pre-built HTML template
  3. Writes the result to a temp file
  4. Opens it in your default browser
  5. Exits

That's it. There is no server. There is no websocket. There is no "onceover process" running in the background. The viewer is a React app (with react-diff-view doing the heavy lifting) that's bundled at build time into a single HTML file via vite-plugin-singlefile. At runtime, the CLI is doing string manipulation and file I/O. It's functionally instant.

Comments persist via localStorage, keyed by a hash of the diff content. So if you accidentally close the tab, your review is right where you left it. New diff = clean slate. No state to manage, no database, no cleanup.

The whole thing is offline. It never phones home. Your code never leaves your machine. There's nothing to log into, nothing to configure, and no background process to babysit.

Usage

The defaults handle 90% of cases:

onceover              # unstaged changes (the most common case)
onceover --staged     # staged only
onceover --all        # staged + unstaged vs HEAD
onceover main         # diff against a branch
onceover HEAD~3       # last 3 commits
onceover abc123       # changes since a specific commit

Node 18+ and git. That's it. Install globally with npm i -g onceover or just lean on npx.

MIT licensed, PRs welcome. The best version of this tool is the one that's a single command you don't have to think about — so go give your code a once-over.