remorses/critique

TUI & website for reviewing git changes

TypeScript

1,275

463 commits

updated Sep 27, 2026

See the code

README



critique

Beautiful diff viewer for terminals, web previews, and agents.



Diff Viewer Demo

Installation

critique requires Bun. It does not run under Node.js.

# Run directly without installing
bunx critique

# Or install globally
bun install -g critique

Quick Start

Open the current working tree diff in the terminal:

critique

Upload the same diff and get a shareable URL:

critique --web "Current working tree"

Share a GitHub pull request directly, from any directory:

critique https://github.com/remorses/sigillo/pull/19 --web "Sigillo PR #19"

Review staged changes:

critique --staged
critique --staged --web "Staged changes"

Core Diff Commands

critique follows the same mental model as git diff.

A GitHub PR URL fetches the pull request diff from the GitHub API. Public PRs work without login. For private PRs, use gh auth login, GH_TOKEN, or GITHUB_TOKEN. The URL also works with --pdf, --image, --filter, or in the terminal viewer.

# View unstaged changes, including untracked files
critique

# View staged changes
critique --staged

# View changes since a ref
critique HEAD~1
critique main

# View one commit only
critique --commit HEAD~1
critique --commit abc1234

# Compare two refs, PR style
critique main HEAD
critique main feature-branch

# Watch the working tree and refresh on changes
critique --watch

# Add experimental call-stack changes to the file tree
critique --calldiff

# Filter files by glob pattern
critique --filter "src/**/*.ts"
critique --filter "src/**/*.ts" --filter "lib/**/*.js"

Which Commits a Diff Contains

Whenever a diff spans commits, critique lists them before the diff or the URL.

3 commits, 22 files, +1573 -311

  2a09302  Correct the identity docs, and mark the release minor
  1fb8af7  Give every element a stable GPUI identity
  7998490  Launch a window without stealing focus
  base: f948f50  Reclaim the style table when the tree shrinks

  + uncommitted working tree changes

This matters because a rebased branch can carry commits replayed from another branch. The merge base is then too far back, and a shared link silently includes work you did not write. If a listed commit is not yours, pass the first commit of your own work as the base:

# Wrong: the merge base pulls in a commit a rebase replayed onto the branch
critique f948f50 --web "Element identity"

# Right: start from your own first commit
critique 7998490 --web "Element identity"

Long ranges are truncated, but the oldest commits are always kept, because a rebase replays a foreign commit right above the base. Silence the list in scripts with --no-commit-list. With --json it goes to stderr and the commits are added to the JSON payload instead.

Diverged Branches

critique A..B and critique <ref> compare two trees directly. On diverged branches such a diff also undoes every commit that exists only on the base side. Those commits are part of the diff, so critique lists them too:

1 commit added, 1 commit reversed, 2 files, +1 -1

  added by right:
    a279fbe  Only on right

  reversed from left:
    d395611  Only on left

  ! left and right have diverged, so this diff also undoes the commits above.

critique A...B and critique A B start at the merge base instead, so they never reverse anything, and the base: line names the merge base rather than the ref.

Plain unstaged and --staged diffs contain no commits, so nothing is printed.

Call-stack Diffs

--calldiff uses calldiff to show how function calls changed. Each changed call tree appears below its source file in the top file tree.

# Working tree call changes
critique --calldiff

# Changes since a ref
critique main --calldiff

# PR-style comparison and web preview
critique main HEAD --calldiff --web "Call flow changes"

# One commit
critique --commit HEAD --calldiff

The feature is experimental. calldiff uses Tree-sitter and can install a language grammar through npm on first use. --staged, --stdin, and --watch are not supported with --calldiff.

Set CRITIQUE_CALLDIFF=1 to enable call-stack diffs by default:

export CRITIQUE_CALLDIFF=1
critique
KeyAction
↑ / ↓Scroll up and down
pOpen file selector dropdown
tOpen theme picker
Option heldFast scroll at 10x speed
g g / GJump to top / bottom
Ctrl+D / Ctrl+UHalf page down / up
q / EscQuit / close overlay

Web Previews

--web renders the diff with the same terminal renderer, uploads it to critique.work, and prints a shareable URL.

# Working tree changes
critique --web "Fix auth retry"

# Staged changes
critique --staged --web "Release notes"

# Changes since a ref
critique main --web "Branch changes"

# One commit
critique --commit HEAD --web "Latest commit"

# PR-style branch diff
critique main HEAD --web "Current branch"

# Pull request from GitHub (no checkout needed)
critique https://github.com/remorses/sigillo/pull/19 --web "Sigillo PR #19"

# JSON output for scripts
critique --web "Deploy changes" --json

Generated URLs look like critique.work/v/<id>.

Web Preview

Web Preview Options

FlagDescriptionDefault
--web [title]Generate and upload a web previewCritique Diff
--stagedShow staged changesnone
--commit <ref>Show changes from a specific commitnone
--calldiffAdd experimental call-stack changes to the file treeoff
--cols <n>Desktop render width240
--mobile-cols <n>Mobile render width100
--filter <pattern>Filter files by glob, can be repeatednone
--theme <name>Use a fixed theme instead of auto light and dark modenone
--no-commit-listDo not list the commits contained in the rangeoff
--openOpen the URL in your browsernone
--jsonPrint { url, id, files, commits } for scriptsnone

How Web Uploads Work

┌─────────────────────────────────────┐
│ git diff / GitHub PR diff           │
└─────────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│ opentui test renderer               │
└─────────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│ HTML variants and raw patch         │
└─────────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│ critique.work upload                │
└─────────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│ shareable URL, optional .patch      │
└─────────────────────────────────────┘

The CLI does not generate a local HTML file. It uploads to critique.work. Local HTML export is tracked separately in issue #42.

Uploaded diffs expire after 7 days unless you use a license key. Identical diffs reuse the same content hash URL.

Raw Patch Access

Every --web upload also stores the raw unified diff. Append .patch to any critique URL to fetch it.

CRITIQUE_URL='https://critique.work/v/<id>'

# View the patch in your terminal
curl "$CRITIQUE_URL.patch"

# Apply the patch directly to your repo
curl -s "$CRITIQUE_URL.patch" | git apply

# Reverse the patch
curl -s "$CRITIQUE_URL.patch" | git apply --reverse

Git Difftool Integration

Configure critique as your git difftool:

git config --global diff.tool critique
git config --global difftool.critique.cmd 'critique difftool "$LOCAL" "$REMOTE"'

Then run:

git difftool HEAD~1

Lazygit Integration

Use critique as a custom pager in lazygit:

# ~/.config/lazygit/config.yml
git:
  pagers:
    - pager: critique --stdin

For details, see lazygit's Custom Pagers documentation.

Pick Files from Another Branch

critique pick lets you apply selected files from another branch to the current checkout.

critique pick feature-branch

Selected files are applied as patches. Deselected files are restored.

Selective Hunk Staging

critique hunks gives scripts and agents a stable alternative to git add -p.

# List unstaged hunks with stable IDs
critique hunks list

# List staged hunks
critique hunks list --staged

# Filter by file pattern
critique hunks list --filter "src/**/*.ts"

# Stage one hunk by ID
critique hunks add 'src/main.ts:@a1b2c3d4e5f6'

# Stage multiple hunks
critique hunks add 'src/main.ts:@a1b2c3d4e5f6' 'src/utils.ts:@f6e5d4c3b2a1'

Hunk IDs use this format:

file:@<hash>
file:@<hash>.1
file:@<hash>.2

The hash is from the hunk's added and removed lines, not the @@ line numbers. Unrelated edits above or below the hunk do not change the ID. Duplicate payloads in the same file get .1, .2, and so on. Old file:@-oldStart,... IDs are no longer accepted.

critique hunks list still prints the @@ header under each ID, so you can see where the hunk sits in the file.

E-Ink Reading

Generate PDFs from diffs to read on Kindle or Boox e-readers.

critique --pdf
critique main --pdf --open

The PDF preserves syntax highlighting and diff formatting. Email it to your Kindle, drop it in BooxDrop, or save it to a synced Google Drive folder. See docs/e-reader-guide.md for setup details.

Agent Skill

This package ships a skill file that teaches AI coding agents how to use critique for diff URLs, PDFs, images, and selective hunk staging.

npx -y skills add remorses/critique

Features

  • Syntax highlighting: powered by Tree-sitter via opentui
  • Split view: side-by-side comparison for wide terminals, unified view on narrow terminals
  • Word-level diff: highlights exact word changes inside modified lines
  • File navigation: quick file switcher with fuzzy search
  • Click to open: click line numbers to open in your editor with REACT_EDITOR
  • Watch mode: refreshes as you edit files
  • Web previews: hosted shareable URLs on critique.work
  • Raw patches: every web preview has a .patch endpoint
  • PDF output: optimized for code review away from the terminal

Supported Languages

TypeScript, JavaScript, TSX, JSX, JSON, Markdown, HTML, CSS, Python, Rust, Go, Java, C, C++, C#, Ruby, PHP, Scala, Haskell, Julia, OCaml, Clojure, Swift, Nix, YAML, and Bash.

Configuration

Environment VariableDescriptionDefault
REACT_EDITOREditor command for click-to-openzed
CRITIQUE_WORKER_URLCustom worker URL for web previewshttps://critique.work

Ignored Files

Lock files are automatically hidden from diffs:

  • pnpm-lock.yaml
  • package-lock.json
  • yarn.lock
  • bun.lockb
  • bun.lock
  • Cargo.lock
  • poetry.lock
  • Gemfile.lock
  • composer.lock

Files with more than 6000 lines of diff are also hidden for performance.

Built With

  • opentui: React-based terminal UI framework
  • Tree-sitter: syntax highlighting
  • diff: diff algorithm
  • Hono: web framework for the preview worker

Sponsors

CodeRabbit

Sponsored by CodeRabbit.

License

MIT

diff
opentui
tui

remorses/critique

TUI & website for reviewing git changes

TypeScript

1,275

463 commits

updated Sep 27, 2026

See the code

README



critique

Beautiful diff viewer for terminals, web previews, and agents.



Diff Viewer Demo

Installation

critique requires Bun. It does not run under Node.js.

# Run directly without installing
bunx critique

# Or install globally
bun install -g critique

Quick Start

Open the current working tree diff in the terminal:

critique

Upload the same diff and get a shareable URL:

critique --web "Current working tree"

Share a GitHub pull request directly, from any directory:

critique https://github.com/remorses/sigillo/pull/19 --web "Sigillo PR #19"

Review staged changes:

critique --staged
critique --staged --web "Staged changes"

Core Diff Commands

critique follows the same mental model as git diff.

A GitHub PR URL fetches the pull request diff from the GitHub API. Public PRs work without login. For private PRs, use gh auth login, GH_TOKEN, or GITHUB_TOKEN. The URL also works with --pdf, --image, --filter, or in the terminal viewer.

# View unstaged changes, including untracked files
critique

# View staged changes
critique --staged

# View changes since a ref
critique HEAD~1
critique main

# View one commit only
critique --commit HEAD~1
critique --commit abc1234

# Compare two refs, PR style
critique main HEAD
critique main feature-branch

# Watch the working tree and refresh on changes
critique --watch

# Add experimental call-stack changes to the file tree
critique --calldiff

# Filter files by glob pattern
critique --filter "src/**/*.ts"
critique --filter "src/**/*.ts" --filter "lib/**/*.js"

Which Commits a Diff Contains

Whenever a diff spans commits, critique lists them before the diff or the URL.

3 commits, 22 files, +1573 -311

  2a09302  Correct the identity docs, and mark the release minor
  1fb8af7  Give every element a stable GPUI identity
  7998490  Launch a window without stealing focus
  base: f948f50  Reclaim the style table when the tree shrinks

  + uncommitted working tree changes

This matters because a rebased branch can carry commits replayed from another branch. The merge base is then too far back, and a shared link silently includes work you did not write. If a listed commit is not yours, pass the first commit of your own work as the base:

# Wrong: the merge base pulls in a commit a rebase replayed onto the branch
critique f948f50 --web "Element identity"

# Right: start from your own first commit
critique 7998490 --web "Element identity"

Long ranges are truncated, but the oldest commits are always kept, because a rebase replays a foreign commit right above the base. Silence the list in scripts with --no-commit-list. With --json it goes to stderr and the commits are added to the JSON payload instead.

Diverged Branches

critique A..B and critique <ref> compare two trees directly. On diverged branches such a diff also undoes every commit that exists only on the base side. Those commits are part of the diff, so critique lists them too:

1 commit added, 1 commit reversed, 2 files, +1 -1

  added by right:
    a279fbe  Only on right

  reversed from left:
    d395611  Only on left

  ! left and right have diverged, so this diff also undoes the commits above.

critique A...B and critique A B start at the merge base instead, so they never reverse anything, and the base: line names the merge base rather than the ref.

Plain unstaged and --staged diffs contain no commits, so nothing is printed.

Call-stack Diffs

--calldiff uses calldiff to show how function calls changed. Each changed call tree appears below its source file in the top file tree.

# Working tree call changes
critique --calldiff

# Changes since a ref
critique main --calldiff

# PR-style comparison and web preview
critique main HEAD --calldiff --web "Call flow changes"

# One commit
critique --commit HEAD --calldiff

The feature is experimental. calldiff uses Tree-sitter and can install a language grammar through npm on first use. --staged, --stdin, and --watch are not supported with --calldiff.

Set CRITIQUE_CALLDIFF=1 to enable call-stack diffs by default:

export CRITIQUE_CALLDIFF=1
critique
KeyAction
↑ / ↓Scroll up and down
pOpen file selector dropdown
tOpen theme picker
Option heldFast scroll at 10x speed
g g / GJump to top / bottom
Ctrl+D / Ctrl+UHalf page down / up
q / EscQuit / close overlay

Web Previews

--web renders the diff with the same terminal renderer, uploads it to critique.work, and prints a shareable URL.

# Working tree changes
critique --web "Fix auth retry"

# Staged changes
critique --staged --web "Release notes"

# Changes since a ref
critique main --web "Branch changes"

# One commit
critique --commit HEAD --web "Latest commit"

# PR-style branch diff
critique main HEAD --web "Current branch"

# Pull request from GitHub (no checkout needed)
critique https://github.com/remorses/sigillo/pull/19 --web "Sigillo PR #19"

# JSON output for scripts
critique --web "Deploy changes" --json

Generated URLs look like critique.work/v/<id>.

Web Preview

Web Preview Options

FlagDescriptionDefault
--web [title]Generate and upload a web previewCritique Diff
--stagedShow staged changesnone
--commit <ref>Show changes from a specific commitnone
--calldiffAdd experimental call-stack changes to the file treeoff
--cols <n>Desktop render width240
--mobile-cols <n>Mobile render width100
--filter <pattern>Filter files by glob, can be repeatednone
--theme <name>Use a fixed theme instead of auto light and dark modenone
--no-commit-listDo not list the commits contained in the rangeoff
--openOpen the URL in your browsernone
--jsonPrint { url, id, files, commits } for scriptsnone

How Web Uploads Work

┌─────────────────────────────────────┐
│ git diff / GitHub PR diff           │
└─────────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│ opentui test renderer               │
└─────────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│ HTML variants and raw patch         │
└─────────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│ critique.work upload                │
└─────────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│ shareable URL, optional .patch      │
└─────────────────────────────────────┘

The CLI does not generate a local HTML file. It uploads to critique.work. Local HTML export is tracked separately in issue #42.

Uploaded diffs expire after 7 days unless you use a license key. Identical diffs reuse the same content hash URL.

Raw Patch Access

Every --web upload also stores the raw unified diff. Append .patch to any critique URL to fetch it.

CRITIQUE_URL='https://critique.work/v/<id>'

# View the patch in your terminal
curl "$CRITIQUE_URL.patch"

# Apply the patch directly to your repo
curl -s "$CRITIQUE_URL.patch" | git apply

# Reverse the patch
curl -s "$CRITIQUE_URL.patch" | git apply --reverse

Git Difftool Integration

Configure critique as your git difftool:

git config --global diff.tool critique
git config --global difftool.critique.cmd 'critique difftool "$LOCAL" "$REMOTE"'

Then run:

git difftool HEAD~1

Lazygit Integration

Use critique as a custom pager in lazygit:

# ~/.config/lazygit/config.yml
git:
  pagers:
    - pager: critique --stdin

For details, see lazygit's Custom Pagers documentation.

Pick Files from Another Branch

critique pick lets you apply selected files from another branch to the current checkout.

critique pick feature-branch

Selected files are applied as patches. Deselected files are restored.

Selective Hunk Staging

critique hunks gives scripts and agents a stable alternative to git add -p.

# List unstaged hunks with stable IDs
critique hunks list

# List staged hunks
critique hunks list --staged

# Filter by file pattern
critique hunks list --filter "src/**/*.ts"

# Stage one hunk by ID
critique hunks add 'src/main.ts:@a1b2c3d4e5f6'

# Stage multiple hunks
critique hunks add 'src/main.ts:@a1b2c3d4e5f6' 'src/utils.ts:@f6e5d4c3b2a1'

Hunk IDs use this format:

file:@<hash>
file:@<hash>.1
file:@<hash>.2

The hash is from the hunk's added and removed lines, not the @@ line numbers. Unrelated edits above or below the hunk do not change the ID. Duplicate payloads in the same file get .1, .2, and so on. Old file:@-oldStart,... IDs are no longer accepted.

critique hunks list still prints the @@ header under each ID, so you can see where the hunk sits in the file.

E-Ink Reading

Generate PDFs from diffs to read on Kindle or Boox e-readers.

critique --pdf
critique main --pdf --open

The PDF preserves syntax highlighting and diff formatting. Email it to your Kindle, drop it in BooxDrop, or save it to a synced Google Drive folder. See docs/e-reader-guide.md for setup details.

Agent Skill

This package ships a skill file that teaches AI coding agents how to use critique for diff URLs, PDFs, images, and selective hunk staging.

npx -y skills add remorses/critique

Features

  • Syntax highlighting: powered by Tree-sitter via opentui
  • Split view: side-by-side comparison for wide terminals, unified view on narrow terminals
  • Word-level diff: highlights exact word changes inside modified lines
  • File navigation: quick file switcher with fuzzy search
  • Click to open: click line numbers to open in your editor with REACT_EDITOR
  • Watch mode: refreshes as you edit files
  • Web previews: hosted shareable URLs on critique.work
  • Raw patches: every web preview has a .patch endpoint
  • PDF output: optimized for code review away from the terminal

Supported Languages

TypeScript, JavaScript, TSX, JSX, JSON, Markdown, HTML, CSS, Python, Rust, Go, Java, C, C++, C#, Ruby, PHP, Scala, Haskell, Julia, OCaml, Clojure, Swift, Nix, YAML, and Bash.

Configuration

Environment VariableDescriptionDefault
REACT_EDITOREditor command for click-to-openzed
CRITIQUE_WORKER_URLCustom worker URL for web previewshttps://critique.work

Ignored Files

Lock files are automatically hidden from diffs:

  • pnpm-lock.yaml
  • package-lock.json
  • yarn.lock
  • bun.lockb
  • bun.lock
  • Cargo.lock
  • poetry.lock
  • Gemfile.lock
  • composer.lock

Files with more than 6000 lines of diff are also hidden for performance.

Built With

  • opentui: React-based terminal UI framework
  • Tree-sitter: syntax highlighting
  • diff: diff algorithm
  • Hono: web framework for the preview worker

Sponsors

CodeRabbit

Sponsored by CodeRabbit.

License

MIT

diff
opentui
tui

Significant stargazers

(top 24 of 48)

Luke Edwards

5,087 followers · starred Dec 2025

Karl Horky

973 followers · starred Jan 2026

Johannes Schickling

2,475 followers · starred Jan 2026

Kit Langton

1,607 followers · starred Jan 2026