Architecture
teru is ~16K lines of Zig. The codebase is organized around a clear separation between platform backends, the terminal core, AI integration, and rendering.
Source Structure
src/
├── main.zig Entry point, event loop, prefix keys
├── compat.zig Zig 0.16 compatibility helpers (time, fork)
├── lib.zig libteru C-ABI public API
├── core/
│ ├── Grid.zig Character grid (cells, cursor, scroll regions, alt-screen)
│ ├── VtParser.zig VT100/xterm state machine (SIMD fast-path)
│ ├── Pane.zig PTY + Grid + VtParser per pane
│ ├── Multiplexer.zig Multi-pane orchestrator + rendering
│ ├── KeyHandler.zig Prefix key dispatch
│ ├── Selection.zig Text selection state machine
│ ├── Clipboard.zig Display-aware clipboard (xclip / wl-clipboard)
│ ├── Terminal.zig Raw TTY mode, poll-based I/O
│ └── UrlDetector.zig URL detection (regex-free)
├── agent/
│ ├── PaneBackend.zig CustomPaneBackend protocol (Claude Code)
│ ├── McpServer.zig MCP server (6 tools, Unix socket)
│ ├── HookHandler.zig Claude Code hook JSON parser (16 event types)
│ └── protocol.zig OSC 9999 agent protocol parser
├── graph/
│ └── ProcessGraph.zig Process DAG (nodes, edges, agent metadata)
├── tiling/
│ └── LayoutEngine.zig 4 layouts, 9 workspaces, swap layouts
├── persist/
│ ├── Session.zig Binary serialization (save/restore)
│ └── Scrollback.zig Command-stream compression (keyframe/delta)
├── render/
│ ├── software.zig CPU SIMD renderer (@Vector alpha blending)
│ ├── FontAtlas.zig stb_truetype glyph rasterization (351 glyphs)
│ ├── tier.zig Two-tier detection (CPU vs TTY)
│ └── render.zig Module index
├── config/
│ ├── Config.zig ~/.config/teru/teru.conf parser
│ └── Hooks.zig External command hooks (fork+exec)
└── platform/
├── types.zig Shared Event/KeyEvent/Size/MouseEvent types
├── platform.zig Comptime platform selector
└── linux/
├── platform.zig Dual X11/Wayland dispatch
├── x11.zig Pure XCB windowing (hand-declared externs)
├── wayland.zig xdg-shell + wl_shm (hand-declared externs)
└── keyboard.zig xkbcommon (live X11 keymap query) Module Overview
core/
The terminal core. Grid.zig is the character cell matrix — it handles cursor movement, scroll regions, and alt-screen switching (so vim and htop work correctly). VtParser.zig is a state machine for VT100/xterm escape sequences with a SIMD fast-path for plain ASCII text. Each Pane owns a PTY file descriptor, a Grid, and a VtParser.
Multiplexer.zig orchestrates all panes — it owns the render pass, applies tiling layouts, handles focus, and dispatches keyboard events to the active pane.
agent/
The AI integration layer. PaneBackend.zig implements the CustomPaneBackend protocol — a Unix domain socket that Claude Code uses to spawn and manage panes directly. McpServer.zig exposes 6 MCP tools for cross-agent communication. HookHandler.zig parses 16 Claude Code lifecycle events. protocol.zig parses OSC 9999 agent self-declaration sequences.
graph/
ProcessGraph.zig maintains a directed acyclic graph of all running processes. Each node stores PID, parent PID, start time, exit code, and (for AI agents) name, group, status, and progress. Edges encode parent-child relationships. The graph is queryable via the teru_get_graph MCP tool.
tiling/
LayoutEngine.zig implements four tiling algorithms across 9 workspaces. Layout calculations are pure geometry — given a list of pane IDs and a terminal size, it returns a list of rectangles. The multiplexer applies these rectangles during the render pass.
persist/
Scrollback.zig implements command-stream compression: it stores VT byte streams with keyframe/delta encoding rather than expanded cell grids. Session.zig serializes the complete workspace/pane/layout state to a binary file for --attach restore.
render/
software.zig is the CPU renderer. It uses Zig’s @Vector built-ins for SIMD alpha blending — blitting glyphs from the font atlas onto the pixel buffer. FontAtlas.zig wraps stb_truetype.h (vendored, 5KB, public domain) to rasterize 351 glyphs at startup. The tier.zig module selects between the software renderer (windowed) and raw TTY output (—raw mode).
config/
Config.zig parses ~/.config/teru/teru.conf — a simple key=value format read once at startup. Hooks.zig manages external command hooks, executing them via fork+exec without blocking the event loop.
platform/
Platform backends are selected at compile time via Zig’s comptime. On Linux, platform.zig dispatches between X11 (via pure XCB, hand-declared externs — no Xlib) and Wayland (via xdg-shell + wl_shm). macOS (AppKit) and Windows (Win32) stubs compile but are not yet functional.
Dependencies
Runtime (system libraries)
| Library | Purpose |
|---|---|
libxcb | X11 protocol (XCB, not Xlib) |
libxkbcommon | Keyboard translation (X11 + Wayland) |
libwayland-client | Wayland protocol |
Vendored (compiled into binary)
| Library | Size | Purpose |
|---|---|---|
stb_truetype.h | 5KB | Font rasterization |
xdg-shell-protocol.c | 7KB | Wayland shell protocol (generated) |
No FreeType. No fontconfig. No OpenGL. No EGL. No GTK.
Build System
teru uses Zig’s build system (build.zig). The Makefile wraps common commands:
make dev # debug build (~4MB, full safety + debug symbols)
make release # release build (1.3MB, ReleaseSafe)
make release-x11 # X11-only (drops wayland-client dep)
make release-wayland # Wayland-only (drops xcb dep)
make test # run all 250 tests
make install # install to /usr/local/bin/teru
make size # compare build profiles
make deps # check runtime dependencies Direct Zig build flags:
zig build -Doptimize=ReleaseSafe # release build
zig build -Doptimize=ReleaseSafe -Dwayland=false # X11-only
zig build -Doptimize=ReleaseSafe -Dx11=false # Wayland-only Testing
250 inline tests covering the full stack:
| Area | Tests |
|---|---|
| VT parser | CSI, SGR, OSC, DCS sequences |
| Grid | Cursor movement, scroll regions, alt-screen |
| Tiling engine | All 4 layouts, workspace switching |
| Scrollback compression | Keyframe/delta encode/decode |
| Session serialization | Save/restore round-trip |
| Agent protocol | OSC 9999 parser |
| Process graph | Node/edge operations, agent metadata |
| URL detection | Various URL patterns |
| Font atlas | Glyph rasterization |
| Software renderer | Alpha blending correctness |
Run with:
make test
# or
zig build test Tests are inline (test blocks inside source files) rather than separate test files. This keeps tests adjacent to the code they test and avoids import gymnastics.
Design Principles
No GPU by design. For terminal rendering — text on a grid — the GPU is idle 99.9% of the time. SIMD @Vector blitting on CPU is faster for this workload and works everywhere: SSH sessions, VMs, containers, cheap VPS with no GPU.
Single binary. No daemon process, no server component, no IPC overhead for the common case. Everything in one event loop.
Minimal dependencies. Three runtime deps (xcb, xkbcommon, wayland-client), two vendored C files. The 1.3MB binary size is a direct result of this discipline.
Comptime over runtime. Platform selection, build options (-Dx11=false), and render tier selection all happen at compile time. The binary you ship contains only the code you need.