A terminal-based code review tool. Browse git diffs, leave comments on specific lines, then export everything as a prompt you can paste into Claude Code or any other AI tool.
Inspired by difit, a great browser-based local diff viewer. Commenting on lines works in the browser, but not yet in the TUI. I wanted a fully terminal-native diff reviewer with line-level comments, a customizable syntax highlighting theme, split view, and a prompt export workflow for AI coding assistants -- so I built orbit.
The key trick is the prompt export. Your review comments become a structured prompt that an AI coding assistant can act on directly. Review a diff, jot down what needs fixing, copy the prompt, paste it, done.
Home screen -- file tree with diff preview
Unified view -- unified diff with syntax highlighting, fold/unfold
Split view -- side-by-side comparison
Comment -- add review comments on any line
Prompt preview -- export comments as a structured prompt
Requires Bun v1.2+.
git clone https://github.com/Hoshock/orbit.git
cd orbit
bun install
bun run register # symlinks bin/orbit to ~/.local/bin/orbitMake sure ~/.local/bin is in your PATH.
orbit # unstaged changes (git diff)
orbit . # same as above
orbit --staged # staged changes (git diff --staged)
orbit HEAD # last commit (HEAD~1..HEAD)
orbit HEAD~3..HEAD # commit range
orbit feature main # branch comparison
orbit --root SHA~1..SHA # diff against empty tree if base is unresolvableAdd the following to your lazygit config (~/.config/lazygit/config.yml) to launch orbit directly from lazygit with a single key:
customCommands:
- key: "o"
description: "Review uncommitted changes"
command: "orbit ."
context: "files"
output: terminal
- key: "o"
description: "Review branch diff"
command: "orbit {{.SelectedLocalBranch.Name}} {{.CheckedOutBranch.Name}}"
context: "localBranches"
output: terminal
- key: "o"
description: "Review commit(s)"
command: "orbit --root {{.SelectedCommitRange.From}}~1..{{.SelectedCommitRange.To}}"
context: "commits"
output: terminalPress o in any of these panels to open orbit:
| Panel | What it reviews |
|---|---|
| Files | Unstaged changes |
| Branches | Diff between selected branch and current branch |
| Commits | Selected commit, or range if multiple are selected |
For commit ranges, select multiple commits with v (visual mode) or shift+up/down in lazygit, then press o. The ~1 ensures the first selected commit is included in the diff. The --root flag handles the case where the selection includes the initial commit by diffing against an empty tree.
The following are default keybindings. You can override them in config.toml.
| Key | Action |
|---|---|
Esc/q |
Quit |
Up/Down |
Move cursor |
Left/Right |
Collapse/expand directory |
[/] |
Shrink/grow tree panel (10%-50%) |
Enter |
Open diff or toggle directory |
c |
Comment list |
p |
Prompt preview |
t |
Toggle split/unified |
v |
Toggle viewed |
| Key | Action |
|---|---|
Esc/q |
Back to file list |
Up/Down |
Move by line |
Left/Right |
Switch side (split mode) |
Shift+Up/Down |
Select range |
c |
Comment on current line or selection |
d |
Delete comment at cursor |
e |
Edit comment at cursor |
f |
File-level comment |
t |
Toggle split/unified |
v |
Toggle viewed |
z |
Fold/unfold (incremental, 20 lines at a time) |
| Key | Action |
|---|---|
Esc |
Cancel |
Ctrl+Enter |
Submit |
| Key | Action |
|---|---|
Esc/q |
Back to file list |
Up/Down |
Move cursor |
Enter |
Jump to comment |
d |
Delete comment |
e |
Edit comment |
| Key | Action |
|---|---|
Esc/q |
Back |
y |
Copy prompt to clipboard |
Each comment you leave records the file path, line number, which side of the diff (old/new), and the code at that line. When you press p to preview and y to copy, orbit formats all of this into a single text block:
src/app.tsx:L42 (a1b2c3d)
This function should handle the edge case where files is empty.
==========
src/utils/git.ts:L15-L20 (a1b2c3d)
Extract this into a helper, it's duplicated in three places.
Paste that into Claude Code (or any LLM) and it has enough context to act on each comment.
Comments, viewed status, and tree panel width are automatically saved and restored across sessions.
| Data | Cache file |
|---|---|
| Comments, viewed, tree width | /tmp/orbit-<repo>-<hash>.json |
The hash is derived from the diff range (e.g., HEAD~1..HEAD), so different ranges get separate caches. Cache files live in /tmp and are cleared on OS restart.
orbit reads custom settings from ${XDG_CONFIG_HOME:-~/.config}/orbit/config.toml.
If the file (or a specific key) is missing, default values are used.
file_tree_initial_width = 0.2
initial_view = "unified" # or "split"
[keybindings.file-tree]
quit = "q"
tree_shrink = "["
tree_grow = "]"
comment_list = "c"
prompt_preview = "p"
toggle_view_mode = "t"
toggle_viewed = "v"
[keybindings.diff-view]
quit = "q"
comment = "c"
delete_comment = "d"
edit_comment = "e"
file_comment = "f"
toggle_view_mode = "t"
toggle_viewed = "v"
fold = "z"
# comment-input has no configurable keybindings (Esc / Ctrl+Enter fixed)
[keybindings.comment-list]
quit = "q"
delete_comment = "d"
edit_comment = "e"
[keybindings.prompt-preview]
quit = "q"
copy_prompt = "y"- Bun - runtime and test runner
- OpenTUI - terminal UI framework (React-based)
- React - component model
- Biome - linter and formatter
bun run start # run from source
bun test # run tests
bun run check # lint + build check
bun run lint # auto-fix lint issuesorbit uses tree-sitter for syntax highlighting. The following languages are currently supported:
| Language | Source |
|---|---|
| JavaScript | OpenTUI built-in |
| TypeScript | OpenTUI built-in |
| Markdown | OpenTUI built-in |
| Zig | OpenTUI built-in |
| Python | Bundled grammar (assets/tree-sitter/python/) |
-
Get the
.wasmgrammar andhighlights.scmmkdir -p assets/tree-sitter/<language> # Prebuilt wasm from unpkg curl -L "https://unpkg.com/tree-sitter-wasms@latest/out/tree-sitter-<language>.wasm" \ -o assets/tree-sitter/<language>/tree-sitter-<language>.wasm # Highlight queries from the official tree-sitter grammar repo curl -L "https://raw.githubusercontent.com/tree-sitter/tree-sitter-<language>/master/queries/highlights.scm" \ -o assets/tree-sitter/<language>/highlights.scm
Verify the
.wasmstarts with\0asm(not a 404 page):xxd ... | head -1 -
Register the parser in
src/index.tsximport langWasm from "../assets/tree-sitter/<language>/tree-sitter-<language>.wasm" with { type: "file" }; import langHighlights from "../assets/tree-sitter/<language>/highlights.scm" with { type: "file" };
Then add an entry to the
addDefaultParsers()call:addDefaultParsers([ // ... existing entries { filetype: "<language>", wasm: resolve(__dir, langWasm), queries: { highlights: [resolve(__dir, langHighlights)] }, }, ]);
-
Ensure
filetype.tshas the mapping —src/utils/filetype.tsmaps file extensions to language names. Add an entry if it doesn't exist yet. -
Add a LICENSE file — Place a
LICENSEinassets/tree-sitter/<language>/with the MIT notice from the grammar repo. Seeassets/tree-sitter/python/LICENSEfor the format. -
Verify —
bun run checkshould show the new.wasmand.scmin the build output.
MIT






