The cleanest way to navigate a stacked-diff workflow isn’t with typed commands — it’s with a TUI. gt tui opens an interactive terminal interface to your stacks: branches on the left, PR status on the right, vim keys to navigate, single letters to act. Once you’ve used it for an afternoon, typed commands start to feel like the long way round.
This article is a guided tour.
Open it
In any repo with gt repo init already done:
gt tui
You’ll see something like this:
┌─ STACK ────────────────────────┐ ┌─ PR / MR ─────────────────────────┐
│ ● main │ │ feature/auth-base │
│ ├─ ● feature/auth-base │ │ PR #41 · open · 2 approvals │
│ │ ├─ ● feature/auth-oauth │ │ Required: lint ✓ test ✓ deploy ⏳│
│ │ │ └─ ◉ feature/auth-2fa │ │ │
│ │ └─ ○ feature/auth-recovery │ │ Recent activity │
│ │ │ │ · @alice approved 2h ago │
│ ├─ ● feature/db-migration │ │ · @bob commented 5h ago │
│ └─ ● feature/router-cleanup │ │ · github-actions deploy started │
│ │ │ │
└────────────────────────────────┘ └────────────────────────────────────┘
[ status: clean · 3 stacks · 9 branches · branch: feature/auth-2fa ]
That’s the core layout. Stacks on the left (a tree, with the current branch marked ◉). On the right, details about whatever branch the cursor is on: PR status, required checks, recent activity, reviewer state.
The status line at the bottom shows your overall state (working tree clean, the current branch, total counts).
Navigation
The whole TUI is keyboard-driven; the mouse works too but most people land on the keys.
| Key | Action |
|---|---|
j / k | Move down / up |
h / l | Collapse / expand a stack node |
g / G | Jump to top / bottom of the tree |
Tab | Move focus between left and right panes |
/ | Filter by branch name (fuzzy match) |
? | Open the keybindings cheat sheet |
q | Quit |
The vim keys are the muscle-memory default; arrow keys also work.
Acting on branches
Pressing letters performs actions on the current branch:
| Key | Action |
|---|---|
c | Create a new branch on top of the current one |
s | Submit (or update) the PR for this branch |
S | Submit the entire stack |
r | Restack on top of the parent’s latest |
R | Restack the whole stack |
m | Modify (amend) the current branch’s tip |
n | Sync with origin (fetch + restack + prune merged) |
d | Delete a branch (with confirmation if it has unmerged work) |
L | Land — merge this branch’s PR |
Enter | Open the branch’s PR in your browser |
Each action runs inside a non-blocking task with a progress bar. You can keep navigating while a long-running submit happens in the background.
Inspecting diffs
Pressing D opens an inline diff viewer for the current branch (diff against its parent):
┌─ DIFF: feature/auth-base ↔ main ──────────────────────────────────────┐
│ src/auth/schema.sql │
│ + CREATE TABLE auth_session ( │
│ + id UUID PRIMARY KEY, │
│ + user_id UUID REFERENCES users(id), │
│ + ... │
│ src/auth/middleware.rs │
│ + pub async fn auth_middleware(req: Request) -> Result<Response> { │
│ ... │
└────────────────────────────────────────────────────────────────────────┘
The diff viewer supports syntax highlighting via Tree-sitter, hunk-by-hunk navigation, and word-level diff (toggle with w). It’s not meant to replace your editor — but for “is this branch what I expect it to be?” it’s faster than opening the PR in a browser.
Esc returns to the stack view.
Conflict resolution
When gt_restack (R from the TUI) hits a conflict, the TUI drops you into a conflict-resolution mode:
┌─ CONFLICT ────────────────────────────────────────────────────────────┐
│ feature/auth-oauth · 1 file with conflicts │
│ │
│ ▸ src/auth/middleware.rs │
│ │
│ Press e to open in $EDITOR, n to skip this file, │
│ a to accept ours, b to accept theirs │
│ │
│ When done: c to continue · q to abort │
└────────────────────────────────────────────────────────────────────────┘
In practice you press e, your editor opens the file, you resolve, save, close — and the TUI detects the resolution and offers c (continue). For simple conflicts (whitespace, renames, formatting), a and b cover most cases.
This is much friendlier than the git mergetool workflow.
Search and filter
For repos with many stacks, / is your friend. Type a few characters and the tree filters live:
/auth
↳ ● feature/auth-base
├─ ● feature/auth-oauth
│ └─ ◉ feature/auth-2fa
└─ ○ feature/auth-recovery
Esc clears the filter; Enter jumps to the selected branch and exits filter mode.
Multi-repo mode
If you keep multiple repos in ~/code/, you can launch the TUI in multi-repo mode:
gt tui ~/code/*
A repo picker appears at the top; r cycles between repos. This is convenient for “I have stacks in three services, show me the current state.”
Persisted state
The TUI remembers its state between launches: the last branch you were on, expanded/collapsed nodes, the focused pane. It uses STKD_TUI_STATE_PATH (default ~/.local/state/stkd/tui.json).
Delete the file to reset.
Customising
A few common tweaks. All go in ~/.config/stkd/config.toml:
[tui]
# Show PR check details inline on the tree
show_check_status = true
# Open editor on conflict instead of dropping into resolution mode
conflict_strategy = "editor" # "editor" | "interactive"
# Refresh provider state on this interval (seconds)
refresh_interval = 30
[tui.keys]
# Override defaults
submit_stack = "S" # default
delete_branch = "d" # default
[tui.colors]
# Theme — accepts "auto", "light", "dark", or a path to a custom .toml
theme = "auto"
Custom themes are a small TOML mapping ANSI color names to CSS-style hex; see gt tui --print-default-theme for a starting point.
Why this matters
The point of the TUI isn’t to replace the CLI — typed commands compose better in scripts, in MCP, and in muscle memory once you have it. The point is that there’s a smooth on-ramp for new users and a fast browser for experienced ones.
Specifically:
- New users get a visible tree of branches and PRs from the first second. They don’t need to memorise
gt logflags. - Experienced users save half a dozen keystrokes per action.
S(submit stack) is faster than typinggt submit --stack. - Code reviewers can
gt tuiin someone else’s repo to see the structure of a stack before reading the diff. - AI agents can describe what they’re about to do, and a human reviewer can confirm the state of the world by looking at the TUI rather than running a series of
gitcommands.
What’s coming
A few features in flight:
- Inline PR comment threads — read and reply to PR comments without leaving the TUI.
- CI log tailing — when a check fails, peek the relevant log in a pane.
- Multi-author stacks — visualise which branches are owned by whom.
Track the GitHub project board for ETAs.
Try it
brew install neul-labs/tap/stkd
cd ~/code/your-repo
gt repo init
gt tui
The whole cheat sheet fits on one screen (?). Spend a few minutes navigating — it sticks fast.