Serie: How Terminal Image Protocols Revolutionize Git Commit Graphs
Hook
While most developers struggle to parse ASCII art commit graphs in git log --graph, Serie sidesteps the entire text-based visualization problem by rendering graphs as actual images—directly in your terminal.
Context
Git's built-in git log --graph has remained essentially unchanged for over a decade, rendering commit history as ASCII art using pipes, slashes, and asterisks. For simple linear histories, this works adequately. But the moment you're dealing with multiple feature branches, merge commits, and parallel development streams, those ASCII diagrams become nearly indecipherable—a tangle of characters that requires intense focus to parse mentally.
GUI Git clients like GitKraken and Tower solved this with rich visual graphs, but they pull you out of the terminal workflow. Terminal-based Git clients like lazygit and tig improved the experience somewhat, but they're still constrained by ASCII character limitations. The fundamental problem is that text-based terminals were never designed for rich graphics. Serie takes a different approach: instead of trying to draw better ASCII art, it exploits modern terminal emulators' ability to display actual images using protocols like iTerm2's Inline Images Protocol and Kitty's Terminal Graphics Protocol. The result is a commit graph that looks like it belongs in a GUI application, but lives entirely in your terminal.
Technical Insight
Serie's architecture revolves around three core components: Git data extraction, graph image generation, and terminal image protocol transmission. Unlike traditional TUI applications that render everything using terminal cells and Unicode characters, Serie generates its commit graph as an actual image file and then transmits it to the terminal using specialized escape sequences.
The application is built on top of Ratatui, the Rust TUI framework, but diverges from typical Ratatui usage patterns. Where most Ratatui apps render everything through the framework's widget system, Serie uses Ratatui primarily for the interface chrome—the commit details pane, keyboard navigation, and command execution—while the commit graph itself is rendered as an embedded image.
Here's how you might configure Serie to integrate with external diff tools and customize the display:
# ~/.config/serie/config.toml
# Use difftastic for syntax-aware diffs
[commands]
diff = "difft --color=always"
# Customize keybindings for your workflow
[keybindings]
scroll_down_half_page = "d"
scroll_up_half_page = "u"
toggle_diff = "Space"
copy_commit_sha = "y"
# Graph rendering options
[graph]
max_nodes = 1000
node_radius = 4
edge_width = 2
The terminal image protocol integration is where things get interesting. Serie must detect which terminal you're using and select the appropriate protocol. For iTerm2, it uses the Inline Images Protocol, which works by encoding image data in base64 and wrapping it in ESC sequences like ESC]1337;File=inline=1:[base64 data]^G. For Kitty, it uses the Terminal Graphics Protocol, a more sophisticated system that supports image chunking and placement commands.
The protocol detection happens at startup and influences rendering behavior throughout the session. Here's a simplified view of how the image transmission works conceptually:
// Pseudocode illustrating the protocol selection logic
match detect_terminal_protocol() {
TerminalProtocol::ITerm2 => {
let image_data = render_commit_graph_as_png(&commits);
let base64 = encode_base64(image_data);
write!(terminal, "\x1b]1337;File=inline=1:{}\x07", base64)?;
}
TerminalProtocol::Kitty => {
let image_data = render_commit_graph_as_png(&commits);
transmit_kitty_graphics_protocol(&image_data, terminal)?;
}
TerminalProtocol::KittyUnicode => {
// Fallback mode using Unicode placeholders
let placeholder_grid = generate_unicode_placeholders(&commits);
write!(terminal, "{}", placeholder_grid)?;
}
TerminalProtocol::Unsupported => {
eprintln!("Terminal does not support image protocols");
}
}
The graph rendering itself uses standard image generation libraries to create the visual representation. Serie parses the Git repository using git2-rs (libgit2 bindings for Rust), extracts the commit DAG structure, and then applies graph layout algorithms to position nodes and edges. The result is a PNG image that gets regenerated whenever you navigate or filter the commit history.
One clever optimization is how Serie handles scrolling and navigation. Rather than regenerating the entire image on every frame, it maintains a state model that tracks which portion of the graph is visible. When you scroll, Serie first attempts to reuse cached image data, only regenerating when necessary—such as when you've scrolled beyond the cached region or when the repository state changes.
The Kitty Unicode placeholder mode deserves special mention because it's a workaround for environments where full image protocols don't work, particularly tmux. In this mode, Kitty transmits the image to create Unicode character placeholders that reference the image data. The terminal then renders the image "behind" the placeholder characters. It's a hack, but it enables Serie to work in multiplexed environments where traditional image protocols break down.
Serie also supports custom commands that can be bound to keybindings, allowing you to pipe commit data to external tools. You might bind a key to open the commit in GitHub, copy the SHA to your clipboard, or trigger a custom review workflow. The command execution uses shell invocation with environment variables populated from the current commit context:
[commands.custom]
open_in_github = "open https://github.com/owner/repo/commit/$SERIE_COMMIT_SHA"
copy_sha = "echo -n $SERIE_COMMIT_SHA | pbcopy"
show_files = "git show --stat $SERIE_COMMIT_SHA | less"
This extensibility model keeps Serie focused on graph visualization while enabling integration with your broader Git workflow.
Gotcha
Serie's biggest limitation is terminal compatibility, and it's not a small constraint. You absolutely must use iTerm2 or Kitty (or forks like WezTerm in Kitty mode). If you're using Alacritty, which is extremely popular in the Rust and terminal enthusiast communities, Serie simply won't work. Windows Terminal, despite Microsoft's recent investments in terminal technology, doesn't support these image protocols either. This isn't a bug or missing feature—it's an architectural constraint. Serie's core value proposition depends on terminal image protocols, and if your terminal doesn't support them, there's no fallback that provides the same experience.
Terminal multiplexer support is similarly limited. While Kitty's Unicode placeholder mode works with tmux, it's a degraded experience compared to running Serie directly. Screen and Zellij don't work at all. If your workflow involves attaching to long-running tmux sessions on remote servers, Serie becomes significantly less useful. You can still use it locally to browse repositories, but the seamless integration you might expect from a terminal application isn't there. Additionally, Windows support is unofficial at best. While Rust compiles for Windows, the terminal ecosystem on Windows doesn't align with Serie's requirements, making it primarily a Unix and macOS tool despite being written in a cross-platform language.
Verdict
Use if: You work in iTerm2 or Kitty on macOS or Linux, you frequently navigate complex Git histories with multiple branches, and you value visual clarity in commit graphs enough to accept terminal constraints. Serie excels in its specific niche—it makes commit history genuinely easier to understand compared to ASCII alternatives, and the focused scope means there's almost no learning curve. If you're already in a supported terminal environment, the value is immediate. Skip if: You use any other terminal emulator, work primarily on Windows, rely on terminal multiplexers for your workflow, or need a full-featured Git client rather than just a graph viewer. The terminal compatibility requirements are non-negotiable, and no amount of configuration will make Serie work in unsupported environments. For those cases, stick with lazygit or gitui—they're less visually impressive but work everywhere.