chenyukang/ghr

https://catcoding.me/ghr/ ghr is a fast terminal workspace for staying on top of GitHub. It brings pull requests, issues, notifications, repo tabs, conversations, checks, and diffs into one stateful TUI

Rust

95

339 commits

updated Oct 18, 2026

See the code

README

ghr

ghr is a fast terminal workspace for staying on top of GitHub. It brings your GitHub inbox, pull requests, issues, repo tabs, conversations, checks, and diffs into one stateful TUI, so you can triage, review, comment, approve, merge, and jump back in without waiting on a fresh GitHub fetch.

CI Release

Conversation and triage view

ghr conversation and triage screenshot

Pull request diff review view

ghr pull request diff review screenshot

Features

  • Inbox, pull request, and issue views.
  • Snapshot-first startup: cached data is shown immediately, the active view refreshes first, Inbox refreshes every 60 seconds while idle, and non-active PR/issue sections are kept warm by a quiet idle sweep.
  • Bounded read-request scheduling per GitHub backend, with limited foreground concurrency, serialized background work, foreground priority, resource-specific rate-limit cooldowns, and rate-limit-aware retries; write operations run immediately and are never retried automatically.
  • Configurable sections and repo tabs, including multi-query sections such as Needs Attention.
  • Automatic current-repo tab persistence when launched inside a Git checkout with a GitHub remote.
  • Paged PR and issue lists with configurable page size.
  • Persistent ignored PRs and issues, stored in UI state and hidden from all lists.
  • Recent Items command for jumping back to the last 200 PRs and issues, including linked inbox notifications, where you spent at least 5 seconds in Details.
  • Fuzzy filtering in every loaded list with /, quick PR/issue/inbox section filters with f, plus structured GitHub search with S.
  • Details pane with rendered Markdown, clickable links and image attachments, fenced code blocks with lightweight Rust and plain/log highlighting, descriptions, comments, review comments, PR commit activity, labels, milestones, action hints, and check summaries.
  • Inbox notifications lazily load linked PR or issue details when opened, so descriptions and recent PR commit activity appear without making the initial inbox fetch heavier.
  • PR diff mode with a changed-file list, per-file diff rendering, inline review comments, and review ranges.
  • Comment, reply, edit, resolve review threads, milestone, merge, close/reopen, update-branch, rerun-failed-checks, local PR checkout, draft / ready-for-review, and full PR review submit flows from inside the TUI.
  • Inbox read/done/mute handling with explicit commands, local cache updates, GitHub sync, and dimmed read items.
  • Mouse support for tabs, lists, links, descriptions, comments, editor cursor placement, details drag-copy, scrolling, text selection mode, and split resizing.
  • Built-in auto plus named light and dark color themes configured through defaults.theme / defaults.theme_name; auto follows the macOS appearance when available.
  • UI state persistence under ~/.ghr, including focus, selected item, scroll position, split ratio, and diff mode.
  • Local state under ~/.ghr: config, SQLite snapshot database, logs, and UI state.
  • Supports direct GitHub API access with a personal access token, or the GitHub CLI as a compatible fallback.

Authentication

Choose either authentication method:

  1. Set a personal access token (classic):
export GHR_GITHUB_TOKEN=ghp_...
ghr

For full access to private repositories, select the classic repo scope. For public repositories only, use public_repo together with notifications. The workflow scope is not required because ghr does not modify workflow files. GitHub's notification endpoints accept the notifications or repo scope, and linked private issues, pull requests, and commits require repo.

GH_TOKEN and GITHUB_TOKEN are also recognized. GHR_GITHUB_TOKEN takes precedence. Tokens are read from the environment and are never written to ~/.ghr/config.toml. Treat the token like a password and give it an expiration date.

Fine-grained PATs (github_pat_...) provide partial repository access, but are not recommended for the complete ghr experience. GitHub's Notifications API does not support fine-grained PATs, so Inbox loading and read/done/mute actions will fail. Fine-grained PATs are also limited to one resource owner, cannot access multiple organizations at once, may not support every Checks API operation, and can require organization approval or a shorter lifetime. See GitHub's documentation for notification authentication and fine-grained PAT limitations.

  1. Install GitHub CLI and authenticate it:
gh auth login

GitHub CLI is not required in PAT mode. Local checkout uses the matching repository remote with ordinary git commands.

Installation

You can install ghr with Homebrew on macOS or Linux through the project tap:

brew install chenyukang/tap/ghr-cli

You can also install ghr with Cargo:

cargo install ghr-cli

Or install the latest release binary on macOS or Linux:

curl -fsSL https://raw.githubusercontent.com/chenyukang/ghr/main/install.sh | sh

Install the latest release binary on Windows PowerShell:

irm https://raw.githubusercontent.com/chenyukang/ghr/main/install.ps1 | iex

Then set a token or authenticate GitHub CLI and run ghr:

# PAT mode, without GitHub CLI
export GHR_GITHUB_TOKEN=ghp_...
ghr

# Or GitHub CLI mode
gh auth login
ghr

## by default, ghr starts in the Inbox/Issues/Pull Requests view
## go to some dir with a GitHub remote and run ghr to see the repo tab show up
## command palette (press `:`) and then type "Project Add" to add new repos

The installers detect your OS and CPU architecture, download the matching GitHub release asset with visible progress, verify its .sha256, and install ghr into ~/.local/bin by default. Use GHR_INSTALL_DIR to choose another install directory, or GHR_VERSION to pin a release tag:

curl -fsSL https://raw.githubusercontent.com/chenyukang/ghr/main/install.sh | GHR_VERSION=v0.9.1 GHR_INSTALL_DIR=/usr/local/bin sh

Usage

Run ghr after setting a token or completing gh auth login. When started inside a Git checkout with a GitHub remote, ghr adds that repository as a local project tab automatically.

Keybindings

Press ? in the TUI for the live shortcut reference. The top-right status shows the current app state; the footer stays focused on the most useful shortcuts for the active area.

KeyAction
:Open the command palette; recent commands lead before typing, then fuzzy relevance wins
1 / 2 / 3 / 4Focus ghr / Sections / list / Details
TabSwitch list/details focus; when ghr or Sections is focused, move to the next tab
Shift+Tab in ListSwitch to the previous Section, then return focus to List after 200 ms
Shift+[ / Shift+] in ListSwitch to the left/right Section, then return focus to List after 200 ms
Shift+Tab elsewhereReturn from Details to List, or move backward within focused ghr/Sections tabs
h / l or [ / ]Move within the focused ghr or Sections tab group, wrapping at the ends
EnterFocus the details pane from the list
EscReturn from details to list, clear search, or leave diff mode
j / kMove list selection, choose diff files, select diff lines, or scroll details
n / p in ghr, Sections, or ListMirror next/previous movement for focus or list selection; p at the first list item returns to Sections
[ / ] in ListLoad previous/next GitHub result page
PgDown / PgUp or d / uPage current list/details movement
n / p in DetailsFocus next/previous check or comment in conversation details, or comments in diff details; p moves back toward PR/issue details
h / l in diff DetailsPage down/up through the file diff; at file edges, jump to the next/previous file
g / GJump to top/bottom in list, details, or diff; in conversation details, top clears comment focus and bottom focuses the last comment
[ / ] in diff modeSwitch diff files
/In PR/issue lists, open the repo search dialog; in other lists, fuzzy filter the loaded list
fFilter the current PR/issue/inbox section with qualifiers such as state:closed label:bug author:alice, unread reason:mention, or done; empty input or clear resets
SSearch matching PRs and issues; global PR/issue lists include a Repo field, repo tabs use remembered per-repo fields, and Inbox searches by state, reason, and repo; use Tab to switch fields, ↑/↓ to move candidates, Enter to choose or search, Ctrl+S to save reusable PR/issue conditions, and Ctrl+U to clear conditions
iIgnore the selected PR or issue and hide it from future lists
x / Delete in InboxMark the selected GitHub inbox notification done
vOpen PR diff mode
VSelect a contiguous commit range or all PR changes
q in diff modeReturn to the state before opening diff
oOpen the selected item in the browser; in diff mode, open the PR changes page; in Details, open the focused check URL when one is selected
aAdd a normal issue or PR comment
LAdd a label to the selected issue or PR; type a prefix and choose from repo labels
NIn a PR list, create a PR from the repo local_dir current branch; in an issue list, create an issue
+Add a reaction to the selected issue, PR, or focused comment
@ / -Assign or unassign assignees on the selected issue or PR
c in DetailsAdd a normal comment in conversation mode, or an inline review comment in diff mode
RReply to the focused comment
eEdit the focused comment in Details, edit the selected issue or PR when no comment is focused, or end a review range in diff mode
zResolve or unresolve the focused inline review thread
TEdit the selected issue or PR title, assignees, labels, and body
mToggle terminal text selection mode; in diff details, begin a review range
MOpen a merge confirmation for the selected PR, defaulting to merge commits
COpen a close or reopen confirmation for the selected issue or PR
XOpen a local PR checkout confirmation using ordinary git commands
FRerun failed checks for the selected PR
UOpen an update-branch confirmation for the selected PR
m / s / r in merge confirmationChoose merge, squash, or rebase before confirming
Tab in merge confirmationCycle merge method
sSubmit a PR review summary as comment, request changes, or approve
AApprove through the PR review summary flow
Ctrl+DDiscard a pending PR review created in this session
EOpen an enable auto-merge confirmation for the selected PR
OOpen a disable auto-merge confirmation for the selected PR
DToggle the selected open PR between draft and ready for review
PRequest or re-request PR reviewers with comma-separated logins
YRemove pending PR review requests with comma-separated logins
tChange or clear the selected issue/PR milestone
y / EnterConfirm the current action in the confirmation dialog
Enter in Reviewer ActionSubmit the reviewer login list
Ctrl+Enter / Ctrl+OSend a comment or save the active issue/PR editor dialog
Ctrl+S / Cmd+S in editor dialogsSave the current comment, issue, or pull request draft
@ in editor dialogsSearch GitHub accounts for mention completion; Up/Down choose and Tab/Enter insert
Ctrl+Enter / Ctrl+O in issue dialogCreate the issue
← / → / ↑ / ↓ in editor dialogsMove the cursor by character or rendered line
Home / End in editor dialogsJump to the start or end of the current line
Ctrl+W / Alt+Backspace in editor dialogsDelete the previous word
Alt+B / Alt+F / Alt+D in editor dialogsJump previous/next word, or delete the next word
Ctrl+U / Ctrl+K in editor dialogsDelete to the start or end of the current line
Ctrl+X in editor dialogsDelete the current line
Ctrl+Z / Cmd+Z in editor dialogsUndo text edits
Ctrl+R / Cmd+Shift+Z in editor dialogsRedo text edits
rRefresh the active tab first, then run a full background refresh
q / Ctrl+CSave UI state and quit

Commands

Open the command palette with : to fuzzy search and run commands. Recently run commands appear first before you type; once you enter a query, the closest matches appear first. Every current top-menu item is also generated as a direct command, including projects added at runtime, so typing Inb or a project name switches to that tab without opening another picker.

CommandAction
Project SwitchFilter configured repos by prefix and activate a project tab
Project AddAdd a repo project to the menu and save it to config.toml
Project RemoveSelect a configured repo project, confirm, and remove it from config.toml
Recent ItemsFuzzy search recently viewed PRs/issues, including linked inbox notifications, and jump back to the selected item
Saved Search FilterPick a named saved PR/issue search filter from config.toml and run it
Set Color ThemeChoose auto or a fixed color theme and save it to config.toml
Top Menu SwitchSwitch Inbox, PR, issue, search, or repo tabs, then focus the list after a short delay
Copy GitHub LinkCopy the selected comment link, or the current PR/issue link, to the clipboard
Copy PR/Issue LinkCopy the current PR/issue link to the clipboard, ignoring selected comments
Copy ContentCopy the selected comment content, or the current PR/issue description, to the clipboard
Open Linked PR/IssueOpen the first linked pull request or issue from the current item
Clear CacheChoose a local cache layer to clear: current section, current view, all list snapshots, suggestions, loaded details/diffs, or all cache
Mark DoneMove the selected GitHub inbox notification out of inbox lists; future activity can still notify unless the thread is muted
Mark All ReadMark every GitHub inbox notification as read
Mute ThreadIgnore future notifications for the selected inbox thread
Subscribe Thread / Unsubscribe ThreadChange the selected inbox thread subscription
Subscribe Item / Unsubscribe ItemChange the selected issue or pull request conversation subscription
InfoShow terminal, version, config/db/log paths, cache counts, runtime state, and ghr system diagnostics in a scrollable popup
LogShow recent direct API and gh api requests with timestamps, status, response sizes, errors, and rate-limit events; use j/k to select and Enter to open details
Rate LimitQuery and show current GitHub core, search, and GraphQL quotas together with local queue and cooldown state

Commit diffs:

  • Press V, click the commits count, or click a commit in the conversation to open its diff.
  • The picker lists commits oldest first with SHA, title, author, and date. Use Space or click to toggle checkboxes, then Enter (or click Enter apply) to apply; Esc cancels and r reloads.
  • Selecting outside the checked range fills the gap. Unchecking the first commit keeps the remaining range; unchecking a middle or last commit keeps only the earlier part. Unchecking the only selected commit clears the selection. Checking every commit applies All commits. To return directly to the full PR diff, focus All commits above the divider and press Enter, or click it; no Space is needed.
  • The Details title shows All commits, a single SHA with title and (N/M), or a SHA range with (N–K/M). Each selection remembers its file and scroll position.
  • Commit selections use the PR's comparison base, including upstream changes merged into the branch. Across merges, ghr builds the same virtual base as the web review: merge the upstream snapshot into the selection's starting snapshot, keeping the starting side on conflicts, then compare against the last selected commit.
  • These comparisons require Git 2.46 or newer. Git snapshots are fetched into ~/.ghr/git-diffs/ and reused; credentials follow the selected GitHub backend. Comparison failures remain visible and can be retried with r.
  • Inline comments (c, including selected line ranges) target the last selected commit; drafts are kept separate for each commit selection. a posts a general PR comment. Comments on older commits may become outdated as the PR changes.

Diff review ranges:

  • Press m on a diff line to begin a range, move the highlight, then press e to end it.
  • Press c after ending a range to post an inline review comment for the selected range.
  • With the mouse, single click selects one diff line. Double click begins a range, then single click the end line to complete it.
  • Press s to open the review summary editor, use Tab or 1 / 2 / 3 to choose comment, request changes, or approve, then press Ctrl+Enter or Ctrl+O to submit.
  • Press Ctrl+P in the review summary editor to create a pending review draft, then press s later to submit it or D to discard it.

Local PR checkout:

  • Press X on a pull request in the list or Details pane, then confirm with y or Enter.
  • Pull request Details show the remote branch as a clickable link when GitHub provides it.
  • ghr fetches refs/pull/<number>/head from the matching Git remote and checks out pr/<number>; GitHub CLI is not required for checkout.
  • An existing pr/<number> branch is only fast-forwarded. If it has diverged, ghr leaves it untouched and reports the conflict.
  • Checkout runs from the matching local repository directory. Set local_dir on a repo entry to make the target explicit:
[[repos]]
name = "Rust"
repo = "rust-lang/rust"
local_dir = "~/code/rust"
# Optional. Defaults to origin when omitted.
remote = "upstream"
show_prs = true
show_issues = true
  • If local_dir is not set, ghr tries the directory where it was launched when that directory has a GitHub remote for the pull request repository. If neither path matches, ghr shows a hint instead of running checkout.
  • Creating a pull request from local_dir runs a local preflight before pushing and calling the GitHub API. It blocks with a dialog when the title is empty, the checkout has moved branches, the worktree is dirty, the head has no commit, no matching GitHub push remote exists, or the branch has no commits ahead of the local base branch.

Mouse behavior:

  • Click ghr or Sections tabs to switch views or sections.
  • Click list rows to select them and focus Details. Mouse hover and mouse wheel do not change PR/issue selection.
  • Click descriptions, comments, links, and visible actions in Details to focus, open, or copy code/quote blocks.
  • Click inside comment, review, issue, PR, or item edit editor dialogs to place the edit cursor.
  • Drag text inside Details or editor body fields to copy that rendered selection to the clipboard without leaving mouse mode.
  • Scroll Details with the mouse wheel.
  • Drag the split between list and Details to resize panes; the ratio is saved.
  • Press m outside diff mode to temporarily disable TUI mouse capture for terminal text selection; press m again to restore mouse controls.

Default Sections

Inbox:

  • All
  • Review Requested
  • Assigned
  • Mentioned
  • Subscribed
  • Others

Pull Requests:

  • Needs Attention: open PRs where you were requested for review, assigned, or mentioned.
  • My Pull Requests: open PRs authored by you.
  • Reviewed: open PRs reviewed by you and authored by someone else.

Issues:

  • Assigned to Me
  • Mentioned
  • Involved

Configuration

The config file is created at:

~/.ghr/config.toml

Example:

[[repos]]
name = "Rust"
repo = "rust-lang/rust"
show_prs = true
show_issues = true
labels = ["T-compiler"]
pr_labels = ["S-waiting-on-review"]
issue_labels = ["E-easy"]

[defaults]
view = "pull_requests"
command_palette_key = ":"
editor_submit_key = "Ctrl+O"
theme = "auto"
log_level = "info"
pr_per_page = 50
issue_per_page = 50
notification_limit = 50
refetch_interval_seconds = 60
include_read_notifications = true

[[pr_sections]]
title = "Needs Attention"
queries = [
  "is:open review-requested:@me archived:false sort:created-desc",
  "is:open assignee:@me archived:false sort:created-desc",
  "is:open mentions:@me archived:false sort:created-desc",
]

[[pr_sections]]
title = "My Pull Requests"
filters = "is:open author:@me archived:false sort:created-desc"

[[pr_sections]]
title = "Reviewed"
filters = "is:open reviewed-by:@me -author:@me archived:false sort:created-desc"

[[saved_search_filters]]
name = "my rust prs"
repo = "rust-lang/rust"
kind = "pull_requests"
status = "open"
author = "chenyukang"
sort = "created_at"

exclude_repos = ["some-org/archive-*"]

Use filters for a single GitHub search query. Use queries when a section should merge several GitHub searches into one deduplicated list. Label filters can be written directly in either form, for example filters = "is:open label:bug archived:false sort:created-desc" or label:"good first issue" for labels with spaces.

Use [[repos]] to add repository tabs to the top bar. Each configured repo shows its name as a top-level tab; inside that tab, show_issues and show_prs control whether the sections are shown as Issues and Pull Requests. Repo tabs default to open issues and open PRs, with Issues shown first. Set labels to filter both repo issue and PR lists, or use issue_labels / pr_labels for kind-specific filters.

Use [[saved_search_filters]] for named PR/issue searches that should be editable in config.toml. From the search dialog, Ctrl+S prompts for a name and saves the current repo, PR/issue kind, and filter fields back to the active config file.

When ghr starts inside a Git checkout with a GitHub remote, it adds that repository as a repo tab if it is not already configured and saves it back to config.toml with local_dir set to the launch directory. If the checkout has more than one GitHub remote, ghr opens a startup modal so you can choose the remote, then stores non-origin choices as remote = "upstream" or whichever remote you selected. If the repo already exists in the config but has no local_dir, ghr fills that field without overwriting an existing value.

Set command_palette_key to change the command palette shortcut. Printable keys such as ":" are treated as text while typing in search, filter, and editor dialogs; use a modified key such as "Ctrl+L" if you want the palette to open from those text inputs. Set editor_submit_key to add a custom submit shortcut for editor dialogs; Ctrl+Enter and Ctrl+O are always accepted.

Set theme to "auto", "dark", or "light" to switch the base TUI palette. Set theme_name for a fixed named theme such as "catppuccin_mocha", "gruvbox_light", or "github_dark". auto follows the macOS system appearance and falls back to dark when the system theme cannot be detected; fixed themes do not auto-switch.

Set log_level to trace, debug, info, warn, or error. In debug mode, direct GitHub API and gh / gh api requests plus UI focus/view changes and mouse clicks are written to ~/.ghr/ghr.log. Failed API requests, failed gh executions, and non-zero gh results are logged at error level, so they are visible with the default info log level. The Log command also keeps an in-memory list of recent direct API and gh calls for the current session, including response errors and GitHub rate-limit failures. RUST_LOG still overrides this config value when it is set.

pr_per_page and issue_per_page control the page size used for PR and issue search sections. Use [ and ] in the list to load adjacent GitHub result pages.

Local Data

ghr keeps all local files in ~/.ghr:

  • config.toml: user configuration
  • ghr.db: SQLite snapshot cache
  • ghr.log: log file
  • state.toml: persisted UI state, including ignored PRs/issues

The snapshot cache is intentionally local and disposable. Use the Clear Cache command to clear one cache layer, or delete ~/.ghr/ghr.db if you want to rebuild every persisted cache row from GitHub.

Contributing

Contributions are very welcome! Please open an issue or a pull request with any bug fixes, improvements, or new features.

chenyukang/ghr

https://catcoding.me/ghr/ ghr is a fast terminal workspace for staying on top of GitHub. It brings pull requests, issues, notifications, repo tabs, conversations, checks, and diffs into one stateful TUI

Rust

95

339 commits

updated Oct 18, 2026

See the code

README

ghr

ghr is a fast terminal workspace for staying on top of GitHub. It brings your GitHub inbox, pull requests, issues, repo tabs, conversations, checks, and diffs into one stateful TUI, so you can triage, review, comment, approve, merge, and jump back in without waiting on a fresh GitHub fetch.

CI Release

Conversation and triage view

ghr conversation and triage screenshot

Pull request diff review view

ghr pull request diff review screenshot

Features

  • Inbox, pull request, and issue views.
  • Snapshot-first startup: cached data is shown immediately, the active view refreshes first, Inbox refreshes every 60 seconds while idle, and non-active PR/issue sections are kept warm by a quiet idle sweep.
  • Bounded read-request scheduling per GitHub backend, with limited foreground concurrency, serialized background work, foreground priority, resource-specific rate-limit cooldowns, and rate-limit-aware retries; write operations run immediately and are never retried automatically.
  • Configurable sections and repo tabs, including multi-query sections such as Needs Attention.
  • Automatic current-repo tab persistence when launched inside a Git checkout with a GitHub remote.
  • Paged PR and issue lists with configurable page size.
  • Persistent ignored PRs and issues, stored in UI state and hidden from all lists.
  • Recent Items command for jumping back to the last 200 PRs and issues, including linked inbox notifications, where you spent at least 5 seconds in Details.
  • Fuzzy filtering in every loaded list with /, quick PR/issue/inbox section filters with f, plus structured GitHub search with S.
  • Details pane with rendered Markdown, clickable links and image attachments, fenced code blocks with lightweight Rust and plain/log highlighting, descriptions, comments, review comments, PR commit activity, labels, milestones, action hints, and check summaries.
  • Inbox notifications lazily load linked PR or issue details when opened, so descriptions and recent PR commit activity appear without making the initial inbox fetch heavier.
  • PR diff mode with a changed-file list, per-file diff rendering, inline review comments, and review ranges.
  • Comment, reply, edit, resolve review threads, milestone, merge, close/reopen, update-branch, rerun-failed-checks, local PR checkout, draft / ready-for-review, and full PR review submit flows from inside the TUI.
  • Inbox read/done/mute handling with explicit commands, local cache updates, GitHub sync, and dimmed read items.
  • Mouse support for tabs, lists, links, descriptions, comments, editor cursor placement, details drag-copy, scrolling, text selection mode, and split resizing.
  • Built-in auto plus named light and dark color themes configured through defaults.theme / defaults.theme_name; auto follows the macOS appearance when available.
  • UI state persistence under ~/.ghr, including focus, selected item, scroll position, split ratio, and diff mode.
  • Local state under ~/.ghr: config, SQLite snapshot database, logs, and UI state.
  • Supports direct GitHub API access with a personal access token, or the GitHub CLI as a compatible fallback.

Authentication

Choose either authentication method:

  1. Set a personal access token (classic):
export GHR_GITHUB_TOKEN=ghp_...
ghr

For full access to private repositories, select the classic repo scope. For public repositories only, use public_repo together with notifications. The workflow scope is not required because ghr does not modify workflow files. GitHub's notification endpoints accept the notifications or repo scope, and linked private issues, pull requests, and commits require repo.

GH_TOKEN and GITHUB_TOKEN are also recognized. GHR_GITHUB_TOKEN takes precedence. Tokens are read from the environment and are never written to ~/.ghr/config.toml. Treat the token like a password and give it an expiration date.

Fine-grained PATs (github_pat_...) provide partial repository access, but are not recommended for the complete ghr experience. GitHub's Notifications API does not support fine-grained PATs, so Inbox loading and read/done/mute actions will fail. Fine-grained PATs are also limited to one resource owner, cannot access multiple organizations at once, may not support every Checks API operation, and can require organization approval or a shorter lifetime. See GitHub's documentation for notification authentication and fine-grained PAT limitations.

  1. Install GitHub CLI and authenticate it:
gh auth login

GitHub CLI is not required in PAT mode. Local checkout uses the matching repository remote with ordinary git commands.

Installation

You can install ghr with Homebrew on macOS or Linux through the project tap:

brew install chenyukang/tap/ghr-cli

You can also install ghr with Cargo:

cargo install ghr-cli

Or install the latest release binary on macOS or Linux:

curl -fsSL https://raw.githubusercontent.com/chenyukang/ghr/main/install.sh | sh

Install the latest release binary on Windows PowerShell:

irm https://raw.githubusercontent.com/chenyukang/ghr/main/install.ps1 | iex

Then set a token or authenticate GitHub CLI and run ghr:

# PAT mode, without GitHub CLI
export GHR_GITHUB_TOKEN=ghp_...
ghr

# Or GitHub CLI mode
gh auth login
ghr

## by default, ghr starts in the Inbox/Issues/Pull Requests view
## go to some dir with a GitHub remote and run ghr to see the repo tab show up
## command palette (press `:`) and then type "Project Add" to add new repos

The installers detect your OS and CPU architecture, download the matching GitHub release asset with visible progress, verify its .sha256, and install ghr into ~/.local/bin by default. Use GHR_INSTALL_DIR to choose another install directory, or GHR_VERSION to pin a release tag:

curl -fsSL https://raw.githubusercontent.com/chenyukang/ghr/main/install.sh | GHR_VERSION=v0.9.1 GHR_INSTALL_DIR=/usr/local/bin sh

Usage

Run ghr after setting a token or completing gh auth login. When started inside a Git checkout with a GitHub remote, ghr adds that repository as a local project tab automatically.

Keybindings

Press ? in the TUI for the live shortcut reference. The top-right status shows the current app state; the footer stays focused on the most useful shortcuts for the active area.

KeyAction
:Open the command palette; recent commands lead before typing, then fuzzy relevance wins
1 / 2 / 3 / 4Focus ghr / Sections / list / Details
TabSwitch list/details focus; when ghr or Sections is focused, move to the next tab
Shift+Tab in ListSwitch to the previous Section, then return focus to List after 200 ms
Shift+[ / Shift+] in ListSwitch to the left/right Section, then return focus to List after 200 ms
Shift+Tab elsewhereReturn from Details to List, or move backward within focused ghr/Sections tabs
h / l or [ / ]Move within the focused ghr or Sections tab group, wrapping at the ends
EnterFocus the details pane from the list
EscReturn from details to list, clear search, or leave diff mode
j / kMove list selection, choose diff files, select diff lines, or scroll details
n / p in ghr, Sections, or ListMirror next/previous movement for focus or list selection; p at the first list item returns to Sections
[ / ] in ListLoad previous/next GitHub result page
PgDown / PgUp or d / uPage current list/details movement
n / p in DetailsFocus next/previous check or comment in conversation details, or comments in diff details; p moves back toward PR/issue details
h / l in diff DetailsPage down/up through the file diff; at file edges, jump to the next/previous file
g / GJump to top/bottom in list, details, or diff; in conversation details, top clears comment focus and bottom focuses the last comment
[ / ] in diff modeSwitch diff files
/In PR/issue lists, open the repo search dialog; in other lists, fuzzy filter the loaded list
fFilter the current PR/issue/inbox section with qualifiers such as state:closed label:bug author:alice, unread reason:mention, or done; empty input or clear resets
SSearch matching PRs and issues; global PR/issue lists include a Repo field, repo tabs use remembered per-repo fields, and Inbox searches by state, reason, and repo; use Tab to switch fields, ↑/↓ to move candidates, Enter to choose or search, Ctrl+S to save reusable PR/issue conditions, and Ctrl+U to clear conditions
iIgnore the selected PR or issue and hide it from future lists
x / Delete in InboxMark the selected GitHub inbox notification done
vOpen PR diff mode
VSelect a contiguous commit range or all PR changes
q in diff modeReturn to the state before opening diff
oOpen the selected item in the browser; in diff mode, open the PR changes page; in Details, open the focused check URL when one is selected
aAdd a normal issue or PR comment
LAdd a label to the selected issue or PR; type a prefix and choose from repo labels
NIn a PR list, create a PR from the repo local_dir current branch; in an issue list, create an issue
+Add a reaction to the selected issue, PR, or focused comment
@ / -Assign or unassign assignees on the selected issue or PR
c in DetailsAdd a normal comment in conversation mode, or an inline review comment in diff mode
RReply to the focused comment
eEdit the focused comment in Details, edit the selected issue or PR when no comment is focused, or end a review range in diff mode
zResolve or unresolve the focused inline review thread
TEdit the selected issue or PR title, assignees, labels, and body
mToggle terminal text selection mode; in diff details, begin a review range
MOpen a merge confirmation for the selected PR, defaulting to merge commits
COpen a close or reopen confirmation for the selected issue or PR
XOpen a local PR checkout confirmation using ordinary git commands
FRerun failed checks for the selected PR
UOpen an update-branch confirmation for the selected PR
m / s / r in merge confirmationChoose merge, squash, or rebase before confirming
Tab in merge confirmationCycle merge method
sSubmit a PR review summary as comment, request changes, or approve
AApprove through the PR review summary flow
Ctrl+DDiscard a pending PR review created in this session
EOpen an enable auto-merge confirmation for the selected PR
OOpen a disable auto-merge confirmation for the selected PR
DToggle the selected open PR between draft and ready for review
PRequest or re-request PR reviewers with comma-separated logins
YRemove pending PR review requests with comma-separated logins
tChange or clear the selected issue/PR milestone
y / EnterConfirm the current action in the confirmation dialog
Enter in Reviewer ActionSubmit the reviewer login list
Ctrl+Enter / Ctrl+OSend a comment or save the active issue/PR editor dialog
Ctrl+S / Cmd+S in editor dialogsSave the current comment, issue, or pull request draft
@ in editor dialogsSearch GitHub accounts for mention completion; Up/Down choose and Tab/Enter insert
Ctrl+Enter / Ctrl+O in issue dialogCreate the issue
← / → / ↑ / ↓ in editor dialogsMove the cursor by character or rendered line
Home / End in editor dialogsJump to the start or end of the current line
Ctrl+W / Alt+Backspace in editor dialogsDelete the previous word
Alt+B / Alt+F / Alt+D in editor dialogsJump previous/next word, or delete the next word
Ctrl+U / Ctrl+K in editor dialogsDelete to the start or end of the current line
Ctrl+X in editor dialogsDelete the current line
Ctrl+Z / Cmd+Z in editor dialogsUndo text edits
Ctrl+R / Cmd+Shift+Z in editor dialogsRedo text edits
rRefresh the active tab first, then run a full background refresh
q / Ctrl+CSave UI state and quit

Commands

Open the command palette with : to fuzzy search and run commands. Recently run commands appear first before you type; once you enter a query, the closest matches appear first. Every current top-menu item is also generated as a direct command, including projects added at runtime, so typing Inb or a project name switches to that tab without opening another picker.

CommandAction
Project SwitchFilter configured repos by prefix and activate a project tab
Project AddAdd a repo project to the menu and save it to config.toml
Project RemoveSelect a configured repo project, confirm, and remove it from config.toml
Recent ItemsFuzzy search recently viewed PRs/issues, including linked inbox notifications, and jump back to the selected item
Saved Search FilterPick a named saved PR/issue search filter from config.toml and run it
Set Color ThemeChoose auto or a fixed color theme and save it to config.toml
Top Menu SwitchSwitch Inbox, PR, issue, search, or repo tabs, then focus the list after a short delay
Copy GitHub LinkCopy the selected comment link, or the current PR/issue link, to the clipboard
Copy PR/Issue LinkCopy the current PR/issue link to the clipboard, ignoring selected comments
Copy ContentCopy the selected comment content, or the current PR/issue description, to the clipboard
Open Linked PR/IssueOpen the first linked pull request or issue from the current item
Clear CacheChoose a local cache layer to clear: current section, current view, all list snapshots, suggestions, loaded details/diffs, or all cache
Mark DoneMove the selected GitHub inbox notification out of inbox lists; future activity can still notify unless the thread is muted
Mark All ReadMark every GitHub inbox notification as read
Mute ThreadIgnore future notifications for the selected inbox thread
Subscribe Thread / Unsubscribe ThreadChange the selected inbox thread subscription
Subscribe Item / Unsubscribe ItemChange the selected issue or pull request conversation subscription
InfoShow terminal, version, config/db/log paths, cache counts, runtime state, and ghr system diagnostics in a scrollable popup
LogShow recent direct API and gh api requests with timestamps, status, response sizes, errors, and rate-limit events; use j/k to select and Enter to open details
Rate LimitQuery and show current GitHub core, search, and GraphQL quotas together with local queue and cooldown state

Commit diffs:

  • Press V, click the commits count, or click a commit in the conversation to open its diff.
  • The picker lists commits oldest first with SHA, title, author, and date. Use Space or click to toggle checkboxes, then Enter (or click Enter apply) to apply; Esc cancels and r reloads.
  • Selecting outside the checked range fills the gap. Unchecking the first commit keeps the remaining range; unchecking a middle or last commit keeps only the earlier part. Unchecking the only selected commit clears the selection. Checking every commit applies All commits. To return directly to the full PR diff, focus All commits above the divider and press Enter, or click it; no Space is needed.
  • The Details title shows All commits, a single SHA with title and (N/M), or a SHA range with (N–K/M). Each selection remembers its file and scroll position.
  • Commit selections use the PR's comparison base, including upstream changes merged into the branch. Across merges, ghr builds the same virtual base as the web review: merge the upstream snapshot into the selection's starting snapshot, keeping the starting side on conflicts, then compare against the last selected commit.
  • These comparisons require Git 2.46 or newer. Git snapshots are fetched into ~/.ghr/git-diffs/ and reused; credentials follow the selected GitHub backend. Comparison failures remain visible and can be retried with r.
  • Inline comments (c, including selected line ranges) target the last selected commit; drafts are kept separate for each commit selection. a posts a general PR comment. Comments on older commits may become outdated as the PR changes.

Diff review ranges:

  • Press m on a diff line to begin a range, move the highlight, then press e to end it.
  • Press c after ending a range to post an inline review comment for the selected range.
  • With the mouse, single click selects one diff line. Double click begins a range, then single click the end line to complete it.
  • Press s to open the review summary editor, use Tab or 1 / 2 / 3 to choose comment, request changes, or approve, then press Ctrl+Enter or Ctrl+O to submit.
  • Press Ctrl+P in the review summary editor to create a pending review draft, then press s later to submit it or D to discard it.

Local PR checkout:

  • Press X on a pull request in the list or Details pane, then confirm with y or Enter.
  • Pull request Details show the remote branch as a clickable link when GitHub provides it.
  • ghr fetches refs/pull/<number>/head from the matching Git remote and checks out pr/<number>; GitHub CLI is not required for checkout.
  • An existing pr/<number> branch is only fast-forwarded. If it has diverged, ghr leaves it untouched and reports the conflict.
  • Checkout runs from the matching local repository directory. Set local_dir on a repo entry to make the target explicit:
[[repos]]
name = "Rust"
repo = "rust-lang/rust"
local_dir = "~/code/rust"
# Optional. Defaults to origin when omitted.
remote = "upstream"
show_prs = true
show_issues = true
  • If local_dir is not set, ghr tries the directory where it was launched when that directory has a GitHub remote for the pull request repository. If neither path matches, ghr shows a hint instead of running checkout.
  • Creating a pull request from local_dir runs a local preflight before pushing and calling the GitHub API. It blocks with a dialog when the title is empty, the checkout has moved branches, the worktree is dirty, the head has no commit, no matching GitHub push remote exists, or the branch has no commits ahead of the local base branch.

Mouse behavior:

  • Click ghr or Sections tabs to switch views or sections.
  • Click list rows to select them and focus Details. Mouse hover and mouse wheel do not change PR/issue selection.
  • Click descriptions, comments, links, and visible actions in Details to focus, open, or copy code/quote blocks.
  • Click inside comment, review, issue, PR, or item edit editor dialogs to place the edit cursor.
  • Drag text inside Details or editor body fields to copy that rendered selection to the clipboard without leaving mouse mode.
  • Scroll Details with the mouse wheel.
  • Drag the split between list and Details to resize panes; the ratio is saved.
  • Press m outside diff mode to temporarily disable TUI mouse capture for terminal text selection; press m again to restore mouse controls.

Default Sections

Inbox:

  • All
  • Review Requested
  • Assigned
  • Mentioned
  • Subscribed
  • Others

Pull Requests:

  • Needs Attention: open PRs where you were requested for review, assigned, or mentioned.
  • My Pull Requests: open PRs authored by you.
  • Reviewed: open PRs reviewed by you and authored by someone else.

Issues:

  • Assigned to Me
  • Mentioned
  • Involved

Configuration

The config file is created at:

~/.ghr/config.toml

Example:

[[repos]]
name = "Rust"
repo = "rust-lang/rust"
show_prs = true
show_issues = true
labels = ["T-compiler"]
pr_labels = ["S-waiting-on-review"]
issue_labels = ["E-easy"]

[defaults]
view = "pull_requests"
command_palette_key = ":"
editor_submit_key = "Ctrl+O"
theme = "auto"
log_level = "info"
pr_per_page = 50
issue_per_page = 50
notification_limit = 50
refetch_interval_seconds = 60
include_read_notifications = true

[[pr_sections]]
title = "Needs Attention"
queries = [
  "is:open review-requested:@me archived:false sort:created-desc",
  "is:open assignee:@me archived:false sort:created-desc",
  "is:open mentions:@me archived:false sort:created-desc",
]

[[pr_sections]]
title = "My Pull Requests"
filters = "is:open author:@me archived:false sort:created-desc"

[[pr_sections]]
title = "Reviewed"
filters = "is:open reviewed-by:@me -author:@me archived:false sort:created-desc"

[[saved_search_filters]]
name = "my rust prs"
repo = "rust-lang/rust"
kind = "pull_requests"
status = "open"
author = "chenyukang"
sort = "created_at"

exclude_repos = ["some-org/archive-*"]

Use filters for a single GitHub search query. Use queries when a section should merge several GitHub searches into one deduplicated list. Label filters can be written directly in either form, for example filters = "is:open label:bug archived:false sort:created-desc" or label:"good first issue" for labels with spaces.

Use [[repos]] to add repository tabs to the top bar. Each configured repo shows its name as a top-level tab; inside that tab, show_issues and show_prs control whether the sections are shown as Issues and Pull Requests. Repo tabs default to open issues and open PRs, with Issues shown first. Set labels to filter both repo issue and PR lists, or use issue_labels / pr_labels for kind-specific filters.

Use [[saved_search_filters]] for named PR/issue searches that should be editable in config.toml. From the search dialog, Ctrl+S prompts for a name and saves the current repo, PR/issue kind, and filter fields back to the active config file.

When ghr starts inside a Git checkout with a GitHub remote, it adds that repository as a repo tab if it is not already configured and saves it back to config.toml with local_dir set to the launch directory. If the checkout has more than one GitHub remote, ghr opens a startup modal so you can choose the remote, then stores non-origin choices as remote = "upstream" or whichever remote you selected. If the repo already exists in the config but has no local_dir, ghr fills that field without overwriting an existing value.

Set command_palette_key to change the command palette shortcut. Printable keys such as ":" are treated as text while typing in search, filter, and editor dialogs; use a modified key such as "Ctrl+L" if you want the palette to open from those text inputs. Set editor_submit_key to add a custom submit shortcut for editor dialogs; Ctrl+Enter and Ctrl+O are always accepted.

Set theme to "auto", "dark", or "light" to switch the base TUI palette. Set theme_name for a fixed named theme such as "catppuccin_mocha", "gruvbox_light", or "github_dark". auto follows the macOS system appearance and falls back to dark when the system theme cannot be detected; fixed themes do not auto-switch.

Set log_level to trace, debug, info, warn, or error. In debug mode, direct GitHub API and gh / gh api requests plus UI focus/view changes and mouse clicks are written to ~/.ghr/ghr.log. Failed API requests, failed gh executions, and non-zero gh results are logged at error level, so they are visible with the default info log level. The Log command also keeps an in-memory list of recent direct API and gh calls for the current session, including response errors and GitHub rate-limit failures. RUST_LOG still overrides this config value when it is set.

pr_per_page and issue_per_page control the page size used for PR and issue search sections. Use [ and ] in the list to load adjacent GitHub result pages.

Local Data

ghr keeps all local files in ~/.ghr:

  • config.toml: user configuration
  • ghr.db: SQLite snapshot cache
  • ghr.log: log file
  • state.toml: persisted UI state, including ignored PRs/issues

The snapshot cache is intentionally local and disposable. Use the Clear Cache command to clear one cache layer, or delete ~/.ghr/ghr.db if you want to rebuild every persisted cache row from GitHub.

Contributing

Contributions are very welcome! Please open an issue or a pull request with any bug fixes, improvements, or new features.

Significant stargazers

raf

912 followers · starred May 2026

Charlie Robbins

2,452 followers · starred May 2026

Asuka Minato

628 followers · starred Sep 2026

许杰友 Jieyou Xu (Joe)

280 followers · starred Jul 2026