Home
Softono
void

void

Open source MIT Zig
131
Stars
2
Forks
1
Issues
0
Watchers
2 weeks
Last Commit

About void

πŸ•³οΈ VOID β€” Terminal emulator written in hexa-lang.

Platforms

Web Self-hosted

Languages

Zig

Links

void

⬑ void

Void β€” grid-first terminal Β· Ghostty hard fork Β· NΓ—M tiling as a core surface Β· beta: grid mode only

License Based on Ghostty Platform Renderer Core Branch

grid-mode Β· tiling-surface Β· terminal Β· pty Β· tool-call-stream Β· perf-first Β· zig Β· swift Β· gtk Β· metal Β· opengl


Void is a hard fork of Ghostty where an NΓ—M pane grid is a first-class rendering surface β€” not a window-manager bolt-on, not a tmux-style multiplexer process. When cell count N changes the layout auto-rebalances (cols = ⌈√NβŒ‰, rows = ⌈N/colsβŒ‰, cols β‰₯ rows), each cell carries its own cwd/env, and input can broadcast to all cells. It inherits Ghostty's engine (SIMD parser, Metal/OpenGL, per-terminal threads) unchanged. Zig shared core, native Swift on macOS, GTK on Linux.

Beta status β€” grid mode is the only implemented direction. Two further directions are planned, not yet built: a structured agent I/O channel alongside PTY (roadmap P3) and a per-PR perf budget vs the Ghostty baseline (roadmap P4). They are described below as roadmap, not as shipped features.

[!NOTE] Part of the dancinlab n = 6 family β€” hexagonal icon, sibling to NEXUS, Anima, N6, and HEXA-LANG. Void is a UX divergence from Ghostty, not a drop-in replacement; upstream syncs are selective cherry-picks only and full Ghostty history/credit is preserved.

At a glance

   spawn a pane with cmd+ctrl+1..9 β€” the grid auto-rebalances

   N = 2          N = 4               N = 6                  N = 9
   β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”          β”Œβ”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”
   β”‚ 1  β”‚ 2  β”‚    β”‚ 1  β”‚ 2  β”‚         β”‚ 1 β”‚ 2 β”‚ 3 β”‚          β”‚ 1 β”‚ 2 β”‚ 3 β”‚
   β”‚~/p β”‚~/w β”‚    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€         β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€          β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€
   β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”˜    β”‚ 3  β”‚ 4  β”‚         β”‚ 4 β”‚ 5 β”‚ 6 β”‚          β”‚ 4 β”‚ 5 β”‚ 6 β”‚
                  β”‚~/l β”‚~/r β”‚         β”‚~/rβ”‚~/sβ”‚~/tβ”‚          β”œβ”€β”€β”€β”Όβ”€β”€β”€β”Όβ”€β”€β”€β”€
   2 Γ— 1          β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”˜          β”‚ 7 β”‚ 8 β”‚ 9 β”‚
                  2 Γ— 2               3 Γ— 2                  β””β”€β”€β”€β”΄β”€β”€β”€β”΄β”€β”€β”€β”˜
                                                             3 Γ— 3

   cols = ⌈√NβŒ‰   rows = ⌈N/colsβŒ‰   cols β‰₯ rows   Β·   per-cell cwd   Β·   no manual resize handles   Β·   no tmux
void                   # launch terminal
cmd+g                  # toggle grid mode <-> tab mode
cmd+ctrl+1..9          # spawn a tab in grid slot 1..9 (auto-rebalances)
cmd+ctrl+shift+1..9    # cycle tabs within a grid slot
cmd+ctrl+0             # broadcast input to all cells

Why void

Three things upstream Ghostty treats as explicit non-goals β€” Void forks to take exactly these bets.

1. Grid mode β€” a first-class tiling surface

   cells = N                              on add / remove the whole grid
   ──────────────────────────────         re-balances to equal splits:
   N = 2  β†’  2 Γ— 1                        cols = ⌈√NβŒ‰
   N = 4  β†’  2 Γ— 2                        rows = ⌈N/colsβŒ‰
   N = 6  β†’  3 Γ— 2                        cols β‰₯ rows (wider before taller)
   N = 9  β†’  3 Γ— 3                        (no manual resize handles)

The NΓ—M grid is a new renderer path, not a patch on the single-surface renderer and not a multiplexer process. Per-cell cwd / env, shared input routing, broadcast. No tmux, no prefix key, no config DSL to learn. This is the headline β€” the other two directions sit on top of it.

2. Ghostty hard fork β€” performance inherited, not rebuilt

Void did not rebuild a terminal. It hard-forks a fast one and changes three things. The SIMD parser, Metal (macOS) / OpenGL (Linux) renderers, and per-terminal render/read/write threads come straight from Ghostty. 4698 files were renamed Ghostty β†’ Void at commit 964c9e32e; upstream history and contributor credit are preserved (cherry-pick only, no clean merges).

3. AI-native I/O and a perf budget (roadmap β€” not yet implemented)

   shell process     β”Œβ”€β”€β”€β”€ PTY ────────▢  traditional byte stream
        β”‚            β”‚
        β–Ό            β”œβ”€β”€β”€β”€ AGENT ──────▢  structured tool-call events
   libvoid layer ─────                    token stream w/ boundaries
        β–²            └──── META ───────▢  cwd, exit-code, span marks
        β”‚
   agent process      (no wrapper process required)

Neither of these is built yet β€” the beta is grid-only. The plan: a structured agent channel alongside PTY (tool-call events and token-stream boundaries as a data model, not heuristic-parsed from stdout) β€” roadmap P3, deliberately not the headline since Void is grid-first, not an "AI overlay" terminal. And a perf budget where every PR reports a delta against the Ghostty baseline with a β‰₯ 2 % regression blocking merge β€” roadmap P4, the harness is not wired yet. Both are described here as intent, not as shipped behaviour.

Highlights

β–¦ Grid mode (implemented) β€” NΓ—M pane grid as a core surface, auto-layout (cols = ⌈√NβŒ‰, rows = ⌈N/colsβŒ‰), per-cell cwd, broadcast
⬑ Ghostty-grade performance (inherited) β€” SIMD parser, per-terminal render/read/write threads, Metal on macOS, OpenGL on Linux
β—ˆ Native UI (inherited) β€” SwiftUI on macOS (AppIntents, Shortcuts), GTK on Linux (systemd, cgroup isolation)
⚑ Perf budget (roadmap P4 β€” not built) β€” plan: every PR reports Ξ” against the Ghostty baseline; β‰₯ 2 % regression blocks merge
β—† AI-native I/O (roadmap P3 β€” not built) β€” plan: agent protocol alongside PTY; structured tool-call / token-stream channels, no wrapper
↻ Session restore (implemented) β€” per-pane mmap'd ring of raw PTY bytes; auto-replay on void/macOS crash restores scrollback + colors + cursor (no upstream Ghostty equivalent)
β¬’ dancinlab branding β€” hexagonal icon, n = 6 family (NEXUS Β· Anima Β· N6 Β· HEXA Β· Void)

Architecture

       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚            macOS App (Swift)             β”‚
       β”‚    SwiftUI Β· AppIntents Β· CoreText       β”‚
       β”‚        Metal renderer Β· native menu      β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚          libvoid (Zig) β€” core            β”‚
       β”‚   parser Β· terminal state Β· renderer     β”‚
       β”‚   grid engine   (agent I/O: roadmap)     β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚            Linux App (GTK)               β”‚
       β”‚      systemd Β· OpenGL Β· FreeType         β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Zig-based shared core with platform-native shells. Core is C-ABI-compatible so it can be embedded in third-party projects (Ghostty's libghostty pattern β€” renamed to libvoid in this fork).

Install

# 1. Install hexa-lang (gives you `hexa` + `hx` package manager)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/dancinlab/hexa-lang/main/install.sh)"

# 2. Install void
hx install void

Or build from source β€” see HACKING.md. Default branch on the fork is void/main, not main.

Run

void                   # launch terminal
void +show-config      # print active config
void +list-keybinds    # list keybindings
void +crash-report     # list crash reports

Keybindings (default)

Keys Action
cmd+g toggle grid mode ↔ tab mode
cmd+ctrl+1..9 spawn new tab in grid slot 1..9 (stacks β€” repeated presses add tabs to the same slot)
cmd+ctrl+shift+1..9 cycle tabs within grid slot
cmd+ctrl+0 broadcast input to all cells
cmd+opt+return find next (relocated from cmd+g)
cmd+shift+opt+return find previous (relocated from cmd+shift+g)
cmd+t / cmd+n new tab / new window
cmd+d / cmd+shift+d split pane right / down
cmd+, open settings

All keys are rebindable via config β€” nothing is hardcoded.

Fork status

Upstream ghostty-org/ghostty β€” cherry-picks only, no merges
Fork date 2026-04-21 (from upstream commit c3c8572f7)
Default branch void/main
L3 rename complete β€” 4698 files renamed Ghostty β†’ Void at commit 964c9e32e
CI .github/workflows/build-fork.yml on GitHub-hosted macos-15 runners (ad-hoc codesign)
Icon hexagonal, dancinlab n = 6 family

See VOID_FORK.md for the full fork rationale, non-goals, and upstream policy.

Roadmap

Checkpoints (done):

# Milestone Date
C0 project-init β€” hexa scaffold 2026-04-21
C1 fork-base β€” Ghostty β†’ Void rebrand 2026-04-21

Phases:

# Phase ETA Status
P1 Grid mode + new-tab keybinding β€” auto-grid, slot-spawn, mode toggle 2026-05-18 βœ…
P2 Stack analysis β€” map void renderer/apprt/terminal/font internals 2026-05-05 ⬜
P3 AI-native I/O protocol β€” structured agent channel alongside PTY β€” ⬜
P4 Perf baseline β€” capture benches, set void regression budgets β€” ⬜
P5 Diverge / upstream strategy β€” decide what feeds back vs stays void β€” ⬜

P1 (grid mode) is complete: surface rendering, NΓ—M auto-layout (cols = ⌈√NβŒ‰), cmd+ctrl+1..9 slot-spawn, broadcast, and per-cell cwd all landed. P4 (perf baseline) is next β€” capturing the Ghostty-baseline benches before further divergence accumulates.

Non-goals

  • Not a drop-in Ghostty replacement β€” Void will diverge in UX.
  • Not a shell β€” Void drives shells, it does not replace them.
  • Not an "AI terminal" β€” grid mode is the headline and the only thing built; agent I/O is an unimplemented roadmap direction, never an overlay.

Crash reports

Void inherits Ghostty's crash reporter. Reports are saved to $XDG_STATE_HOME/void/crash (default ~/.local/state/void/crash) and are not sent off your machine. Use void +crash-report to list. Reports use the Sentry envelope format with extension .voidcrash.

[!WARNING] Crash reports contain full stack memory per thread at the time of the crash and can include sensitive data.

Session restore β€” survive abnormal termination

When void or macOS dies abnormally, void re-opens with the previous terminal contents (scrollback, colors, cursor) restored β€” not just the window layout. The mechanism is fork-only (no upstream Ghostty equivalent); see docs/design/sighup-resistant-session.md for the full design.

Two failure modes, one experience

Scenario Event What survives
A: void only dies segfault, OOM, jetsam SIGKILL grid + per-pane terminal content
B: macOS dies kernel panic, hard shutdown, power loss same (bounded ≀ 1s loss)

How it works

       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚  macOS NSWindowRestoration (existing)    β”‚  ← grid topology + per-surface UUID
       β”‚  TerminalRestorable.swift                β”‚    survive force-quit / crash
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚  uuid round-trips via Codable
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚  PersistRing (mmap, 4 MB / pane)         β”‚  ← raw PTY byte stream β†’ disk
       β”‚  ~/.void/sessions/by-uuid/<uuid>.ring    β”‚    memcpy + msync(MS_ASYNC) every 1s
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚  on relaunch
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚  Termio.init replay β†’ processOutput      β”‚  ← bytes (ANSI + colors + cursor)
       β”‚  BEFORE io read thread starts            β”‚    fed back through SIMD parser
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Write side β€” Termio.processOutput appends every PTY byte to an mmap'd ring (memcpy, ~0Β΅s, lock-free per pane). msync(MS_ASYNC) fires every 1s β†’ kernel page cache + dirty-page flush bound Scenario B loss to ≀ 1 second. Scenario A loses nothing because mmap MAP_SHARED page cache survives process death.
  • Read side β€” at surface init, if a ring exists at the UUID-keyed path, PersistRing.replay() extracts up to 4 MB of most-recent bytes, and Termio.processOutputLocked feeds them through the parser before the io read thread spawns. The new shell still starts fresh underneath; the visual scrollback is reconstructed via ANSI replay.

Enable

# void config
window-save-state    = always     # macOS NSWindowRestoration (already documented)
persist-bytes-mmap   = true       # opt-in: enable per-pane ring buffer

What's restored / what isn't

βœ… Restored ❌ Not restored
scrollback text running processes (PTY child is fresh)
colors + text attributes (via ANSI escapes in byte stream) live cursor position from a long-running TUI
grid topology + per-pane cwd (via existing TerminalRestorable) environment variables that diverged at runtime
focused pane, tab color, title overrides sub-process state (vim buffers, REPL history, etc.)

Apple Terminal.app's "Tab Contents v2" mechanism is plain-text-only (no colors); void's ring is raw bytes including ANSI sequences, so attributes round-trip.

Manual recovery

If auto-replay doesn't trigger (e.g. UUID lost, ring schema changed), the byte stream is still on disk:

tool/void-session-replay.sh --list           # enumerate ring files
tool/void-session-replay.sh --latest         # dump most recent ring to stdout
tool/void-session-replay.sh --all            # dump every ring
tool/void-session-replay.sh <path-to-ring>   # dump a specific ring

Pipe to less -R, cat, or save to a file.

Storage layout

~/.void/sessions/by-uuid/
    <uuid>.ring   # 4 MB mmap'd ring buffer per pane
    ...

Ring files are not garbage-collected automatically β€” rm -rf ~/.void/sessions/by-uuid is safe between sessions when you want to start fresh.

Status

  • Beta β€” grid mode is the only implemented direction. P1 (grid mode + new-tab keybinding) complete (2026-05-18): surface rendering, NΓ—M auto-layout, slot-spawn, broadcast, per-cell cwd
  • Inherited from Ghostty (not Void-built): SIMD parser, Metal/OpenGL renderers, per-terminal threads, native Swift/GTK shells, crash reporter
  • Void-only support infra (shipped, not a "direction"): session-restore via per-pane mmap byte ring β€” see Session restore
  • Not yet implemented: AI-native I/O (roadmap P3) Β· perf-budget harness (roadmap P4) β€” described in this README as intent, not shipped behaviour
  • Fork date: 2026-04-21 (from upstream commit c3c8572f7); default branch void/main (not main)
  • L3 rename complete β€” 4698 files renamed Ghostty β†’ Void at commit 964c9e32e
  • Next: P4 perf baseline (capture Ghostty-baseline benches), then Show HN / r/commandline launch
  • CI: .github/workflows/build-fork.yml on GitHub-hosted macos-15 runners (ad-hoc codesign)

Repo layout

void/
β”œβ”€β”€ README.md
β”œβ”€β”€ AGENTS.md / AGENTS.tape         project ops manual + machine-readable companion
β”œβ”€β”€ VOID_FORK.md                    fork rationale + non-goals + upstream policy
β”œβ”€β”€ HACKING.md / CONTRIBUTING.md    dev + contribution guides
β”œβ”€β”€ LICENSE                         MIT
β”œβ”€β”€ build.zig / build.zig.zon       Zig build entry + manifest
β”œβ”€β”€ src/                            libvoid (Zig core) β€” parser Β· terminal state Β· renderer Β· grid  (agent I/O: roadmap)
β”œβ”€β”€ macos/                          Swift app (SwiftUI Β· AppIntents Β· Metal Β· CoreText)
β”œβ”€β”€ linux/ + gtk/                   GTK app (systemd Β· OpenGL Β· FreeType)
β”œβ”€β”€ pkg/                            vendored package wrappers
β”œβ”€β”€ include/                        C-ABI headers for libvoid embedders
β”œβ”€β”€ images/                         icon + brand assets (hexagon n=6 family)
β”œβ”€β”€ docs/                           reference docs + logo.svg
β”œβ”€β”€ conformance/                    terminal protocol conformance tests
β”œβ”€β”€ bench/                          perf budget harness β€” roadmap P4 (Ξ” vs Ghostty baseline)
β”œβ”€β”€ nix/ + flake.nix                Nix build entry
└── .github/workflows/              CI (build-fork.yml on macos-15 runners)

Contributing

Credits

Void is a hard fork of Ghostty by Mitchell Hashimoto and the Ghostty team. All Ghostty contributors are credited in upstream history, which is preserved in this repo. Divergent work β€” grid mode (implemented), plus the planned AI-native I/O and perf-harness directions β€” is Void-only.

License

MIT β€” same license as upstream Ghostty. All Ghostty contributors are credited in upstream history (preserved in this repo); divergent work (grid mode implemented; AI-native I/O and perf-harness planned) is Void-only.


⬑ Terminal as substrate. Grid as primitive. · Based on Ghostty · dancinlab