Skip to content

Coco UI

Griffen Fargo edited this page Jun 9, 2026 · 17 revisions

Coco UI

coco ui is Coco's full-screen Git workstation. It builds on the interactive log work and moves toward a terminal-native alternative to GitKraken, lazygit, and gitui for daily repository work.

coco log -i remains supported. Internally it opens coco ui --view history, so existing muscle memory keeps working while new workflows grow around the broader coco ui entrypoint.

Start The Workstation

# Open the history browser
coco ui

# Start on worktree status
coco ui --view status

# Start on the focused diff surface
coco ui --view diff

# Keep using the existing interactive log entrypoint
coco log -i

# Browse all refs or filter history before opening
coco ui --all
coco ui --branch feature/ui --path src --limit 500

# Force a theme preset
coco ui --theme catppuccin
NO_COLOR=1 coco ui

If coco ui is not running in a TTY, Coco falls back to non-interactive output so automation and packaged CLI smoke checks do not hang.

Layout

The UI uses a persistent Git workstation layout:

  • Header: command label (coco), repository, branch, dirty state, provider/PR state, search text, and a -separated breadcrumb showing where you are in the navigation stack (e.g. history › diff).
  • Sidebar: status, branches, tags, stashes, and worktrees tabs. When focused, items inside the active tab are cursor-navigable and per-entity actions (checkout / apply / pop / drop / etc.) fire without leaving the workstation view.
  • Main panel: the active view — history graph, status, diff, compose, branches, tags, stash, worktrees, or pull-request.
  • Right dock (inspector): contextual metadata + per-entity action list. Narrow at rest (~22% of width) so the commit graph dominates; expands to ~40% when focused via tab. On short terminals, collapses into a tabbed [Inspector] Actions layout so neither section gets clipped.
  • Footer: two slots — view-specific contextual hints on the left, and persistent global affordances anchored to the right (g jump · < back · ? help · : cmds · q quit).
  • Narrow terminals (single-pane): below ~100 columns the three-pane layout folds to a single full-width pane (the old 8-cell icon rails are retired). Tab / Shift+Tab cycles which pane is visible (sidebar → main → inspector) and the footer prepends a tab: [sidebar] main inspector switcher. Press v to momentarily peek the sidebar from the main/inspector pane — v or Esc snaps you back. This makes an 80×24 tmux split or SSH session first-class.

The goal is calm density. Common actions stay visible; advanced or destructive actions move behind help, the command palette, or confirmation prompts.

Views

coco ui has sixteen top-level views. Each is a first-class destination — reachable from any other view through the navigation stack.

View Chord Start flag Purpose
History g h --view history Browse commits, refs, changed files, and commit metadata.
Status g s --view status Select changed files, stage/unstage, revert with confirmation.
Diff g d --view diff Inspect the selected commit or worktree file diff with hunk navigation and staging. Toggle unified ↔ side-by-side with d.
Compose g c Full-screen commit draft editor with summary/body cursors, AI draft, and hook feedback.
Branches g b List local branches with divergence info; checkout/delete/create-PR via workflow keys. Current branch pinned at row 0 and highlighted in green. Checking out a branch that's already checked out in another worktree raises a prompt to switch to that worktree (y), remove it and check out here (r), or remove it and delete the branch (x).
Tags g t List tags.
Stash g z Stash list as an aligned table (ref · age · branch · files · message) with a column header; full detail in the inspector preview. a/A apply, p pop, R rename, b branch-from-stash, X drop, u undo-drop; : palette adds staged-only / keep-index variants. (gs is reserved for status, so stash uses gz. gZ creates a stash from any view.)
Worktrees g w List linked worktrees with current/dirty markers; remove via W.
Pull request g p Dedicated PR action panel for the current branch: header, checks table, reviews summary, body preview. Action keys: 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. Distinct from g p (single, current branch); capital P targets the cursored PR by number. 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, 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, …) with relative time, action, hash, and message. Enter drills into the diff for the entry's hash. Actionable recovery keys: c checks out the cursored entry (detaches HEAD to inspect / recover), Z resets HEAD to the entry (soft / mixed / hard prompt), B creates a branch at the entry. Reset and branch reuse the same workflows as the history view.
Bisect g B Bisect workflow surface. Shows the current candidate, the parsed decision log, and the action keys: g good / b bad / s skip / x reset. The title bar shows a BISECTING badge whenever a bisect is in progress.
Submodules g M Registered submodules with name, pinned sha, tracking branch, and clean/modified/uninitialized/conflicted state. Enter drills into the cursored submodule (see Submodule navigation below). Capital M disambiguates from g m which is the compare-base mark.
Changelog L Full-screen AI-generated changelog for the current branch. Reached via L from history or branches (not a g-chord). Per-branch cache; r regenerates, y yanks, E opens in $EDITOR, c kicks off create-PR seeded with the content.

The --view flag accepts history, status, or diff for the historical command-line surface. The other views are reached interactively via chords or by pressing Enter on a contextual selection.

History mode starts in compact graph mode. Press \ to toggle to full graph mode when you want higher topology fidelity — pattern junctions (├╮ / ├╯), per-lane coloring, distinct merge / HEAD glyphs ( / ), and graph continuation rows.

Submodule navigation

coco ui treats every nested submodule as a first-class repository. Pressing Enter on a submodule drills into it — git, history, branches, status, diff, and every other view re-scope to the submodule's working directory, as if you had run coco ui from inside it. Pressing Esc or < pops back to the parent.

Two entry points:

  • Submodules view (g M). Cursor a row, press Enter. The frame opens on the submodule's history view.
  • Commit diff (any commit that touches a submodule). Open the diff, cursor onto the submodule's file row, press Enter. The frame opens with the (oldPin, newPin) range captured from the diff — useful for seeing exactly what changed between two pinned commits.

Once inside, the breadcrumb in the title bar shows where you are (coco › vendor/lib ← esc). Selection state per view is preserved; popping back lands the cursor exactly where you left it on the parent. Drill-ins can stack — coco › vendor/lib › vendor/lib/inner ← esc works the same way, with each Esc walking back one level.

The drill-in is read-only by design. Stage / commit / push workflows still run against the parent until follow-up work on per-frame mutation lands.

Compare two refs

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

  1. From branches, tags, or history, press m on a row to mark the cursored ref as the compare base. The status banner sticks ("Compare base: <label> — press enter on another ref to diff") and the footer adapts to show enter compare · m clear.
  2. Navigate to a second ref on any of those three views.
  3. Press Enter to push the diff view in compare mode (git diff <base>..<head>).
  4. < or Esc pops the diff and clears the base automatically.

m again on the same ref toggles the base off without leaving the view. Outside the compare flow, m is unbound on those views.

Navigation

coco ui shares a chord-driven navigation model with coco log -i. Press g and then a second key to jump anywhere; < or Esc pops the navigation stack to where you came from. Forgot what a view's single keys do? Press g? for a live strip of the current view's single-key actions (? opens the full help).

g h  history    g c  compose    g b  branches    g t  tags        g w  worktrees
g s  status     g d  diff       g z  stash       g p  PR          g x  conflicts
g i  issues     g P  PR triage  g r  reflog      g B  bisect      g M  submodules
<    back       esc back

Selection state per view is preserved across navigation, and a -separated breadcrumb in the header shows your current path.

For the full navigation reference — chord rules, contextual transitions (Enter on a commit, e/c from status), the interactive command palette (:), the / global search across views, the help overlay, the per-context [/] and ←/→ keys, theming, and accessibility — see TUI Navigation.

Worktree And Diff Workflow

In status view:

  • Files render under ▾ Staged (n) / ▾ Unstaged (n) / ▾ Untracked (n) headers in canonical order.
  • j / k or arrows move through files within the active group.
  • / jumps between groups (lands on the group's first file).
  • at the first file of a group promotes the cursor onto the group header. from the header re-enters the group.
  • Enter on a file opens the diff. Enter on a group header fires the batch action: Unstage all staged files, Stage all unstaged files, or Stage all untracked files (the last requires y-confirm).
  • Space stages or unstages the selected file.
  • z asks to revert the selected file. Press y to confirm or n/Esc to cancel.
  • 1 / 2 / 3 toggle the staged / unstaged / untracked visibility mask.

In diff view:

  • j / k move between hunks.
  • PageUp / PageDown scroll the diff.
  • Space stages or unstages the selected hunk.
  • z asks to revert the selected hunk. Press y to confirm or n/Esc to cancel.
  • [ / ] jumps between hunks (or files in stash diffs).
  • Esc or < pops the navigation stack so you return to whichever view pushed diff (status or history).

Stash diffs render multiple files in one scrolling stream. Each diff --git row paints as a compact ▾ <path> header (> <path> in ASCII mode), and the file the cursor is currently scrolled inside gets selection styling so the active context is always visible.

Real diffs stay in the main panel so long diffs do not overflow the right dock. The right dock stays focused on metadata and commit actions.

Commit Compose

Status and diff views show a commit box in the right dock.

Key Action
e Edit the commit summary/body fields.
Tab Switch fields while editing.
Enter Move from summary to body, or finish body editing.
Ctrl+U Clear the active field while editing.
Esc Leave edit mode.
c Commit staged changes with the current draft.
I Ask for an AI commit draft after explicit confirmation.
Esc (while drafting) Cancel the in-flight AI draft. Hard cancel via AbortController — the LLM request tears down, the spinner stops, the status line reads "AI draft cancelled." Works from any view (not just compose) while the draft is loading.
R Accept a pending AI draft when one is staged (see below).

Manual commits require staged changes and a non-empty summary. Hook failures are shown in the TUI status/commit feedback instead of breaking terminal state.

AI drafts are opt-in. Pressing I shows a confirmation panel with an estimated token impact before Coco calls a provider. Confirmed AI drafts populate editable summary/body fields; they do not commit automatically.

Live streaming preview (opt-in)

When service.streaming.enabled: true is set in .coco.config.json, the AI draft renders a live preview pane below the loader as the model generates. Content builds up character-by-character so you can read the draft forming instead of staring at an opaque spinner. The final draft still goes through the same schema validator and commitlint retry as the non-streaming path; streaming is preview-only.

{
  "service": {
    "streaming": { "enabled": true }
  }
}

Default is false. Some providers stream poorly (one-shot blob disguised as a stream) and the preview just blinks in those cases.

Pending AI draft confirmation

When you've already typed content in the summary or body and then fire I, the AI draft does not silently replace your typing. It stages in pendingAiDraft and the compose surface shows a message:

AI draft ready. Press R to replace your text, or Esc to keep what you have.

Press R to swap the AI draft in (your typing is lost). Press Esc to dismiss the AI draft (your typing is preserved). The empty-fields case still replaces directly as before — no extra step when there's nothing to lose.

Surface keybindings

For the navigation model (chords, back, palette, search, help, breadcrumb, themes, context-routed [/] and ←/→), see TUI Navigation. The keys below are specific to the surfaces coco ui exposes — they're available alongside the global navigation set.

Generic (every view)

Key Action
j / k, arrows Move selection in the active list
PageUp / PageDown Scroll history / detail / diff
G Jump to last visible commit
n / N Next or previous visible search result
[ / ] Previous or next sidebar tab (sidebar focused) / inspector tab (inspector focused, short terminals) / diff hunk or file (diff view)
/ Switch sidebar tabs (sidebar focused)
15 Jump to sidebar tab
Enter Open the diff for the selected commit (history) or file (status), checkout (branches), open diff (stash), drill in (sidebar tab)
Space Stage/unstage the selected file or hunk (status/diff)
z Revert the selected file or hunk after confirmation
y / Y Yank cursored identifier (commit hash, branch, tag, stash ref, file path) to the system clipboard
O Open the cursored entity in the browser (commit on history; PR / repo elsewhere)
r Refresh repository context

History view

History view actions all route through y-confirm or a mode prompt — none fire silently from the keystroke.

Key Action
c Cherry-pick the cursored commit
R Revert the cursored commit (git revert --no-edit)
Z Reset to the cursored commit. Opens a soft / mixed / hard mode prompt; recovery instructions surface in the status line for --hard.
i Start an interactive rebase from the cursored commit's parent (git rebase -i <sha>^). Lowercase i so the global I ai-commit-summary stays reachable.
B Create a branch rooted at the cursored commit (git switch -c <name> <sha>). Prompts for the name and checks out the new branch.
gT Create a lightweight tag at the cursored commit (git tag <name> <sha>).
C Create a pull request for the current branch. Generates the PR title + body via coco changelog against the default branch, opens a multi-line review prompt pre-filled with the seeded content (Ctrl+D submits, Esc cancels). Auto-detects the head + base branches; surfaces a pointer if a PR is already open for the branch.
L Generate a changelog for the current branch in a full-screen view. Per-branch cache so re-entry is instant; r regenerates, y yanks to clipboard, E opens in $EDITOR, c kicks off create-PR seeded with this content, < / Esc exits.

After a successful split-apply or single commit, the freshly created commits get a accent marker next to their short hash for ~5 seconds so you can see at a glance which rows the operation just created.

Diff view

Key Action
d Toggle between unified and side-by-side rendering. Persists per-repo. Falls back to unified on terminals narrower than 120 cols.
Space Stage/unstage the cursored hunk (worktree diff).
z Revert the cursored hunk (worktree diff).
c Cherry-pick the cursored file from a commit-diff or stash-diff explore.
H Apply the cursored hunk to the worktree (git apply).
gH Apply the cursored hunk to the index (git apply --cached).
[ / ] Jump to previous / next hunk (or file in stash-diff).

Pull-request view

Reachable via g p. Each action routes through a confirmation gate or an input prompt.

Key Action
m Merge the PR. Prompts for merge / squash / rebase, then y-confirms.
x Close the PR (without merging).
a Approve the PR.
R Request changes. Opens a multi-line review-body prompt (Enter inserts a newline; Ctrl+D submits).
c Comment on the PR. Multi-line prompt as above.
O Open the PR in the browser.

Sidebar (focused)

When the sidebar is focused (via tab or by opening it directly), navigation runs on two axes plus an "escape upward" to the active tab's title:

       ┌─ Status (3) ──┐
       │  Branches (12)│   ←/→ between tab titles
       │  Tags (4)     │   (header focus carries
       │  Stashes (1)  │    across switches)
       └─ Worktrees (2)┘
              ↑↓
       ──────────────
       [Branches (12)]   ← Header is its own cursor target.
                            ↑ from item index 0 lands here.
                            Enter drills to the dedicated view (`g b`).
       ──────────────
       *  main           ← Items list. ↑/↓ navigates;
          feat/x            Enter performs per-entity action;
          feat/y            ↓ from header re-enters here.
Key Action
/ Switch between sidebar tabs (Status / Branches / Tags / Stashes / Worktrees). Header focus carries across switches.
/ , j / k Navigate items within the active tab's list. ↑ at index 0 promotes the cursor onto the active tab's header.
Enter (on items) Per-entity primary action — checkout for branches, open diff for stashes, drill into the dedicated view for tabs without a primary action.
Enter (on header) Drill into the dedicated view for the active tab (g b / g t / g z / g w / g s) regardless of items.
D / R / u / +P / F Branches: delete / rename / set-upstream / push / fetch
a / p / X Stashes: apply / pop / drop
T / P Tags: delete / push
W Worktrees: remove

The cursor only ever appears in one place. When the header is focused, the items render without their selection highlight; when an item is focused, the header renders as the normal active title. The per-entity ops fire via the same dispatch as the dedicated views, so muscle memory carries across.

Inspector (focused)

When focused (via tab), the inspector expands to ~40% of width. Two tabs share the panel: [Inspector] shows commit metadata and the changed-file list; [Actions] shows the per-entity action cheat-sheet and is itself a cursor-navigable list.

Key Action
[ / ] Toggle between [Inspector] and [Actions] tabs
/ (Inspector tab) Move the file-list cursor
/ (Actions tab) Move the cursor through the action list
Enter (Inspector tab) Open the diff for the cursored file
Enter (Actions tab) Fire the cursored action (cherry-pick / revert / reset / yank / open in browser, etc.)

The Actions tab dispatches the same events the matching keystroke would fire, so the action list stays in sync with the keyboard. The active row gets the same selection styling sidebar headers and status group headers use, so the visual cue is consistent across surfaces.

Compose

Key Action
e Edit commit compose fields inline (also pushes compose if you're elsewhere)
E Open the commit draft in $EDITOR / $VISUAL. Round-trips the current draft through a temp file so you get the full power of your editor (markdown highlighting, paste, multi-line nav). On save, the content gets re-split into summary + body. A crashed editor preserves the existing draft. Also works from status and diff views (pushes into compose first).
c Commit staged changes (also pushes compose first so the result lands in view)
S Split the staged set into multiple commits. Opens an overlay with the LLM-generated plan (y apply / r regenerate / < cancel). Each group's title respects your conventional-commits + commitlint config. See Commit Split for the full flow.
Tab Switch summary/body fields while editing
Enter (in editor) Move from summary to body, or finish body editing
Ctrl+U (in editor) Clear the active field
Esc (in editor) Leave edit mode
I Generate an AI commit draft from the staged changes

After a successful operation (commit / split / etc.), the status line surfaces a directive next-step hint: "Created N commits — press gh to view them in history. 6 unstaged + 3 untracked remaining — press gs to stage, I to draft AI commit message."

Input prompts

Most prompts are single-line (Enter submits). Two are multi-line: pr-comment and pr-request-changes. In multi-line mode:

Key Action
Enter Insert a newline (does not submit)
Ctrl+D Submit
Esc Cancel
Backspace Delete the previous character (including newlines)
Ctrl+U Clear the entire buffer

Workflow actions

D (delete branch), T (delete tag), X (drop stash), W (remove worktree), A (abort operation), M (AI conflict help), and C (create PR) launch workflow actions, gated behind confirmation prompts where destructive. All workflow actions are also reachable from the command palette (:).

GitKraken Migration Notes

GitKraken concept Coco UI equivalent Notes
Commit graph History view with \ toggle for full graph mode Pattern junctions (├╮ / ├╯), per-lane coloring, distinct merge / HEAD glyphs ( / )
File tree / changes panel Status view (g s) Stage with Space, revert with z, navigate hunks in diff view
Diff view Dedicated diff view (g d) with d to toggle unified ↔ side-by-side 120-col fallback to unified on narrow terminals
Stage file / hunk Space in status / diff Hunk-level apply via H (worktree) / gH (index) on commit-diff and stash-diff explores
Commit panel Right-dock commit compose (g c) Edit / commit / AI draft inline; multi-line input prompt for free-form text
AI commit summary I confirmed draft action Token cost shown before the call; cancellable from the prompt
PR / provider panel Dedicated pull-request view (g p) Header, checks table, reviews summary, body preview; m merge / x close / a approve / R request changes / c comment
Right-click commit menu Inspector Actions: section + per-key bindings on history view c cherry-pick, R revert, Z reset (mode prompt), i interactive rebase, B create branch here, gT create tag here, O open in browser
Branches sidebar g b view + sidebar Branches tab Current branch pinned at row 0 and shown in green; synced / diverged / no upstream / * current markers; relative timestamps
Stash list g z view + sidebar Stashes tab Enter opens diff; a apply, p pop, X drop
Worktrees g w view + sidebar Worktrees tab W remove (current worktree refused)

Manual QA Checklist

Use this checklist when validating changes to the TUI:

  • Clean repo: coco ui
  • Dirty repo with staged, unstaged, and untracked files: coco ui --view status
  • Long diff file: open status, press Enter, scroll with PageDown
  • Hunk flow: press j/k, Space, then refresh/status check
  • Revert safety: press z, cancel with n and Esc, then confirm only on disposable changes
  • Commit compose: edit summary/body with e, commit staged changes with c
  • AI draft: press I, cancel once, then confirm in a test repo/provider setup
  • Narrow terminal: verify minimum-size messaging
  • Wide terminal: verify panels remain stable
  • NO_COLOR=1 coco ui
  • Non-TTY fallback: coco ui < /dev/null

Troubleshooting

  • The UI does not open: verify the command is running in a real TTY.
  • Colors look wrong: try NO_COLOR=1 coco ui or set logTui.theme.preset to monochrome.
  • A commit is blocked by hooks: the commit box shows hook output. Fix or restage the affected files, then commit again.
  • AI draft is not running: AI calls require explicit I confirmation and a configured provider.

Plain coco log --format table and coco log --format json remain the stable interfaces for scripts.

Clone this wiki locally