Skip to content

TUI Navigation

Griffen Fargo edited this page May 15, 2026 · 7 revisions

TUI Navigation

Coco's interactive TUI is keyboard-driven and chord-based. Whether you launch it as coco ui or coco log -i, every git surface — history, working tree, diffs, commit compose, branches, tags, stash — is reachable from any other surface through a unified navigation model.

This page is the source of truth for that model. The companion pages Coco UI and Interactive Log TUI cover surface-specific actions and command-line flags; everything navigation-related lives here.

Mental model

  • Views are top-level destinations. There are fifteen: history, status, diff, compose, branches, tags, stash, worktrees, pull-request, pull-request-triage, issues, conflicts, reflog, bisect, and changelog.
  • Chords jump you between views. They start with g, followed by a single key (g h, g s, g d, g c, g b, g t, g z, g w, g p, g P, g i, g x, g r, g B).
  • The navigation stack remembers where you came from. Pressing < or Esc pops back. Going history → diff → compose → back returns to diff, then back again returns to history.
  • Selection state survives navigation. The selected commit, selected branch, selected stash, and current compose draft are all preserved when you jump away and come back.
  • The chrome adapts. A -separated breadcrumb in the header reflects the navigation stack; the footer's right-side global slot stays the same across views; help and palette read the active view to show the right scope.

Views and chords

View Chord What it shows
History g h Commit graph/list with refs and metadata. gh also clears the navigation stack.
Status g s Working-tree files (staged/unstaged/untracked) with stage/unstage/revert.
Diff g d Hunks of the currently-selected commit (from history) or worktree file (from status).
Compose g c Full-screen commit draft editor with summary/body cursors, AI draft, hook feedback.
Branches g b Local branches with divergence info; checkout/delete/create-PR via workflow keys.
Tags g t Tag list.
Stash g z Stash list; apply/drop via workflow keys. (g s is reserved for status, hence g z.)
Worktrees g w Linked worktrees with current/dirty markers; remove via W.
Pull request g p Dedicated PR action panel for the current branch (header, checks, reviews, body) with m merge / x close / a approve / R request changes / c comment / O open in browser.
PR triage g P Multi-PR triage list with filter cycling and per-row actions. Capital P disambiguates from g p (single, current-branch panel). See Issue & PR Triage.
Issues g i Issue triage list with filter cycling and per-row actions: comment, label, assign, close, reopen. See Issue & PR Triage.
Conflicts g x Conflict resolution helper view, available during merge / rebase / cherry-pick / revert. Per-row keys s stage / u theirs / U ours / o edit / C continue.
Reflog g r Chronological recovery log — every HEAD movement (commit / checkout / merge / reset / etc.) with relative time, action, hash, and message. Enter drills into the diff for the entry's hash.
Bisect g B Bisect workflow surface (#784). Capital B disambiguates from g b (branches). Shows the current candidate, the parsed decision log, and the four action keys: g good / b bad / s skip / x reset.
Changelog L Full-screen AI-generated changelog for the current branch (#914). Reached via L from history or branches rather than a g-prefixed chord. Per-branch cache; r regenerates, y yanks, E opens in $EDITOR, c kicks off create-PR seeded with the content.

g g is a separate chord that jumps to the first commit in the active history list — it pre-dates the view chords. g H (uppercase) on a diff view applies the cursored hunk to the index (companion to bare H which applies to the worktree). g T (uppercase) on the history view opens a new-tag prompt rooted at the cursored commit.

One-keystroke workflows (not view-jumps)

A few uppercase keys kick off workflows that span multiple views. These aren't chords; press them once and the workflow takes over.

Key Where Action
C history / branches Create a pull request for the current branch. Seeds the title + body from a generated changelog and opens a multi-line prompt for review.
L history / branches Generate a changelog for the current branch in a full-screen surface. Per-branch cache; r regenerates, y yanks to clipboard, E opens in $EDITOR, c kicks off create-PR seeded with this content.
S compose Split the staged set into multiple commits. Opens an overlay with the LLM-generated plan. y apply / r regenerate / < cancel.
E compose / status / diff Open the current commit draft in $EDITOR. Round-trips through a temp file; on save the content is re-split into summary + body. Companion to lowercase e (inline edit).
I compose / status / diff Generate an AI commit draft from the staged set.
B history (on a commit) Create a branch rooted at the cursored commit (git switch -c).
+ branches view / sidebar branches tab Create a branch from HEAD (git switch -c).

Going back

Key Action
< Pop the navigation stack
Esc Same as < when in a normal view; also closes filter/help/palette/confirmation modes

The stack always has at least one frame (the root view), so pressing < from the root is a no-op rather than an exit. Use q or Ctrl+C to quit.

Contextual transitions

Some keys perform navigation based on what's selected:

Trigger Effect
Enter on a commit (history view) Push diff scoped to that commit. The diff view inherits the selection so < returns to the same row.
Enter on a file (status view) Push diff scoped to that file. < returns to status.
Enter on a reflog row Push diff scoped to that entry's hash (#781).
e from status or diff Push compose and start editing. From inside compose, e toggles edit mode without re-pushing.
c from status or diff Push compose and run createManualCommit — the result (success or hook output) lands in compose so you can see it.

Cross-view workflows

Some flows span multiple views — you mark a state on one view and then act on it from a different one. The footer hints adapt to the flow state so the override is always discoverable.

Compare two refs (#779)

Diff any two refs (branches, tags, or commits) without leaving the workstation:

Step Trigger Effect
1 m on a row in branches / tags / history Mark the cursored ref as the compare base. Status banner sticks: "Compare base: <label> — press enter on another ref to diff."
2 m on the same ref again Toggle the base off (no Enter needed).
3 Navigate to a second ref on any of branches / tags / history (no key required — just move)
4 Enter on that second ref Push the diff view in compare mode, showing git diff <base>..<head>.
5 < / Esc Pop the diff. The compare base clears automatically when the diff is popped.

The compare diff is read-only — no per-file cherry-pick or hunk-apply across arbitrary refs (those don't have a sensible mutate-from-here flow). Just scroll with j/k, toggle split mode with d, and back out with <.

While a base is set, the footer adapts on every compare-flow target view:

Branches:  ↑/↓ branches · enter compare · m clear · esc back
Tags:      ↑/↓ tags     · enter compare · m clear · esc back
History:   ↑/↓ move     · enter compare · m clear · esc back

Outside the compare flow, m is unbound on those views except the dedicated PR view (where it triggers merge).

Bisect (#784)

Bisect support pairs the g B view with a top-bar BISECTING badge so you can't lose the workflow. The TUI picks up an active bisect on its next refresh — start it from your shell with git bisect start <bad-ref> <good-ref> and re-open coco ui.

Trigger Effect
g B Push the bisect view. Shows current candidate (HEAD), parsed decision log, and the action keys. The view is reachable even when bisect is inactive — the empty-state hint tells you how to start one.
g (on the bisect view) Mark the current candidate as good (bug not yet present). Advances to the next candidate.
b (on the bisect view) Mark the current candidate as bad (bug present). Advances to the next candidate.
s (on the bisect view) Skip the current candidate (e.g. it doesn't build). Advances to the next candidate.
x (on the bisect view) Reset the bisect — discards in-progress state. Routed through the y-confirm path.

Inside the bisect view, g and b bypass the chord prefix — pressing g marks good rather than entering chord mode. The path back out is < / Esc (never a chord). Outside the view, g/b/s/x keep their existing semantics.

The status line surfaces git's own "Bisecting: N revisions left to test after this (roughly K steps)" line after each decision so you always know how far you have to go.

Command palette (:)

The palette is an interactive launcher, not a static reference. Press : to open it; type to filter, press Enter to run.

Key Action
Printable keys Append to the fuzzy filter
Backspace / Delete Remove the last filter character
Ctrl+U Clear the filter
/ , Ctrl+P / Ctrl+N Move the selection cursor (clamped to filtered count)
Enter Run the selected command (records as recent, then closes)
Esc Close without running

The palette enumerates every keybinding plus every workflow action (commit, delete-branch, ai-commit-summary, etc.). Recently-used items float to the top when the filter is empty; once a query is set, relevance ranking takes over and recent ordering is ignored.

Behind the scenes, palette execution maps each command id to the same events the keystroke would dispatch — palette and keymap stay in sync.

Search (/)

/ opens filter mode in the active view:

  • History: ranked fuzzy matching across hash, date, author, message, and refs.
  • Branches: substring match on branch names and upstreams.
  • Tags: substring match on tag names and subjects.
  • Stash: substring match on stash refs and messages.

While filtering, the active view's header shows N/M totals plus the filter text (5/12 local | filter: feat). Ctrl+U clears, Esc or Enter exits filter mode.

In other views (diff, compose, status), / opens filter mode but the surface doesn't currently apply it — typing closes the filter without effect. That's a polish opportunity for a follow-up; track it via the wiki/issue tracker.

Help overlay (?)

Help is grouped into two sections so the right scope is always obvious:

  • Global — bindings that work from any view or focus (?, :, q, r, focus nav, workflow actions, the navigation chords).
  • This view (<active>) — bindings filtered to what makes sense in the current view + focus, with the active view named in the section title so you always know which scope applies.

Esc or ? closes the overlay.

Footer

The footer has two slots that don't overlap:

  • Contextual (left, dimmed) — what changes by mode/view/focus, like ↑/↓ files · enter diff · space stage · z revert · e/c compose in status.
  • Global (right edge, dimmed) — persistent affordances anchored to the right: g jump · < back · ? help · : cmds · q quit.

In special modes (filter / help open / palette open), the global slot trims down (q quit always present) since : and ? mean close in those contexts.

A few keys are context-routed across surfaces:

  • [/] — diff view: jump previous/next hunk or file. Sidebar focused: cycle sidebar tabs. Inspector focused (on short terminals where the inspector is tabbed): cycle inspector tabs. Each context owns its meaning of the key; the footer hints surface which one applies.
  • ←/→ — sidebar focused: switch between Status / Branches / Tags / Stashes / Worktrees tabs. Vertical axis (↑/↓) navigates items within the active tab.

Header breadcrumb

The header shows where you are in the navigation stack as a -separated trail:

Stack Breadcrumb
[history] (empty — no breadcrumb shown at root)
[history, diff] history › diff
[status, diff] status › diff
[history, status, diff] history › status › diff

The breadcrumb is purely informational — there's no clickable navigation through it (the TUI is keyboard-only). Use < / Esc to walk it back.

Themes and accessibility

  • Four theme presets: default, monochrome, catppuccin, gruvbox. Set via --theme <preset> or logTui.theme.preset in .coco.config.json.
  • NO_COLOR=1 is honored end-to-end. Borders fall back to the terminal default and color emphasis is dropped without changing layout.
  • The chrome uses a small set of unicode glyphs (, ↑/↓, ·); layout is ASCII-only so a missing glyph never breaks columns.
  • Empty / loading copy is unified across views and points users at the next sensible action — no blank screens.
  • The TUI is keyboard-only by design. Every action is reachable from the keymap or : palette. Mouse input is not consumed.

What's new since v0.34.0

The shell architecture landed in v0.34.0 (TUI shell epic, #747). The releases since have layered on a navigable, action-rich workstation. Highlights worth knowing if you came from an earlier version:

v0.40.0 — unified three-tier navigation

Wherever a list of items lives inside a named group, the group's title is now a first-class cursor target with its own canonical action. The same mental model carries across all four surfaces it applies to:

  • Sidebar. at items index 0 promotes the cursor onto the active tab's header (Branches / Tags / Stashes / Worktrees). / scans neighboring tab headers; Enter on the header drills into the dedicated view.
  • Status view. Files render under ▾ Staged (n) / ▾ Unstaged (n) / ▾ Untracked (n). / jumps between groups; at a group's first file promotes to the header; Enter on a header fires the batch action (Stage all unstaged, Unstage all staged, Stage all untracked with y-confirm).
  • Inspector Actions. [ / ] toggles to the Actions tab; / moves the cursor; Enter fires the cursored action (cherry-pick, revert, reset, yank, open in browser).
  • Stash diffs. diff --git rows render as compact ▾ <path> headers; the file the cursor is scrolled inside gets selection styling so the active context is always visible.

Header focus persists across / switches in the sidebar so the user can scan tab → tab → drill in one fluid motion. All four surfaces use the same selection styling for their headers, so the visual cue is the same wherever you are.

v0.39.0 — inspector and cross-list cursor sync

  • The right-hand inspector dropped its duplicative repo / branch / status trailer and added an Actions: section listing the keystrokes available on the cursored entity. Destructive actions render with a [!] marker.
  • Inspector at rest is narrow (~22% of width); focusing it via tab expands to ~40% so the metadata, body preview, and action panel get the room they need. Mirrors the existing sidebar focus-expand pattern.
  • On short terminals (rows < 28), the inspector collapses into a tabbed [Inspector] Actions layout. [/] while the inspector is focused cycles tabs.
  • Cursoring a branch in the sidebar / branches view auto-jumps the history panel cursor to that branch's tip commit (debounced 150ms). Same for tags. A Synced history to <ref> status confirms the jump even when the dedicated branches view obscures the history graph.
  • Current branch always pins to position 0 of the branches list regardless of sort mode. After a checkout, the cursor snaps back to row 0 so it lands on the just-checked-out branch.
  • New keys on the history view: B create branch from cursored commit, gT create tag from cursored commit. The prompt itself is the affirmative gate.
  • Header label is coco (was coco ui).

v0.38.0 — action surface

  • Pull-request panel via g p: header / checks / reviews / body with m / x / a / R / c / O action keys.
  • History-view mutations: R revert, Z reset (soft / mixed / hard mode prompt), i interactive rebase. All routed through y-confirm or mode prompt.
  • d on a commit-diff or stash-diff toggles between unified and side-by-side rendering. Persists per-repo. Falls back to unified on terminals narrower than 120 cols.
  • H on a diff view applies the cursored hunk to the worktree (git apply). gH applies to the index (git apply --cached).
  • Higher-fidelity commit graph: pattern junctions (├╮ / ├╯), per-lane coloring, distinct merge / HEAD glyphs ( / ).
  • In-sidebar selection: when sidebar is focused, ←/→ switch tabs and ↑/↓ (or j/k) navigate items. Per-entity ops (Enter checkout / a apply / D delete / etc.) fire from the sidebar without drilling into the dedicated view.
  • Multi-line input prompt for PR comments + review bodies. Enter inserts a newline; Ctrl+D submits. Single-line prompts (branch names, merge strategies) keep Enter as submit.
  • Branches list polish: dropped "even with X" noise, added relative timestamps (today / Nd / Nw), four-state remote indicator (* / / / ).
  • Stash diff header surfaces @{N} <message> on <branch> instead of the raw timestamp ref.

v0.37.0 — quick-win affordances

  • y / Y yank the cursored identifier (commit hash, branch, tag, stash ref, file path) to the system clipboard from every promoted view.
  • 1 / 2 / 3 on the status view toggle staged / unstaged / untracked visibility.
  • /path:src/foo and /author:alice re-run git log with the matching flags so commits touching a path or by a given author show up without dropping to a shell.

v0.34.0 — chord prefix

g is now a chord prefix. Pressing g alone no longer toggles the graph immediately — it waits for the second key. The graph toggle moved to \. Previously g did toggleGraph as a side effect of starting a gg chord, which caused a brief flicker on every g-prefixed sequence.

If you had muscle memory for g, you can either retrain to \ or use : and search for "graph" to invoke it from the palette.

Quick reference card

Navigation              Within a view              Modes
  g h  history            j/k, ↑/↓   move             ?    help (toggles)
  g s  status             gg / G     top / bottom     :    palette (toggles)
  g d  diff               n / N      next / prev      /    search (toggles)
  g c  compose            Tab        focus next       Esc  close mode / back
  g b  branches           ←/→        sidebar tab      <    back (nav stack)
  g t  tags               [/]        sidebar tab /    Quit
  g z  stash                         inspector tab      q, Ctrl+C
  g w  worktrees          1-5        sidebar jump
  g p  pull request       \          toggle graph
  g x  conflicts          r          refresh
  g r  reflog             d          unified ↔ split  (diff view)
  g B  bisect             m          mark compare base (branches/tags/history)
                          g/b/s/x    bisect: good/bad/skip/reset (bisect view)

History view ops          Diff view ops              PR view ops
  c   cherry-pick           H   apply hunk             m   merge
  R   revert                gH  apply hunk to           x   close
  Z   reset (mode prompt)       index                  a   approve
  i   interactive rebase    [/] file/hunk nav          R   request changes
  B   create branch here    space  stage/unstage       c   comment
  gT  create tag here       z   revert                 O   open in browser
  y/Y yank hash             c   cherry-pick file
  O   open in browser

For surface-specific actions (staging, hunks, commit compose, workflow keys like D/X/I), see the per-view sections in Coco UI.

Clone this wiki locally