Skip to content

How it's built

tt-git is one app with two front ends. Everything the app knows and decides lives in one crate, tt-git-app. The terminal app draws it with ratatui; the desktop app draws it with GPUI, the UI framework the Zed editor is built on. Neither front end decides what a key does, what a pane shows or which git command runs. That’s why the two apps behave the same, and why a key you rebind or a plugin you install works in both.

tt-git is a Cargo workspace. The arrows follow each crate’s dependencies in its Cargo.toml:

tt-git's cratesThe tt-git binary depends on tt-git-tui, which draws with ratatui. The tt-git-gui binary draws with GPUI and gpui-component. Both front ends depend on tt-git-app, the shared app, which depends on tt-git-core, tt-git-graph and tt-git-plugin. tt-git-plugin depends on tt-git-core. tt-git-testkit is for tests, and the plugins in plugins/ are separate programs that talk to tt-git through its CLI and socket.tt-gitterminal app: the binary and its CLItt-git-guidesktop app: windows, menus, GPUI viewstt-git-tuidraws with ratatui, reads crossterm inputGPUI + gpui-componentZed's GPU UI frameworktt-git-appthe app both front ends run: state, panes, keymap, dialogs, view models, jobs, plugin panestt-git-coreruns git, parses what it saystt-git-graphthe commit graph's lanestt-git-pluginplugin host and socket APItt-git-testkittests only: sandbox repos, test driverplugins/GitHub, Azure DevOps: separate programsCLI, socket
An arrow points to a crate the other one uses. The front ends also use tt-git-core's and tt-git-plugin's types directly.
CrateWhat it isUses
tt-git-coreRuns the git on your PATH and parses what it prints: commits, branches, status, diffs, blame. Also the write operations, undo and the config and state paths.none of the others
tt-git-graphLays out the commit graph’s lanes. No git, no UI.none of the others
tt-git-pluginThe plugin host: manifests, the registry, installing, running plugins and the JSON socket.tt-git-core
tt-git-appThe app itself, for both front ends (below). It has no ratatui, crossterm or GPUI in it; a test fails if one gets in.tt-git-core, tt-git-graph, tt-git-plugin
tt-git-tuiThe terminal front end: draws tt-git-app with ratatui and turns crossterm’s keys and mouse into the app’s input.tt-git-app, tt-git-core, tt-git-graph, tt-git-plugin
tt-gitThe terminal app’s binary: the command line (tt-git plugin list, tt-git update…) and starting the terminal front end.tt-git-tui, tt-git-core, tt-git-plugin
tt-git-guiThe desktop app: its binary and its front end. Draws tt-git-app with GPUI and gpui-component, and adds windows, menus and the start window.tt-git-app, tt-git-core, tt-git-plugin, GPUI
tt-git-testkitFor tests only: throwaway repositories, a driver that runs the app in-process, and the mock project the screenshots on this site show.tt-git-tui, tt-git-core, tt-git-plugin

Outside the crates, the GitHub and Azure DevOps plugins in plugins/ are separate Go programs. Like any plugin, they talk to tt-git only through its command line and socket, so they work with both apps.

tt-git-app holds everything that isn’t drawing:

  • The state: the repository, every pane and its selection and scroll position, the open dialog, the layout, the theme.
  • The keymap. Every key, in both apps, goes through it. A front end only says which key was pressed.
  • What each pane shows. For every pane and dialog the app works out the rows to show: plain text split into spans, each with a style role (a branch name, a date, an added line) rather than a color. A front end looks each role up in the theme and draws it.
  • The mouse. A front end says what the pointer was over (a row, a tab, a pane’s border); the app decides what that click means, double-clicks included.
  • Jobs: git commands, run in the background so the screen never waits on them, with their results applied when they finish.
  • Plugins, their events and socket, and the terminal panes (plugin panes and the agent pane), which run in a pseudo-terminal the app owns.
Terminal (tt-git-tui)Desktop (tt-git-gui)
Draws withratatui, into the terminalGPUI, on the GPU, in a window
Sizes interminal cellspixels, with text fitted to columns of one monospace font
Inputcrossterm’s keys and mousethe window’s keys, clicks, right-clicks and wheel
Its own extrasruns in any terminal, over SSH toomenus, right-click menus, resizable panes, zoom, a window per repository, the start window
Editorssuspends itself and runs a terminal editorruns a terminal editor in a pane over the window
Clipboardthe terminal’s (OSC 52)the system clipboard

A key press goes the same way in both: the front end turns it into the app’s key, the app’s keymap runs the command, the app works out what changed, and the front end draws it again.

GPUI is the UI framework Zed’s team wrote for the Zed editor. It draws everything on the GPU: Direct3D 11 on Windows, Metal on macOS and Vulkan on Linux, so a long graph, a big diff or a blame scrolls smoothly in a window too.

The desktop app uses GPUI through GPUI Kit, which pins a published snapshot of Zed’s GPUI together with gpui-component, the component library the title bar, the menus, the right-click menus and the resizable splits come from. The panes themselves are tt-git’s own: one monospace font, laid out in rows, styled from the same theme as the terminal app.