commd
Interactive Markdown reviewer in the terminal (TUI) or a web browser.
Add review comments at section level or line level using Conventional Comments and output structured feedback.
Formerly ccplan — see Migration from ccplan for upgrade instructions.

Install
mise
mise use -g github:koh-sh/commd
go install
go install github.com/koh-sh/commd@latest
Pre-built binary
Download the latest release from the Releases page.
Usage
commd review
Display a Markdown file in a 2-pane TUI and add review comments to each section.
review is the default command, so the subcommand name can be omitted.
commd review path/to/document.md
# Same as above (review is the default command)
commd path/to/document.md
# Output review to a file
commd review --output file --output-path ./review.md document.md
# Output to stdout
commd review --output stdout document.md
# Review local git changes in diff view (working tree vs HEAD)
commd review --diff document.md
# Pick from all changed/untracked .md files, comparing against a branch
commd review --diff --base main
# Review in a web browser instead of the TUI
commd review --web document.md
commd review --web --diff
| Flag |
Description |
--output |
Output method: clipboard (default), stdout, file |
--output-path |
File path for --output file |
--theme |
Color theme: dark (default), light |
--track-viewed |
Persist viewed state to sidecar file (.reviewed.json) for change detection across sessions |
--diff |
Review local git changes in diff view. Without a file, pick from changed .md files |
--base |
Git ref to diff against (default: HEAD; requires --diff) |
--web |
Review in a web browser instead of the TUI (see Web review) |
--port |
Port for --web (default: a free port) |
--no-open |
With --web, print the URL instead of opening a browser |
When --track-viewed is enabled, commd saves which sections you've marked as viewed in a .reviewed.json sidecar file. On subsequent runs, viewed marks are restored automatically. If a section's content has changed, its viewed mark is cleared (detected via content hash).
Diff mode
--diff reviews what changed in the working tree instead of the whole file — for example, docs that Claude Code edited, before you commit them. It uses the same diff view as commd pr:
- The right pane opens in raw view showing the unified diff (
+/- lines); press r for the rendered working-tree content
- Press
Tab to focus the diff pane, then comment on added, removed, or context lines with c / V; section comments work in the rendered view
- Without a file argument, all changed and untracked
.md files under the current directory are offered in a file picker and reviewed one by one; comments are combined into a single output
- Untracked files are shown as entirely added; unchanged files are skipped
--track-viewed is not available in diff mode
Web review
--web opens the same review in your browser. commd serves the page on 127.0.0.1, prints the URL, opens it, and waits for the review to finish; the result is output exactly as from the TUI (--output applies).
- The page works like the TUI: the same modes, dialogs, status bar, and key bindings, including the raw view line cursor,
V selection, the C comment list, and / search. --theme sets the initial colors
- Unlike the TUI there is no pane focus (
Tab does nothing): j/k/↑/↓ and the page keys scroll the content (in the raw view, move the line cursor), and pressing on at the end or start of a section moves to the next or previous one; gg/G go to the top or end of the whole document. In the full view the document reads as one page
- The mouse works too: click a section, a line number (drag or shift+click for a range), a label chip, or a button; drag the pane border to resize. Scrolling runs on across sections: past the end or start of a section it continues into the next or previous one. On narrow windows the ☰ button shows the section list
- With
--diff and no file argument, the changed files are offered in a picker first and then reviewed one by one, as in the TUI (s finishes a file, q or Ctrl+C skips it)
Ctrl+S saves a comment (Ctrl+Enter / ⌘+Enter also work); Ctrl+C copies instead of quitting while text is selected
- Pressing
Ctrl+C in the terminal abandons the whole review without output
- Reloading the page is safe: the review lives in commd, so comments and progress are kept (only a comment being typed is lost)
- The URL carries a random token that the page needs to read or change the review, so other web pages cannot access it and other local users need the token. Treat the URL like a password: it is printed to the terminal, passed to the browser launcher (briefly visible in the process list), and kept in the browser history. Besides the page, only images referenced by relative paths in the document are served, and only from the document's directory
- To review on a remote machine, run with
--port and forward the port (e.g. ssh -L 8080:127.0.0.1:8080 host), then open the printed URL locally
commd pr
Review Markdown files changed in a GitHub pull request. Comments are submitted as a GitHub PR Review with inline file comments.
# Interactive file picker for changed .md files
commd pr https://github.com/owner/repo/pull/123
# Review a specific file directly
commd pr https://github.com/owner/repo/pull/123 --file docs/README.md
| Flag |
Description |
--file |
Review a specific file instead of showing the file picker |
--theme |
Color theme: dark (default), light |
Authentication: Requires a GitHub token via GITHUB_TOKEN environment variable or gh auth login.
File size: The GitHub Contents API only decodes files up to 1 MB. Larger files (up to GitHub's 100 MB limit) are fetched automatically via their raw download URL.
File picker: When --file is not specified, an interactive file picker shows all changed .md files. All files are selected by default. Use space to toggle, a to select/deselect all, enter to confirm, q or esc to cancel.
Review flow: After selecting files, you review them one by one. For each file you can add comments, then press s to finish or q to skip. After all files, a summary dialog lets you choose to approve, comment, or cancel the review.
Submit behavior: Comments are posted as a GitHub PR Review with inline comments on each file. If no comments are added, you can optionally approve the PR. Note: Overview (file-level) comments are not posted to GitHub due to API limitations — only section-level and line-level comments are submitted.
commd version
Show the current version.
commd version
TUI Key Bindings
Normal Mode
| Key |
Action |
j / k / ↑ / ↓ |
Navigate sections (left pane) or lines (right pane, raw view) |
gg / G |
Jump to first / last |
Ctrl+D / Ctrl+U |
Half page down / up |
Ctrl+F / Ctrl+B |
Full page down / up |
l / h / → / ← |
Scroll the detail pane right / left |
H / L |
Scroll to start / end (right pane) |
> / < |
Resize left pane wider / narrower |
Enter |
Toggle expand/collapse |
Tab |
Switch focus between panes |
f |
Toggle full view / section view |
r |
Toggle raw source view (with line numbers) / rendered view |
c |
Add comment (section-level in rendered view, line-level in raw view) |
C |
Manage comments (edit/delete) |
V |
Start visual line selection (raw view, right pane) |
v |
Toggle viewed mark |
/ |
Search sections |
s |
Submit review and exit |
q / Ctrl+C |
Quit |
? |
Show help |
| Key |
Action |
Tab |
Cycle comment label (forward) |
Shift+Tab |
Cycle comment label (reverse) |
Ctrl+D |
Cycle decoration (none, non-blocking, blocking, if-minor) |
Ctrl+S |
Save comment |
Esc |
Cancel |
| Key |
Action |
j / k |
Navigate comments |
e |
Edit selected comment |
d |
Delete selected comment |
Esc |
Back to normal mode |
Status Bar
The status bar shows key hints and a progress indicator: [X/Y viewed] for sections marked as viewed, and [N comments] when comments have been added.
Search Mode
| Key |
Action |
| Type text |
Incremental filter (searches ID, title, and body) |
↑ / ↓ |
Navigate results |
Enter |
Confirm search |
Esc |
Cancel search |
Mermaid Diagram Rendering
Fenced ```mermaid code blocks are automatically converted to ASCII art in the detail pane. If rendering fails (e.g. unsupported diagram type), the original source is shown as-is.
Raw Source View
Press r to switch the right pane to raw source view with line numbers. In this mode:
- Line-level commenting: Press
c to comment on the cursor line
- Visual selection: Press
V, move with j/k to select a range, then c to comment. In diff mode (commd pr and --diff), a selection spanning both sides is automatically restricted to the cursor's side (old or new file lines) to satisfy GitHub's single-side comment requirement
- Section navigation:
j/k at the edge of a section automatically moves to the adjacent section
- Press
f to toggle between section view (only selected section's lines) and full file view
- Press
r again to return to rendered view
Both section-level comments (from rendered view) and line-level comments (from raw view) can coexist in the same session.
The review output generated on submit uses Conventional Comments labels:
# Review
Please review and address the following comments on: /path/to/document.md
## Overview
[note] Add a performance metrics section.
## S1.1: JWT verification
[suggestion (non-blocking)] Switch to HS256. Load the key from an environment variable.
## S2: Update routing
[issue (blocking)] Not needed; the existing implementation covers this.
---
`L15` [question] Is this variable used?
> const token = parseToken(header)
`L20-L25` [suggestion] Extract this block into a helper function.
> if err := validate(input); err != nil {
> return err
> }
Section-level comments (including Overview for the preamble) are grouped under section headings. Line-level comments appear below a --- divider with inline code line references, followed by a quote of the commented source (up to 5 lines) so the target can still be found after the file changes. In diff mode, comments on removed lines are numbered by the old file and marked (removed). When several files are reviewed with --diff, each file gets its own ## path heading with section headings nested below it.
Labels: suggestion, issue, question (default), nitpick, todo, thought, note, praise, chore
Decorations: non-blocking, blocking, if-minor — cycle with Ctrl+D in comment mode
Claude Code Integration (Deprecated)
Deprecated: commd cchook and commd cclocate are deprecated and will be removed in a future release. They still work but are hidden from commd --help, and cclocate prints a deprecation notice. To review a plan or other Markdown file, run commd review on it directly.
commd can be used as a Claude Code hook to review plan files interactively during plan mode.
commd cchook
Run as a Claude Code hook. Launches the review TUI for the plan file to enable a feedback loop. Two trigger points are supported:
PreToolUse on ExitPlanMode (recommended): fires once, when Claude has finished the plan and asks to leave plan mode. Claude Code injects the plan file path (tool_input.planFilePath), so no plansDirectory lookup is involved. Intermediate edits to the plan do not open a review.
PostToolUse on Write|Edit: fires on every write to a file under plansDirectory, including edits made before the plan is complete.
# Called automatically by Claude Code hook (no manual invocation needed)
commd cchook
| Flag |
Description |
--spawner |
Terminal multiplexer: auto (default), wezterm, tmux |
--theme |
Color theme: dark (default), light |
Note: Currently only WezTerm is supported as a terminal multiplexer spawner. tmux support is not yet implemented. auto will try WezTerm first, then fall back to running in the same terminal.
commd cclocate
Locate plan file paths from a Claude Code transcript JSONL. Useful for debugging the PostToolUse trigger's plansDirectory resolution; the PreToolUse/ExitPlanMode trigger receives the plan path directly and does not need it.
commd cclocate --transcript ~/.claude/projects/.../session.jsonl
# List all plan files found in a transcript
commd cclocate --transcript session.jsonl --all
# Read hook JSON input from stdin to resolve the plan file
commd cclocate --stdin
Hook Setup
Add the following to .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "commd cchook",
"timeout": 600
}
]
}
]
}
}
The hook only activates in plan mode and automatically enables --track-viewed. The review opens before Claude Code's own plan approval dialog:
- Claude writes the plan and calls
ExitPlanMode
- commd opens the plan for review
- submitted (exit 2): the review is sent to Claude as the denial reason; Claude revises the plan in plan mode and calls
ExitPlanMode again (back to step 2)
- approved / cancelled (exit 0): Claude Code shows its usual plan approval dialog
To review on every plan file write instead (including intermediate edits), use the PostToolUse trigger. It requires the file to be under plansDirectory:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "commd cchook",
"timeout": 600
}
]
}
]
}
}
Set CC_PLAN_REVIEW_SKIP=1 to temporarily disable the hook.
Development
Dev tools are managed by mise. Run mise install to set up the toolchain (includes Go linters, formatters, and bun).
mise run ci # Run full CI pipeline (fmt, fix, lint, build, cov, e2e-basic)
mise run e2e # Run all E2E tests (full suite)
mise run e2e-basic # Run basic E2E tests (critical path only, included in ci)
E2E tests use tuistory to drive the TUI in a virtual terminal and Playwright to drive the --web page in headless Chromium (installed by the e2e tasks).
Migration from ccplan
commd was formerly known as ccplan. If you are upgrading:
| Item |
Before |
After |
| Binary |
ccplan |
commd |
| Subcommand |
ccplan review |
commd review |
| Subcommand |
ccplan hook |
commd cchook |
| Subcommand |
ccplan locate |
commd cclocate |
| Hook config |
"command": "ccplan hook" |
"command": "commd cchook" |
| Environment variable |
PLAN_REVIEW_SKIP=1 |
CC_PLAN_REVIEW_SKIP=1 |
| go install |
github.com/koh-sh/ccplan |
github.com/koh-sh/commd |
| mise |
github:koh-sh/ccplan |
github:koh-sh/commd |
For mise users upgrading:
mise uninstall github:koh-sh/ccplan
mise use -g github:koh-sh/commd