Skip to content
/ orbit Public

A terminal-based code review tool

License

Notifications You must be signed in to change notification settings

Hoshock/orbit

Repository files navigation

orbit (Offline Review Board In Terminal)

orbit

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.

Demo

Why

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.

Screenshots

Home screen -- file tree with diff preview

Home screen

Unified view -- unified diff with syntax highlighting, fold/unfold

Unified view

Split view -- side-by-side comparison

Split view

Comment -- add review comments on any line

Comment

Prompt preview -- export comments as a structured prompt

Prompt preview

Install

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/orbit

Make sure ~/.local/bin is in your PATH.

Usage

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 unresolvable

Lazygit integration

Add 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: terminal

Press 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.

Keybindings

The following are default keybindings. You can override them in config.toml.

File list

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

Diff view

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)

Comment input

Key Action
Esc Cancel
Ctrl+Enter Submit

Comment list

Key Action
Esc/q Back to file list
Up/Down Move cursor
Enter Jump to comment
d Delete comment
e Edit comment

Prompt preview

Key Action
Esc/q Back
y Copy prompt to clipboard

How the prompt works

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.

Persistence

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.

Configuration

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"

Stack

  • Bun - runtime and test runner
  • OpenTUI - terminal UI framework (React-based)
  • React - component model
  • Biome - linter and formatter

Development

bun run start             # run from source
bun test                  # run tests
bun run check             # lint + build check
bun run lint              # auto-fix lint issues

Syntax highlighting

orbit 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/)

Adding a new language

  1. Get the .wasm grammar and highlights.scm

    mkdir -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 .wasm starts with \0asm (not a 404 page): xxd ... | head -1

  2. Register the parser in src/index.tsx

    import 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)] },
      },
    ]);
  3. Ensure filetype.ts has the mappingsrc/utils/filetype.ts maps file extensions to language names. Add an entry if it doesn't exist yet.

  4. Add a LICENSE file — Place a LICENSE in assets/tree-sitter/<language>/ with the MIT notice from the grammar repo. See assets/tree-sitter/python/LICENSE for the format.

  5. Verifybun run check should show the new .wasm and .scm in the build output.

License

MIT

About

A terminal-based code review tool

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages