@agoalofalife/review-kungfu
v0.1.0
Published
Local web-based Markdown annotation tool with Claude Code integration
Downloads
72
Maintainers
Readme
review-kungfu
Local Markdown review tool with native Claude Code integration.
Open any set of .md files in the browser, annotate them like a GitHub PR, and push the review directly into a running Claude Code session — no copy-paste, no context juggling.
Built for reviewing agent-generated plans, RFCs, task lists, and documentation.
Audience: solo developers who use Claude Code and want a fast way to review agent-generated markdown plans, docs, RFCs, and task lists, then feed corrections back without copy-paste.
Not a general-purpose markdown editor. Read-mostly, with surgical edits (checkbox toggle, comments). Content is not edited inline.

Table of Contents
- Features
- Installation
- Quick Start
- Usage
- Claude Code Integration
- Settings Panel
- Themes
- Fonts
- Editors & Terminals
- File Path Links
- Keyboard Shortcuts
- Push Format
- File Structure
- Architecture
- Troubleshooting
- Requirements
- Uninstall
- License
Features
Core
- Two view modes: Source (raw Markdown with syntax highlighting) and Preview (rendered) — toggling preserves your scroll position by line, not by ratio
- Tabs for multiple files, with active-tab persistence across reloads, and a per-tab close
×(hover to reveal) when more than one file is open - Line-by-line commenting (add, edit, delete, statuses
pending/pushed) - Push to Claude Code — delivers review via the IDE bridge (MCP over WebSocket)
- Auto-submit on push (macOS only, opt-in) — after the push, send Enter to the Claude Code CLI so the review is processed without you switching terminals. See Auto-submit on push
- Auto-start Claude Code session from the UI in a terminal of your choice
Reading
- Table of contents, auto-generated from headings, with scroll-sync highlighting
- In-page hash links (e.g.
[Features](#features)) jump to the matching heading inside the preview container — Markdown anchor TOCs work as expected - Inline images with relative paths (e.g.
) are resolved relative to the markdown file's directory and served via an internal asset endpoint - Interactive checkboxes in Preview — click
[x]/[ ]to rewrite the source - Copy-code button on every fenced block
- Line numbers in code blocks
- Mermaid diagrams
- Syntax highlighting (highlight.js) with theme-aware color palette
Customization
- 13 themes (GitHub, Dracula, Monokai, Nord, One Dark, Gruvbox, Tokyo Night, Solarized, Material, Oceanic, …)
- 11 fonts (JetBrains Mono default + Fira Code, Source Code Pro, IBM Plex Mono, Inconsolata, Ubuntu Mono, Inter, Merriweather, Lora, Nunito, System UI)
- Adjustable font size, line height, max content width, TOC size & width — all with live preview and persistence
Editing
- Click any path-like link (
phpstorm://,vscode://, etc.) in Preview to open the file in your configured editor at the right line - Path resolution tries: markdown file's dir → git root → CWD
- Click a line number in Source to copy
file.md:Nto clipboard (great for pasting into Claude)
Live-reload
- File watcher: when the underlying markdown changes on disk, the Preview re-renders with a subtle flash and toast
Installation
git clone <repo>
cd review-kungfu
npm install
npm linkAfter npm link, the review-kungfu command is available globally.
Quick Start
review-kungfu path/to/plan.mdBrowser opens automatically. Click any block's + in Preview (or hover a line in Source and click +) to add a comment. When you're done, click Push to Claude Code.
If Claude Code isn't yet connected, click Start Claude Code in the header — it launches claude --ide in your configured terminal with the correct working directory, and connects back automatically.
Usage
# Single file
review-kungfu docs/plan.md
# Multiple files → shown as tabs
review-kungfu docs/plan.md docs/architecture.md docs/rfc-01.md
# Shell glob
review-kungfu docs/*.md
# Custom port (default 7700, overridable via REVIEW_KUNGFU_PORT env)
review-kungfu docs/plan.md --port 8080
# Resume a previous session (reuses comment history)
review-kungfu --session abc123def456
# Pick an editor up front (otherwise auto-detected or set in Settings)
review-kungfu docs/plan.md --editor codeClaude Code Integration
review-kungfu registers itself as an IDE with Claude Code using the same mechanism JetBrains/VS Code plugins use (lockfile at ~/.claude/ide/{port}.lock + WebSocket MCP server). There are three ways to connect:
1. Auto-launch (easiest)
Click the amber Start Claude Code button in the browser header. review-kungfu spawns claude --ide in your selected terminal (iTerm2 / Ghostty / tmux / Terminal.app) with the correct working directory. The connection is established automatically.
The button turns into a green Claude Code connected label once connected.
2. From an existing Claude Code session
In a running Claude Code conversation:
/ideSelect review-kungfu from the list. Connection established.
3. File-based fallback
After clicking Push to Claude Code, the full formatted review is written to ~/.review-kungfu/latest-push.md. You can just tell Claude:
Read my review from ~/.review-kungfu/latest-push.mdThe push is also copied to the clipboard via a modal button.
What happens on Push
- Pending comments are formatted into the
---MD-REVIEW-PUSH---envelope - File is written to
~/.review-kungfu/latest-push.mdand session history - The
at_mentionedMCP notification is sent to Claude Code — it reads the file into context - The exposed MCP tool
get_review_commentsnow shows[NEW REVIEW AVAILABLE]in its description - Comments are marked
pushed; you can continue annotating and push again - (Optional — see below) If Auto-submit on push is enabled, review-kungfu sends
Enterto the Claude Code terminal so the @-mention is submitted automatically
Auto-submit on push
By default at_mentioned only stages the push file in Claude Code's input buffer — you still have to press Enter in the terminal yourself. The Auto-submit on push setting lets review-kungfu do it for you.
macOS only. The implementation uses AppleScript and tmux send-keys; there's no equivalent on Linux/Windows.
How it's done per terminal:
| Terminal | Mechanism | Focus stealing? |
|---|---|---|
| iTerm2 | osascript activates iTerm2, then System Events → keystroke return | Yes (briefly) |
| Ghostty | Same — Ghostty has no scripting API for sending input | Yes (briefly) |
| tmux | tmux send-keys -t claude Enter (targets the window the launcher creates) | No |
| Terminal.app | osascript activate + keystroke return | Yes (briefly) |
Caveats:
- Each push the terminal will briefly come to the front (except tmux). Your browser regains focus after.
- Accessibility permission is required for the keystroke synthesis. The first push triggers a macOS permission dialog asking you to add the parent process (your shell, iTerm2, etc.) to System Settings → Privacy & Security → Accessibility. If the dialog doesn't appear, add it manually.
- iTerm2 / Terminal.app use the frontmost window. If you have multiple windows open and Claude Code isn't in the active one, the Enter goes to the wrong place.
- The tmux path assumes the window is named
claude(which the launcher creates). If you started Claude in tmux yourself with a different window name, auto-submit won't find it. - If auto-submit fails, the toast in the browser will say "auto-submit failed: …" and the server log prints
[auto-submit] result ok=false error=….
Settings Panel
Click the ⚙ icon in the bottom-left to open the floating settings panel. Every option persists across page reloads and sessions.
| Setting | What it does |
|---|---|
| Theme | Grid of 13 color themes. Applies to the whole page + swaps highlight.js stylesheet. |
| Font | Select from 11 Google Fonts: monospace, sans-serif, serif. |
| Font size | 12–28 px slider. Code blocks scale proportionally (0.85×). |
| Line height | 1.2–2.5 slider. |
| Max width | 500–1200 px. Keeps long lines readable. |
| TOC size | 9–18 px. Size of table of contents text. |
| TOC width | 120–350 px. Controls TOC panel width and truncation. |
| Editor | Which editor opens when you click a path link. |
| Terminal | Which terminal hosts claude --ide and terminal editors (vim/nvim). |
| Comment in source | If on (default), clicking + in Preview jumps to Source mode at that line and opens the comment form, then returns to Preview on submit. |
| Auto-submit on push | Off by default. When on, review-kungfu sends Enter to the Claude Code terminal right after pushing, so the review is processed without you switching apps. macOS only. See Auto-submit on push below for caveats. |
Themes
All themes update: page background, text, headings, links, inline code, code blocks, blockquotes, borders, and the highlight.js syntax colors.
- Default — adaptive, follows Tailwind's dark/light
- GitHub Dark, GitHub Light
- Dracula
- Monokai
- Nord
- One Dark (Atom)
- Gruvbox
- Tokyo Night
- Solarized Dark, Solarized Light
- Material
- Oceanic
Hover any theme swatch to see its name below the grid.
Fonts
Loaded from Google Fonts with preconnect for fast first paint. Applies to the whole app (body + preview + UI chrome).
Monospace: JetBrains Mono (default), Fira Code, Source Code Pro, IBM Plex Mono, Inconsolata, Ubuntu Mono. Sans-serif: Inter, Nunito, System UI. Serif: Merriweather, Lora.
Editors & Terminals
Supported editors
GUI: PhpStorm, RustRover, GoLand, IntelliJ IDEA, Zed, VS Code, Cursor. Terminal: Neovim, Vim — launched inside your chosen terminal emulator.
JetBrains IDEs are opened via their native URL scheme (phpstorm://open?file=…&line=…) which is the most reliable way on macOS.
Supported terminals
iTerm2 (new tab via AppleScript), Ghostty (open -na), tmux (tmux new-window), Terminal.app (AppleScript).
The terminal setting is used both for launching Claude Code and for opening vim/nvim on clicked file paths.
File Path Links
Write links in markdown using editor-protocol URLs — the preview renders them as clickable, and review-kungfu routes the click through your configured editor (not the URL's embedded editor).
[file.php:42](phpstorm://open?file=app/Services/PaymentService.php&line=42)
[config](vscode://file/~/project/config.yaml&line=1)
[main.go](goland://open?file=/abs/path/to/main.go&line=100)Three ways to write paths:
Relative to project root (recommended for sharing with teammates):
[Model](phpstorm://open?file=app/Models/User.php&line=42)review-kungfu tries: active-file's directory → git root → launch CWD. First hit wins.
Home directory with
~/:[config](phpstorm://open?file=~/.config/nvim/init.lua)Absolute paths (personal notes only — don't share):
[note](phpstorm://open?file=/Users/me/notes.md&line=5)
Bonus: clicking a line number in Source mode copies file.md:N to clipboard (shows a toast). Handy for pasting into Claude Code.
Keyboard Shortcuts
| Key | Action |
|---|---|
| Esc | Cancel comment form / close modal |
| Ctrl+Enter / Cmd+Enter | Submit comment or save edit |
Push Format
When you click Push to Claude Code, the comments are serialized as:
---MD-REVIEW-PUSH---
Session: abc123def456
Files: plan.md
## plan.md
**Line 5** (`This project uses a modular structure`):
> Need to clarify the module boundaries here
**Line 23** (`### Error Handling`):
> Does this cover timeout scenarios?
Summary: 2 comments, 1 file(s)
---END-MD-REVIEW---This same payload is:
- Written to
~/.review-kungfu/latest-push.md(for manual Claude prompting) - Appended to the session history at
~/.review-kungfu/sessions/{id}/push-{n}.md - Printed to the server's stdout (the terminal where review-kungfu runs)
- Pushed via MCP
at_mentionedto any connected Claude Code session
File Structure
~/.review-kungfu/
├── sessions/
│ └── {session-id}/
│ ├── meta.json # files, timestamps, push count
│ ├── comments.json # all comments for this session
│ └── push-{n}.md # historical push outputs
├── latest-session.txt # ID of the last started session
└── latest-push.md # most recent push outputNothing is ever deleted automatically; clean up manually if you want.
Architecture
graph TD
User[User in terminal] -->|review-kungfu file.md| Server[Node.js server.js]
Server -->|spawns| HTTP[HTTP :7700+]
Server -->|spawns| WS[WebSocket MCP :10000+]
HTTP -->|serves| Browser[Browser UI]
Browser -->|HTTP + SSE| HTTP
WS -->|MCP JSON-RPC| Claude[Claude Code CLI]
Server -->|writes| Lockfile[~/.claude/ide/*.lock]
Claude -->|reads lockfile, /ide| WS
Server -->|fs.watch| Files[Markdown files]
Files -->|SSE file-changed| Browser
Browser -->|POST /api/push| Server
Server -->|bridge.pushReview<br/>at_mentioned| ClaudeTwo parallel servers in one Node process:
- HTTP + SSE for the browser UI and REST API (
/api/session,/api/files,/api/comments,/api/push,/api/open-editor,/api/toggle-checkbox,/api/start-claude, …) - WebSocket MCP for Claude Code — speaks the same MCP protocol as the official JetBrains/VS Code plugins
The browser never talks to Claude Code directly. The server translates HTTP actions into MCP notifications.
For the full internal architecture and module breakdown, see AGENTS.md.
Troubleshooting
/ide shows review-kungfu but fails to connect.
Claude Code validates that its current working directory matches one of the workspaceFolders in review-kungfu's lockfile. review-kungfu auto-includes each file's parent directory, each file's git root (if any), and the launch CWD. If your Claude Code session is in a directory outside those, either cd into a parent-of-project directory or restart review-kungfu from there.
open -a Ghostty opens but immediately closes with "No such file or directory".
Ghostty passes the -e argument to /usr/bin/login, not a shell. review-kungfu already wraps the command in sh -c "...; exec sh". If you customized the template, keep that pattern.
Vim/Neovim says "command not found" when opened from a clicked link.
GUI-launched terminals don't inherit your shell PATH. review-kungfu uses full binary paths (/opt/homebrew/bin/nvim, /usr/bin/vim). If yours live elsewhere, edit src/editor.js (terminalEditorPaths).
File watcher stops reacting to changes.
fs.watch on macOS is occasionally flaky. Restart review-kungfu. Polling is on the backlog.
Theme selector doesn't change code-block colors.
That highlight.js CDN doesn't host that theme under the name I guessed. Check base16/ subfolder (e.g. base16/dracula, base16/solarized-dark).
Auto-submit reports ok=true in the log but no Enter actually fired in the terminal.
This is the silent-success case for missing Accessibility permission. macOS lets osascript succeed even when System Events → keystroke is silently denied. Open System Settings → Privacy & Security → Accessibility and add (or toggle on) the parent process that launched review-kungfu — typically your shell's host app (iTerm2, Terminal.app, Ghostty, etc.) or the node binary itself. Verify by running this in a regular shell — Ghostty (or whichever terminal) should briefly come to the front and receive an Enter:
osascript -e 'tell application "Ghostty" to activate' \
-e 'delay 0.2' \
-e 'tell application "System Events" to keystroke return'Auto-submit doesn't fire at all (no [auto-submit] log line).
The browser is probably running the cached old app.js. Hard-reload (Cmd+Shift+R), then re-toggle the setting under ⚙ — old localStorage doesn't carry the new flag.
Requirements
- Node.js 18+
- macOS (Ghostty, iTerm2 AppleScript,
open -aall macOS-specific; Linux/Windows require port modifications) - Claude Code CLI (installable as
claude— review-kungfu currently hardcodes/Applications/cmux.app/Contents/Resources/bin/claude; editsrc/claude-launcher.jsif yours is elsewhere) - Modern browser (Chrome, Firefox, Safari, Edge)
Uninstall
cd review-kungfu
npm unlink -g review-kungfuTo remove all stored sessions and pushes:
rm -rf ~/.review-kungfuTo remove any leftover IDE lockfiles:
rm -f ~/.claude/ide/*.lockLicense
MIT
