Desktop overview of all your Claude Code review sessions: discover open PRs across hand-picked repos, dispatch review/follow-up sessions, track follow-ups, auto-clear merged PRs.
Tauri v2 + React + TypeScript + Tailwind. No remote server — everything runs locally: the app polls gh, scans ~/.claude/projects/ sessions and each repo's AI_TASKS/code-review/ exports.
⚠️ Opinionated. This app encodes my personal review flow (discover → dispatch a Claude review → push comments → follow up → approve) and has only been tested against my personal commands — it may not fit yours out of the box.But you can configure the dispatched prompts in Settings → Claude commands (defaults use Claude Code's built-in
/review; placeholders<branch_name>and<pr_id>are supported).
This repo doubles as its own Homebrew tap:
brew tap chartrandf/lookout https://github.com/chartrandf/lookout
brew trust --cask chartrandf/lookout/lookout # Homebrew 6+ gates third-party casks
brew install --cask lookout # --force to replace a hand-installed copyAll three lines are required, in order. Homebrew expands a bare
chartrandf/lookouttochartrandf/homebrew-lookout, which doesn't exist — so not even the fully-qualifiedbrew install --cask chartrandf/lookout/lookoutcan tap this repo on its own. Skip thebrew tapline and you getInvalid usage: Casks must be fully-qualified/No Cask with this name exists.
Grab the latest .dmg from Releases (universal — Apple Silicon + Intel) and drag Lookout to Applications.
On Linux (x86_64), grab the .deb (sudo apt install ./Lookout_*.deb) or the .AppImage (chmod +x, then run it).
The bundle is self-signed, so macOS quarantines it. You may need to release the quarantine manually from the Terminal.
xattr -dr com.apple.quarantine /Applications/Lookout.apppnpm install
pnpm tauri devpnpm tauri … builds the CLI first (pretauri → pnpm build:cli): tauri.conf.json bundles
dist-cli/lookout.mjs as a resource, and the Rust build fails without it.
Requirements — see Tauri's prerequisites for your OS:
- Linux — the webview/tray system libs, e.g. on Debian/Ubuntu:
sudo apt install libwebkit2gtk-4.1-dev build-essential libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev - Rust (stable) —
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh. Without itpnpm tauri devdies atcargo metadata … No such file or directory (os error 2). - Xcode Command Line Tools (macOS) —
xcode-select --install, for the linkercargoshells out to. gh(authenticated) and theclaudeCLI.
pnpm is pinned by the packageManager field — corepack enable picks up the right version.
npm install can't build this tree: package-lock.json is stale, and resolving the missing dev
deps from scratch crashes Arborist with Cannot read properties of null (reading 'edgesOut').
- Settings — add local clone paths;
owner/repois detected from each clone's git origin. Your GitHub login is auto-detected; your own PRs are never listed. - Discovery — new open PRs land here. Review (add to board + dispatch
/do-review), Watch (add to board), Ignore (hide forever). PRs you already reviewed or commented on skip Discovery. - Reviews — Watching / Needs Review / Reviewed / Follow-up / Done. Drag cards to triage or prioritize. Merged or closed PRs auto-move to Done and drop off after 24 h.
- Pull Requests — your own PRs: Waiting / In Review / Ready to merge / Done. A human review moves a card to In Review, an approval to Ready to merge (where the CI tag is all you need to decide). Cards only ever move forward on their own, so re-requesting a review or flipping back to draft can't drop one out of In Review. Bot reviews (Cursor, Sonar) show a 🤖 badge but never move a card — they're lint, not review. Drag anywhere, in either direction: a drop stays put until GitHub itself changes its mind. Done holds what you merged or closed today and empties overnight.
- PR panel — click a card: chat-style history (sessions, reports, commits, reviews), dispatch buttons, stage selector, one-click approve when follow-up is all green, resume sessions in Ghostty.
- Worktrees — you only ever register the clone path. A branch checked out in a linked worktree is followed there: actions run in that worktree, its sessions and
AI_TASKS/code-review/reports show up on the card, and resume opens the directory the session actually ran in.
A review only reaches a card if something wrote it down. My own /do-review exports
AI_TASKS/code-review/<stamp>-<branch>.md, which the app scans — but the default review button runs
Claude Code's own /review, which prints its verdict and saves nothing. Those cards used to show a
session and no review.
Lookout now reads the review back out of the session transcript itself (the final assistant turn) and keeps it for 30 days. Follow-up runs are captured the same way and labelled as follow-ups. It is display only: a captured review never moves a card and never raises an alert. Settings → Capture reviews has the switch, the count and a Clear button.
A branch whose reviews are exported to AI_TASKS/code-review/ is left alone — the file is used and
nothing is captured, so a review can't appear twice. A session that wrote its own report is skipped
for the same reason.
Capture happens on the next sync. For it to land the moment a session stops, copy the Stop hook from
Settings into ~/.claude/settings.json:
{ "hooks": { "Stop": [{ "hooks": [{ "type": "command", "command": "lookout review capture --hook", "timeout": 10 }] }] } }A skill can also hand a review over outright, which always wins over what Lookout guessed:
lookout review report --file AI_TASKS/reviews/pr-2305.md # a report file living anywhere
claude -p "…" | lookout review report --stdin # or the text itselfThe Homebrew cask puts a lookout command on your PATH — brew install --cask lookout symlinks it,
nothing else to do. Installing the DMG by hand instead leaves it inside the bundle at
Lookout.app/Contents/Resources/lookout; symlink it yourself:
ln -sf /Applications/Lookout.app/Contents/Resources/lookout ~/.local/bin/lookoutIt runs on Node 22.13+ (or 23.4+), where node:sqlite stopped needing a flag. In a dev checkout:
pnpm build:cli, then symlink dist-cli/lookout.mjs. It moves cards from a terminal, so a Claude Code skill can
report back once it has pushed comments — and it works whether or not the app is open, because it
writes the same SQLite database the app uses.
The command name says whose work it is: review for other people's PRs (the review pipeline),
mine for your own (the merge pipeline).
lookout review list --stage "in review" # what's in a column
lookout review show --pr 2305 # one card, or omit the selector inside a repo checkout
lookout review reviewed # the PR for this repo + branch → Reviewed
lookout review comments-pushed --count 3 # what /do-review calls after `gh api .../reviews`
lookout review report --file report.md # register a report your skill wrote, wherever it wrote it
lookout review capture --hook # Stop-hook entry point: payload on stdin, always silent
lookout mine list --column ready # my PRs that are approved and just need a CI check
lookout mine show # my PR for this repo + branch
lookout mine ready # → Ready to merge
lookout stream add "#app implement card 1,2" # dump work onto the Stream board (--queue for Queued)
lookout stream list --status needs_review # what waits on me
lookout stream gate --summary "Plan ready" # an agent stops for my review (--kind question to ask)
lookout stream note "tests are slow here" # a line in the item's trail
lookout doctor # database path and both board countsStages and columns are named the way the board names them — needs-review, "In Review",
follow-up, "Ready to merge", case and spacing ignored. Retired names still resolve (inbox is
now needs_review, and lookout card … is the old spelling of lookout review …), so older
scripts and shell aliases keep working.
A card is picked by --id <id>, --pr <n> or --branch <b> (add --repo owner/repo to
disambiguate); with no selector at all it uses the current checkout's origin and branch. Moves on
both boards are forward-only — the app's own rule, so an automated caller can't drag a card
backwards — with --force to override. --json for machine output, --dry-run to resolve without
writing.
Exit codes are the contract for scripts: 0 done · 1 error · 2 no matching card · 3 Lookout
has never run here · 4 selector matched several cards. In a skill, guard on the binary and let the
"nothing to do" codes pass:
command -v lookout >/dev/null && lookout review comments-pushed --branch "$BRANCH" --count 3 --quiet || trueWhen the app is running it repaints immediately: the CLI pings a unix socket the app publishes next to the database, and the app re-reads. The event is only a hint — every failure degrades to the app noticing at its next sync.
Bundles Leckerli One (SIL Open Font License 1.1).
