gwae
niri's scrolling tiling, for your CLI agents, in any terminal.
An infinite 2D grid of strips where panes never shrink.
No daemon. No compositor. One process.
curl -fsSL
https://raw.githubusercontent.com/hongnoul/gwae/main/scripts/install.sh
| bash
GitHub · Releases · MIT · macOS / Linux / Windows
Onboarding
Install → Guided setup → Spawn agents → Hold ⌥ to triage
curl -fsSL https://raw.githubusercontent.com/hongnoul/gwae/main/scripts/install.sh | bash
gwae # one strip, one quarter-width pane
gwae init # guided setup: theme, layout, chrome (live preview)
gwae run "claude" # your agent in column 0
gwae doctor # config + theme validity, layout smoke
- First run walks a short guided setup: theme with live swatches, panes at launch, column width — every question drawn over a live mockup of the grid, repainted on each keypress.
-
⌥+;spawns your agent in a new column right of focus.⌥+Enteropens a column,⌥+Shift+Entera new strip below. -
Hold
⌥for the minimap: one tile per pane, tinted by status.⌥+gsmart-jumps to the pane that needs you.
Why
Every terminal multiplexer divides a fixed screen: more agents means smaller panes, until nothing is readable. niri solved this on the desktop with scrolling tiling — columns keep their size, the viewport moves. gwae brings that model into the terminal you already use.
- Panes never shrink. Fixed-width columns; a row that outgrows the screen scrolls past the viewport edge — it doesn't cram.
- Quantized scroll. The viewport rests only on column boundaries, so the same grid paints pixel-identically in every scroll state. No slivers, no wobble.
-
Single process. No socket, no attach/detach.
Persistence is each harness's own
--resume. -
Kitty graphics passthrough. Screenshots and
kitten icatrender inside their pane, clipped to the pane rect.
For coding agents
gwae hosts ordinary PTYs, so every agent works out of the box: Claude Code, Jcode, Codex, OpenCode, Gemini CLI, anything you can launch from a command line. Status tracking speaks the standard OSC 133 protocol only, with a quiet-heuristic fallback for shells without integration.
» working command running
! wants attention idle with output / prompt waiting
✓ done exited 0
✗ failed non-zero exit
⌥+g jumps to the pane that needs you most: failed beats
wants-attention beats done, nearest first, crossing strips and
following with the scroll.
Compared
| Project | Layout | In a terminal? | Detach? | Platforms |
|---|---|---|---|---|
| tmux | plane tiling | yes | yes (server) | macOS/Linux/*BSD |
| Zellij | plane tiling + floating | yes | yes | macOS/Linux/Windows |
| Séance | niri strip (GUI) | no | socket | Linux (GTK) |
| tairi | niri strip (GUI) | no | workspaces | macOS |
| gwae | 2D niri strip grid | yes | no (--resume) |
macOS/Windows/Linux |
Philosophy
- No daemon, deliberately. Your agents already persist themselves. A shell that must survive the terminal belongs in tmux, which runs happily inside a gwae pane.
- Zero instrumentation. Panes stay ordinary PTYs speaking standard protocols. Nothing to install into your agent.
- Every binding self-documents. Keybindings, the cheat-sheet HUD, hints, and the README render from one registry — tests fail the build when any surface drifts.
- Structured, not free-form. A grid of strips, not a canvas. No floating panes, no plugin system.
Usage
⌥+h/j/k/l focus left / down / up / right (crosses strips)
⌥+Shift+hjkl move column / carry pane
⌥+Enter new column right of focus
⌥+; spawn agent column
⌥+s split: new pane below
⌥+r cycle column width 1/3 → 1/2 → 1/4
⌥+f toggle full width
⌥+↑/↓ scrollback (typing snaps back to live)
⌥+1..9 jump to column N
⌥+g smart-jump to the pane that needs you
⌥+t live theme picker
⌥+/ cheat-sheet HUD
All other keys pass through to the focused pane. Full table in the README.
Architecture
gwae (one process)
├── Layout core (rows/strips/columns/panes) — pure, no I/O
├── Pane tasks (one per PTY: bytes → parse → grid + OSC 133)
├── Composer (coalesce damage → single 2D cell buffer)
├── Render (diff buffer → batched ANSI, sync-update markers)
├── Input (raw mode: decode keys, route to pane or ⌥)
└── Minimap / smart-jump (per-pane status → chrome)
Layout invariants are proptest properties; E2E tests
drive the real binary through a live PTY. See
ARCHITECTURE.md
and the normative
LAYOUT-SPEC.md.