A Zig terminal multiplexer that displays 9 interactive terminal sessions in a 3×3 grid with smooth expand/collapse animations. Built on ghostty-vt for terminal emulation and SDL3 for rendering.
Warning
This project is in early stages of development. Use at your own risk.
The application is experimental and may have bugs, stability issues, or unexpected behavior. See Known Limitations for current shortcomings.
Download the latest release from the releases page.
For Apple Silicon (M1/M2/M3/M4):
curl -LO https://github.com/forketyfork/architect/releases/latest/download/architect-macos-arm64.tar.gz
tar -xzf architect-macos-arm64.tar.gz
xattr -dr com.apple.quarantine Architect.app
open Architect.appFor Intel Macs:
curl -LO https://github.com/forketyfork/architect/releases/latest/download/architect-macos-x86_64.tar.gz
tar -xzf architect-macos-x86_64.tar.gz
xattr -dr com.apple.quarantine Architect.app
open Architect.appNote:
- The archive contains
Architect.app. You can launch it withopen Architect.appor run./Architect.app/Contents/MacOS/architectfrom the terminal. Keep the bundle contents intact. - Not sure which architecture? Run
uname -m- if it showsarm64, use the ARM64 version; if it showsx86_64, use the Intel version.
Prerequisites: Xcode Command Line Tools must be installed:
xcode-select --installInstall via Homebrew (builds from source):
# Tap the repository (note: requires full repo URL since the formula is in the main repo)
brew tap forketyfork/architect https://github.com/forketyfork/architect
# Install architect
brew install architect
# Copy the app to your Applications folder
cp -r $(brew --prefix)/Cellar/architect/*/Architect.app /Applications/Or install directly without tapping:
brew install https://raw.githubusercontent.com/forketyfork/architect/main/Formula/architect.rb
cp -r $(brew --prefix)/Cellar/architect/*/Architect.app /Applications/The formula will:
- Build from source using Zig
- Install all required dependencies (SDL3, SDL3_ttf)
- Create Architect.app with bundled fonts and icon
- After copying to /Applications, launch from Spotlight or:
open -a Architect
See Setup section below for building from source.
- 3×3 Terminal Grid: Run 9 independent shell sessions simultaneously
- Smooth Animations: Click any terminal to smoothly expand it to full screen
- Full-Window Scaling: Each terminal is sized for the full window and scaled down in grid view
- Resizable Window: Dynamically resize the window with automatic terminal and PTY resizing
- Real-Time I/O: Non-blocking PTY communication with live updates
- Interactive Control:
- Click any grid cell or press ⌘+Return in grid view to expand
- Hold Esc for ~700ms to collapse back to grid; a quick tap is forwarded to the terminal
- Type in the focused terminal
- Keyboard Navigation: Move the grid focus with ⌘↑/↓/←/→ and open the on-screen shortcut overlay via the ? pill in the top-right corner
- Scrollback in Place: Hover any terminal and use the mouse wheel to scroll history; typing snaps back to live output and a yellow strip in grid view shows when you're scrolled
- High-Quality Rendering: SDL_ttf font rendering with SFNSMono (default system monospace font on macOS), glyph caching, vsync-aligned presentation (renders at display refresh rate), and cached grid tiles to reduce redraw work
- Persistent Configuration: Automatically saves and restores font size, font family, window dimensions, and window position
- Font Size Adjustment: Use Cmd+Plus/Minus (8–96px) to adjust font size (saved automatically)
- Link Opening: Cmd+Click on OSC 8 hyperlinks to open them in your default browser (cursor changes to pointer when hovering over links with Cmd held)
- Claude-friendly hooks: Unix domain socket for notifying Architect when a session is waiting for approval or finished; grid tiles highlight with a fat yellow border
- Session Recovery: A
Restartbutton appears on any grid tile whose shell exited, letting you respawn that session without quitting the app - Working Directory Bar: Grid tiles show the session’s current working directory with a marquee for long paths
- Nix with flakes enabled
-
(Optional) Pre-fetch the ghostty dependency to speed up the first build:
just setup
just setupcaches theghosttysource tarball; the regular build will fetch it automatically if you skip this step. -
Update the Nix flake and enter the development shell:
nix flake update nix develop
Alternatively, if using direnv:
direnv allow
-
Verify the environment:
zig version # Should show 0.15.2+ (compatible with ghostty-vt) just --list # Show available commands
Build the project:
just build
# or
zig buildBuild optimized release:
zig build -Doptimize=ReleaseFastRun the application:
just run
# or
zig build runArchitect automatically saves your preferences to ~/.config/architect/config.toml. The configuration is organized into sections:
- size: Font size in pixels (range: 8-96, default: 14) - Adjusted via Cmd+Plus/Minus shortcuts
- family: Font family name (default:
SFNSMonoon macOS)
- width: Window width in pixels
- height: Window height in pixels
- x: Window X position (-1 = system default)
- y: Window Y position (-1 = system default)
Window dimensions and position are automatically saved when you resize the window or adjust font size.
- background: Terminal background color as hex (default:
#0E1116) - foreground: Terminal text color as hex (default:
#CDD6E0) - selection: Selection highlight color as hex (default:
#1B2230) - accent: UI accent color as hex (default:
#61AFEF)
The 16 ANSI colors can be customized with named parameters:
Normal colors (0-7):
- black, red, green, yellow, blue, magenta, cyan, white
Bright colors (8-15):
- bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white
Each color is specified as a hex string (e.g., "#E06C75").
- rows: Number of terminal rows in the grid (range: 1-12, default: 3)
- cols: Number of terminal columns in the grid (range: 1-12, default: 3)
Grid size must be edited manually in the config file.
- vsync: Enable vertical sync (default:
true) - When enabled, frames render at display refresh rate
The configuration file is created automatically on first use and updated whenever settings change.
Fonts are loaded from macOS system directories, searched recursively:
/System/Library/Fonts/- System fonts (and subdirectories)/Library/Fonts/- System-wide installed fonts (and subdirectories)~/Library/Fonts/- User-installed fonts (and subdirectories)
Supported font formats:
.ttf- TrueType fonts.otf- OpenType fonts.ttc- TrueType Collection (multiple variants in one file)
Naming patterns searched (in order):
{font_family}-{style}.{ext}(e.g.,VictorMonoNerdFont-Bold.ttf){font_family}{style}.{ext}(e.g.,SFNSMonoBold.ttf){font_family}.{ext}for Regular style (e.g.,Monaco.ttf){font_family}.ttc- TTC file containing all variants
Examples of supported fonts:
| Font | Location | Type |
|---|---|---|
SFNSMono |
/System/Library/Fonts/SFNSMono.ttf |
Separate TTF files |
Menlo |
/System/Library/Fonts/Menlo.ttc |
TTC with all variants |
Monaco |
/System/Library/Fonts/Monaco.ttf |
Single TTF (no variants) |
VictorMonoNerdFont |
/Library/Fonts/Nix Fonts/.../VictorMonoNerdFont-Regular.ttf |
Nerd Font in subdirectory |
Fallback behavior:
If a requested font isn't found, the app falls back to SFNSMono with a warning:
warning(font_paths): Font family 'MyFont' not found, falling back to SFNSMono
If style variants (Bold, Italic, BoldItalic) aren't found:
- For TTC files: Uses the same TTC file for all variants (SDL_ttf loads correct variant)
- For TTF/OTF: Falls back to default font's variant
- Last resort: Uses Regular variant
Example configuration:
[font]
size = 16
family = "VictorMonoNerdFont"
[window]
width = 1920
height = 1080
x = 150
y = 100
[theme]
background = "#1E1E2E"
foreground = "#CDD6F4"
accent = "#89B4FA"
selection = "#313244"
# Optional: custom ANSI palette colors (example: Catppuccin Mocha)
[theme.palette]
black = "#45475A"
red = "#F38BA8"
green = "#A6E3A1"
yellow = "#F9E2AF"
blue = "#89B4FA"
magenta = "#F5C2E7"
cyan = "#94E2D5"
white = "#BAC2DE"
bright_black = "#585B70"
bright_red = "#F38BA8"
bright_green = "#A6E3A1"
bright_yellow = "#F9E2AF"
bright_blue = "#89B4FA"
bright_magenta = "#F5C2E7"
bright_cyan = "#94E2D5"
bright_white = "#A6ADC8"
[grid]
rows = 3
cols = 4
[rendering]
vsync = trueDebugging font loading:
Run the app and check logs to see which fonts were found:
info(font_paths): Found font: /Library/Fonts/.../VictorMonoNerdFont-Regular.ttf
info(font_paths): Found font: /Library/Fonts/.../VictorMonoNerdFont-Bold.ttf
info(font_paths): Found font: /Library/Fonts/.../VictorMonoNerdFont-Italic.ttf
info(font_paths): Found font: /Library/Fonts/.../VictorMonoNerdFont-BoldItalic.ttf
Or for TTC files:
info(font_paths): Found font: /System/Library/Fonts/Menlo.ttc
info(font_paths): Using TTC file for Bold variant: /System/Library/Fonts/Menlo.ttc
info(font_paths): Using TTC file for Italic variant: /System/Library/Fonts/Menlo.ttc
info(font_paths): Using TTC file for BoldItalic variant: /System/Library/Fonts/Menlo.ttc
To reset to defaults, simply delete the configuration file:
rm ~/.config/architect/config.tomlRun tests:
just test
# or
zig build testCheck code formatting:
just lint
# or
zig fmt --check src/Format code:
zig fmt src/- Geometry + hit testing helpers live in
src/geom.zig. - Shared easing functions live in
src/anim/easing.zig. - Rounded/thick border drawing helpers live in
src/gfx/primitives.zig; use these instead of redefining SDL primitives in new UI components. - The UI framework entrypoint is
src/ui/:UiRoothandles event dispatch, per-frame updates, and overlay rendering for registered UI components. - Architecture and layering overview: see
docs/architecture.md. - For scrolling text overlays, reuse
src/ui/components/marquee_label.zig.
Architect integrates with AI coding assistants through a Unix domain socket protocol. Grid tiles automatically highlight when an assistant is waiting for approval (pulsing yellow border) or has completed a task (solid green border).
- Notification socket: Architect listens on
${XDG_RUNTIME_DIR:-/tmp}/architect_notify_<pid>.sock(Unix domain socket, mode 0600, where<pid>is the process ID). - Per-shell env: Each spawned shell receives
ARCHITECT_SESSION_ID(0‑based grid index) andARCHITECT_NOTIFY_SOCK(socket path) so tools inside the terminal can send status. - Protocol: Send a single-line JSON object to the socket:
{"session":0,"state":"start"}clears the highlight and marks the session as running.{"session":0,"state":"awaiting_approval"}turns on a pulsing yellow border in the 3×3 grid (request).{"session":0,"state":"done"}shows a solid green border in the grid (completion).
Example from inside a terminal session:
python - <<'PY'
import json, socket, os
sock = os.environ["ARCHITECT_NOTIFY_SOCK"]
msg = json.dumps({"session": int(os.environ["ARCHITECT_SESSION_ID"]), "state": "awaiting_approval"}) + "\n"
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(sock)
s.sendall(msg.encode())
s.close()
PYExample from outside (host):
# Find the socket (PID is included in the filename)
SOCK=$(ls ${XDG_RUNTIME_DIR:-/tmp}/architect_notify_*.sock 2>/dev/null | head -1)
# Send notification for session 0
python - <<PY
import json, socket, os
sock = os.environ["SOCK"]
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(sock)
s.sendall(json.dumps({"session":0,"state":"done"}).encode() + b"\n")
s.close()
PYTo automatically send notifications when Claude Code stops or requests approval:
-
Copy the
architect_notify.pyscript from the repository root to your Claude config directory:cp architect_notify.py ~/.claude/architect_notify.py chmod +x ~/.claude/architect_notify.py
This script is included in the Architect repository and handles notifications for all supported AI assistants.
-
Add hooks to your
~/.claude/settings.json:{ "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "python3 ~/.claude/architect_notify.py done || true" } ] } ], "Notification": [ { "hooks": [ { "type": "command", "command": "python3 ~/.claude/architect_notify.py awaiting_approval || true" } ] } ] } } -
Run Architect and start Claude Code in one of the terminal sessions. The grid cell will automatically highlight when Claude requests approval or completes a task.
To automatically send notifications when Codex requests approval or completes a task:
-
Create a notification script at
~/.codex/notify.py:#!/usr/bin/env python3 import json, os, subprocess, sys HOME = os.environ.get("HOME", "") ARCHITECT_NOTIFY = [ "python3", os.path.join(HOME, "path/to/architect/architect_notify.py"), ] def route_to_architect(notification: dict) -> None: ntype = (notification.get("type") or "").lower() state = None if ntype == "agent-turn-complete": state = "done" elif "approval" in ntype or "permission" in ntype: state = "awaiting_approval" elif "input" in ntype and "await" in ntype: state = "awaiting_approval" if state is None: return try: subprocess.run(ARCHITECT_NOTIFY + [state], check=False) except Exception: pass def main() -> int: notification = json.loads(sys.argv[1]) route_to_architect(notification) return 0 if __name__ == "__main__": sys.exit(main())
-
Update the path to
architect_notify.pyin the script to match your repository location. -
Add the
notifysetting to your~/.codex/config.toml:notify = ["python3", "/Users/your-username/.codex/notify.py"]
-
Run Architect and start Codex in one of the terminal sessions. The grid cell will automatically highlight when Codex requests approval or completes a task.
To automatically send notifications when Gemini CLI requests approval or completes a task:
-
Copy the notification scripts from the repository:
cp architect_notify.py ~/.gemini/architect_notify.py cp architect_hook_gemini.py ~/.gemini/architect_hook.py chmod +x ~/.gemini/architect_notify.py ~/.gemini/architect_hook.py
Note: Gemini CLI hooks require special handling because they receive JSON via stdin and must output JSON to stdout. The
architect_hook.pywrapper handles this protocol and calls the sharedarchitect_notify.pyscript. -
Add hooks to your
~/.gemini/settings.json:{ "hooks": { "AfterAgent": [ { "matcher": "*", "hooks": [ { "name": "architect-completion", "type": "command", "command": "python3 ~/.gemini/architect_hook.py done", "description": "Notify Architect when task completes" } ] } ], "Notification": [ { "matcher": "*", "hooks": [ { "name": "architect-approval", "type": "command", "command": "python3 ~/.gemini/architect_hook.py awaiting_approval", "description": "Notify Architect when waiting for approval" } ] } ] }, "tools": { "enableHooks": true } }Important: The
"tools": {"enableHooks": true}setting is required to enable hooks in Gemini CLI. -
Run Architect and start Gemini CLI in one of the terminal sessions. The grid cell will automatically highlight when Gemini requests approval or completes a task.
Note: Gemini CLI hooks use a different protocol than Claude Code and Codex. The matcher field is required, and hooks must read JSON from stdin and output JSON to stdout. See the Gemini CLI hooks documentation for more details.
macOS release binaries are automatically built for both ARM64 (Apple Silicon) and x86_64 (Intel) architectures via GitHub Actions when a version tag is pushed:
git tag v0.1.0
git push origin v0.1.0Each release includes:
architect-macos-arm64.tar.gz- For Apple Silicon Macs (M1/M2/M3/M4)architect-macos-x86_64.tar.gz- For Intel Macs
Download the latest release from the releases page.
src/main.zig- Main application with SDL3 event loop and animation systemsrc/shell.zig- Shell process spawning and managementsrc/pty.zig- PTY abstractions and utilitiessrc/font.zig- Font rendering with SDL_ttf and glyph cachingsrc/font_paths.zig- Font path resolution from macOS system font directoriessrc/config.zig- Configuration persistence (font, window, and theme settings)src/c.zig- C library bindings for SDL3build.zig- Zig build configuration with SDL3 dependenciesbuild.zig.zon- Zig package dependenciesdocs/- Documentation and implementation plansjustfile- Convenient command shortcutsflake.nix- Nix development environment.github/workflows/- CI/CD workflows (build and release)
- ghostty-vt: Terminal emulation library from
ghostty-org/ghostty, fetched as a pinned tarball via Zig package manager (seebuild.zig.zon)- Provides terminal state machine and ANSI escape sequence parsing
- SDL3: Window management and rendering backend (via Nix)
- SDL3_ttf: Font rendering library (via Nix)
Each terminal session is initialized with full-window dimensions (calculated from font metrics). In grid view, these full-sized terminals are scaled down to 1/3 and rendered into grid cells, providing a "zoomed out" view of complete terminal sessions.
The application uses cubic ease-in-out interpolation to smoothly transition between grid and full-screen views over 300ms. Six view modes (Grid, Expanding, Full, Collapsing, PanningLeft, PanningRight) manage the animation state, including horizontal panning for terminal switching.
- Font glyphs are rendered to cached SDL textures
- Terminal cells are iterated and glyphs drawn at scaled positions
- Content is clipped to grid cell boundaries
- Borders indicate focus state
✅ Fully Implemented:
- 3×3 grid layout with 9 terminal sessions
- PTY management and shell spawning
- Real-time terminal I/O
- SDL3 window and event loop with resizable window support
- Font rendering with SDL_ttf
- Click-to-expand interaction
- Smooth expand/collapse animations
- Keyboard input handling
- Full-window terminal scaling
- Dynamic terminal and PTY resizing on window resize
- Persistent configuration (font, window, and theme/color settings)
- Font size adjustment via keyboard shortcuts (Cmd+Plus/Minus)
- Claude Code integration via Unix domain sockets
- Scrolling back through terminal history (mouse wheel) with a grid indicator when a pane is scrolled
- Text selection in full view with clipboard copy/paste (drag, ⌘C / ⌘V)
- Cmd+Click to open hyperlinks (OSC 8) in your default browser
The following features are not yet fully implemented:
- Emoji coverage is macOS-only: Apple Color Emoji fallback is used; other platforms may still show tofu or monochrome glyphs for emoji and complex ZWJ sequences.
- Limited font distribution: Only the bundled font family ships with the app today
- Limited configurability: Keybindings are hardcoded
MIT

