Skip to content

v-za/lens

Repository files navigation

Lens

Desktop code-review tool. Claude generates story-driven reviews with inline annotations; each annotation is an interactive thread you can click to ask follow-ups, with answers streamed back into the diff viewer. Works for Bitbucket PRs and uncommitted local changes.

Lens demo

What's in here

Product

  • Story-driven AI code review — a narrative walkthrough with inline notes, not a one-shot lint comment
  • Click any annotation to spawn a scoped Claude subagent that resumes its own session for follow-up questions
  • Three modes: PR review (Bitbucket), self-review (local uncommitted changes), answer-review (respond to feedback)
  • Thread replies post back to Bitbucket; suggested code fixes can be applied or rejected inline

Agent architecture

  • Each user action spawns a purpose-built Claude subagent — annotation reply, file explainer, ship-commit, and a background reconciliation agent — coordinated by the server through session.json state, not a single chat loop
  • Sessions resume across turns via claude -p --resume <sid> so context is reused without re-prompting (token + latency win)
  • Background reconciliation agent runs after any code-changing reply, returning a JSON-schema response that updates annotation fixStatus and refreshes affected file explanations
  • Per-spawn cost/latency tuning: --model sonnet --effort high + outputStyle: ultra-concise override so subagents don't burn tokens emitting structured progressive payloads

Backend / infra

  • Bun + Hono server with WebSocket file watcher broadcasting session changes to all connected clients
  • Subprocess cancel registry with kill semantics; deterministic session IDs; stream-JSON parsing of Claude CLI output for incremental UI updates
  • Per-session turn lock prevents races on claude -p --resume <sid> writing the same jsonl transcript
  • Atomic JSON mutations via a single-writer mutex; pure merge helpers for disk↔memory reconciliation
  • Custom bb (Bitbucket) + jr (Jira) CLI wrappers with pagination + 429 backoff

Stack: TypeScript (strict), Bun, Hono, React 18, Vite, Zustand, Electron, Claude Code subagents, refractor, react-diff-view

If you only have 5 minutes — a guided code tour

The most interesting parts of the codebase, in order. Each file is small enough to read end-to-end.

  1. server/subagent.ts (~195 lines) — the spawn primitive. Wraps Bun.spawn("claude", ...), parses stream-JSON output, and registers each subprocess with a cancel registry keyed so a /api/reply/cancel route can kill the right pid. Throws a CANCELLED_SENTINEL so callers can distinguish user-cancellation from real failures.

  2. server/reply.ts (~395 lines) — the orchestrator. handleReply routes each user action (annotation reply, comment reply, ship, pr-comment, explain) to the right prompt builder, picks the right spawn options (resume? json-schema? bypass permissions?), parses structured JSON responses, and writes the result back to session.json via atomic mutation.

  3. server/reconcile.ts (~162 lines) — the second agent. After any code-changing reply, a background agent runs with a JSON-schema response describing which annotations to mark applied/resolved and which file explanations to refresh. This is the multi-agent coordination piece: agent 1's output triggers agent 2's spawn.

  4. src/store/session-merge.ts (~310 lines) — pure helpers for disk↔memory state. mergeSessionData reconciles incoming websocket-broadcast session.json updates against in-memory edits without clobbering. detectNewReplies notices when an asking-claude spinner should clear because a Claude reply just landed on disk.

  5. src/components/DiffView.tsx (~720 lines) — the diff renderer + widget map. Splices annotations, comments, and PR comments into the diff at correct change keys, with per-pane horizontal scroll sync and a custom gutter that hosts the inline "Ask Claude" UI. The widget-map useMemo is the heart of the rendering loop.

If you want one file to understand the project: read server/reply.ts. Everything else exists to serve it.

Quick start

Prerequisites

  • macOS (Keychain used for credential storage)
  • Buncurl -fsSL https://bun.sh/install | bash
  • Node.js ≥ 18
  • Claude Codenpm install -g @anthropic-ai/claude-code (required — powers all AI review features)
  • Git

Install + run

git clone <repo-url>
cd lens
./setup.sh
lens

setup.sh walks you through:

  1. Auto-installs Bun if missing; checks node / git / claude
  2. Bitbucket API token (scopes: Account/Workspace/Users/Repos Read, PR Read+Write, Pipelines Read)
  3. Jira API token (optional, for ticket context in reviews)
  4. Auto-fetches your Bitbucket identity, workspaces, and repos
  5. Installs skills, agents, and the lens command on your PATH

How to use it

Open Lens (lens) and the home page lets you start a review directly — pick a repo, pick a PR or branch, click Start. The viewer opens when the review agent is ready.

You can also start from Claude Code via slash commands (/pr-review, /self-review, /review) if you prefer the terminal.

The reply flow. Click any annotation or comment in the viewer to ask Claude a follow-up about that specific code. Each click spawns a scoped subagent with the annotation's context + your question + the surrounding diff; subsequent questions resume the same session via claude -p --resume <sid> so context isn't re-prompted.

Project layout

server/          Bun + Hono API server (port 3100) + WebSocket file watcher
  ├─ reply.ts        orchestrator: routes each user action to a subagent
  ├─ subagent.ts     spawn primitive + cancel registry
  ├─ reconcile.ts    background agent that updates session.json after code changes
  ├─ prompts.ts      prompt builders per item type
  ├─ review.ts       session.json I/O (atomic, mutex-protected)
  ├─ git.ts          diff / file-content / branch helpers
  └─ routes/         Hono route modules (pr, review, session, git)
src/             React + Vite frontend (port 1421)
  ├─ components/     DiffView, AnnotationBox, CommentWidget, PrCommentBubble, ...
  └─ store/          Zustand: session, ui, session-merge (pure helpers)
electron/        Electron shell
scripts/bb/      Bitbucket CLI (pr list, pr comment, etc.)
scripts/jr/      Jira CLI (view, edit, comment, etc.)
.claude/skills/  Review skill definitions (symlinked to ~/.claude/skills/)
.claude/agents/  Specialist agent definitions (symlinked to ~/.claude/agents/)
.reviews/        Session data (gitignored, per-repo hash directories)

Known limitations

  • macOS only — uses Keychain for credential storage; no Linux/Windows port
  • Requires Claude Code Pro/Max — every AI feature spawns a claude -p subprocess against the user's installed CLI
  • Bitbucket only — no GitHub PR integration; self-review mode works against any git remote
  • Single-user — no multi-tenant, no shared sessions across machines
  • Self-review diff freezes to the pushed branch when you switch contexts — intentional, prevents the diff from silently changing under your feet when you check out a different branch mid-review

License

MIT — see LICENSE.

Troubleshooting

First step for any issue:

lens --check

Validates dependencies, credentials, configuration, and port availability.

  • Port 3100 already in use: another Lens instance is running. lsof -ti:3100 | xargs kill.
  • lens: command not found: restart your shell (source ~/.zshrc) or re-run ./setup.sh.
  • Bitbucket token issues: security delete-generic-password -s "bitbucket-api-token" then re-run ./setup.sh.
  • Jira token issues: security delete-generic-password -s "jira-cli-token" then re-run ./setup.sh.

Personal project I built to speed up my own review workflow. Public mainly as a writing sample.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages