ghost-tab
v2.7.1
Published
Terminal + tmux wrapper for AI coding tools (Claude Code, Codex CLI, Copilot CLI, OpenCode)
Maintainers
Readme
Ghost Tab
A Ghostty + tmux wrapper that launches a four-pane dev session with Claude Code, lazygit, broot, and a spare terminal. Automatically cleans up all processes when the window is closed — no zombie Claude Code processes.

Quick Start
npx ghost-tabThat's it — only requirements are macOS and Node.js 16+. Everything (Ghostty, tmux, lazygit, broot, Claude Code) is installed automatically.
Usage
Step 1. Open a new Ghostty window (Cmd+N)
Step 2. Use the interactive project selector:
⬡ Ghost Tab
──────────────────────────────────────
1❯ my-app
~/Projects/my-app
2 another-project
~/Projects/another-project
──────────────────────────────────────
A Add new project
D Delete a project
O Open once
P Plain terminal
──────────────────────────────────────
↑↓ navigate ⏎ select- Arrow keys or mouse click to navigate
- Number keys (1-9) to jump directly to a project
- Letter keys — A add, D delete, O open once, P plain terminal
- Enter to select
- Path autocomplete when adding projects (with Tab completion)
- Plain terminal opens a bare shell with no tmux overhead
Step 3. The four-pane tmux session launches automatically with Claude Code already focused — start typing your prompt right away.
[!TIP] You can also open a specific project directly from the terminal:
~/.config/ghostty/claude-wrapper.sh /path/to/project
Hotkeys
| Shortcut | Action |
|---|---|
| Cmd+T | New tab |
| Cmd+Shift+Left | Previous tab |
| Cmd+Shift+Right | Next tab |
| Left Option | Acts as Alt instead of typing special characters |
What ghost-tab Does
- Downloads
tmux,lazygit,broot, andjqnatively (no package manager required) - Installs
Claude Codevia native installer (auto-updates) - Prompts to install
Ghosttyfrom ghostty.org if not already installed - Sets up the
Ghosttyconfig (with merge option if you have an existing one) - Walks you through adding your project directories
- Installs
Node.jsLTS (if needed) and sets up Claude Code status line showing git info and context usage - Auto-updates automatically — just run
npx ghost-tabagain to get the latest version
Status Line
The ghost-tab command configures a custom Claude Code status line based on Matt Pocock's guide:
my-project | main | S: 0 | U: 2 | A: 1 | 23.5%- Repository name — current project
- Branch — current git branch
- S — staged files count
- U — unstaged files count
- A — untracked (added) files count
- Context % — how much of Claude's context window is used
[!TIP] Monitor context usage to know when to start a new conversation. Lower is better.
Process Cleanup
[!CAUTION] When you close the
Ghosttywindow, all processes are force-terminated — make sure your work is saved.
The wrapper automatically:
- Recursively kills the full process tree of every
tmuxpane (including deeply nested subprocesses spawned byClaude Code,lazygit, etc.) - Force-kills (
SIGKILL) any processes that ignored the initialSIGTERMafter a brief grace period - Destroys the
tmuxsession - Self-destructs the session via
destroy-unattachedif thetmuxclient disconnects without triggering cleanup
This prevents zombie Claude Code processes from accumulating.
Architecture
Ghost Tab uses a hybrid architecture:
Layer 1: Go TUI Binary (ghost-tab-tui)
- Interactive terminal UI components built with Bubbletea
- Project selector, AI tool selector, settings menu, input forms
- Outputs structured JSON for bash consumption
- Binary:
~/.local/bin/ghost-tab-tui
Layer 2: Bash Orchestration (ghost-tab)
- Entry point and session orchestration
- Process management, config file operations
- Calls ghost-tab-tui for interactive parts
- Parses JSON responses with jq
- Script:
~/.local/bin/ghost-tab
Dependencies:
- Go 1.21+ (for building)
- jq (for JSON parsing)
- tmux (session management)
- Ghostty (terminal emulator)
Communication:
# Bash calls Go with subcommand
result=$(ghost-tab-tui select-project --projects-file ~/.config/ghost-tab/projects)
# Go returns JSON
{"name": "my-project", "path": "/home/user/code/my-project", "selected": true}
# Bash parses with jq
project_name=$(echo "$result" | jq -r '.name')