Terminal-native autocomplete engine using PTY proxying for macOS terminals.
Ghost Complete sits inside your terminal's data stream as a PTY proxy, intercepting I/O between your terminal emulator and your shell. When you type a command, it renders autocomplete suggestions as native ANSI popups — no macOS Accessibility API, no IME hacks, no Electron overlay. Just your terminal, your shell, and fast completions.
Inspired by the Fig autocomplete experience. Built from scratch in Rust.
Zstd compression preserves the embedded 711-spec corpus while shrinking the benchmarked macOS arm64 release binary from 103.41 MB to 11.81 MB.
Ghost Complete is under active development. Contributions and bug reports are welcome.
Found a bug? Open an issue.
brew install StanMarek/tap/ghost-complete
ghost-complete install
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/StanMarek/ghost-complete/releases/latest/download/ghost-complete-installer.sh | sh
ghost-complete install
cargo install --git https://github.com/StanMarek/ghost-complete.git
ghost-complete install
git clone https://github.com/StanMarek/ghost-complete.git
cd ghost-complete
cargo build --release
cp target/release/ghost-complete ~/.cargo/bin/
ghost-complete install
ghost-complete install does~/.zshrc (auto-wraps your shell via PTY proxy)~/.config/ghost-complete/shell/~/.config/ghost-complete/specs/~/.config/ghost-complete/config.toml (never overwrites existing)ghost-complete uninstall
brew uninstall ghost-complete # if installed via Homebrew
After installation, restart your terminal. Ghost Complete activates automatically in zsh.
Run ghost-complete status to see loaded specs and generator diagnostics.
Ghost Complete auto-detects your terminal and selects the best rendering strategy. All supported terminals work out of the box — no config flag needed.
| Terminal | Rendering | Prompt Detection | tmux Support |
|---|---|---|---|
| Ghostty | Synchronized (DECSET 2026) | OSC 133 (native) | Yes |
| Kitty | Synchronized (DECSET 2026) | OSC 133 (native) | Yes |
| WezTerm | Synchronized (DECSET 2026) | OSC 133 (native) | Yes |
| Alacritty | Synchronized (DECSET 2026) | Shell integration | Yes |
| Rio | Synchronized (DECSET 2026) | OSC 133 (native) | — |
| iTerm2 | Pre-render buffer | Shell integration | Yes |
| Terminal.app | Pre-render buffer | Shell integration | No |
| Zed | Synchronized (DECSET 2026) | OSC 133 (native) | Yes |
| VSCode (and forks) | Synchronized (DECSET 2026) | OSC 133 (native) | Yes |
Notes:
- Terminal.app inside tmux is not detected (it sets no env var that leaks through tmux).
- Alacritty does not support OSC 133 natively; Ghost Complete uses its own shell integration markers instead. No functional difference — just a different detection path.
- VSCode detection covers all Electron-based VSCode forks: VSCodium, Cursor, Windsurf, Positron, Trae. They share the xterm.js frontend and shell integration model. Ghost Complete coexists with VSCode's own shell integration (OSC 633) — the proxy forwards editor sequences untouched so command decorations, sticky scroll, and "run recent command" continue to work.
- Unsupported terminals can be enabled with [experimental] multi_terminal = true in config.
Ghost Complete running inside Zed and VSCode's integrated terminals.
Config lives at ~/.config/ghost-complete/config.toml:
The snippet below is illustrative — the install-time default config is generated by ghost-complete install and covers every supported option. For the exhaustive reference see docs/CONFIGURATION.md.
[trigger]
auto_chars = [' ', '/', '-', '.']
delay_ms = 150
[popup]
max_visible = 10
[keybindings]
accept = "tab"
dismiss = "escape"
trigger = "ctrl+/"
[theme]
preset = "dark" # dark, light, catppuccin, material-darker
[suggest]
max_results = 50
max_history_results = 5
[suggest.providers]
commands = true
filesystem = true
specs = true
git = true
Theme, keybindings, trigger chars, and popup dimensions are hot-reloaded. Other changes need a shell restart.
See docs/CONFIGURATION.md for the full reference.
Ghost Complete ships with 711 Fig-compatible JSON completion specs covering git, docker, cargo, npm, kubectl, brew, curl, ssh, and 700+ more — converted from the Fig autocomplete ecosystem.
Beyond specs, built-in providers offer:
- Environment variables — echo $HOM → $HOME
- SSH hosts — parsed from ~/.ssh/config with mtime caching
- Shell alias resolution — alias g=git → g push uses the git spec
- Frecency-ranked history — frequently/recently used commands score higher
Many specs include dynamic generators that run shell commands for live results (e.g., brew list, docker ps, kubectl get). Generator results are cached with configurable TTL. A loading indicator (...) appears while generators run. Specs that originally relied on inline JavaScript (Fig postProcess, script: () => [...], custom: async () => [...]) execute through the embedded gc-jsrt runtime — see docs/JS_RUNTIME.md for the sandbox model.
Custom specs go in ~/.config/ghost-complete/specs/. See docs/COMPLETION_SPEC.md for the format reference.
Rust workspace with 9 crates:
| Crate | Role |
|---|---|
ghost-complete |
Binary entry point, CLI, install/uninstall |
gc-pty |
PTY proxy event loop (portable-pty + tokio) |
gc-parser |
VT escape sequence parsing (vte), cursor/prompt tracking |
gc-buffer |
Command line reconstruction, context detection |
gc-suggest |
Suggestion engine with fuzzy ranking (nucleo) |
gc-overlay |
ANSI popup rendering with synchronized output |
gc-config |
TOML config, keybindings, themes |
gc-terminal |
Terminal detection, capability profiling, render strategy selection |
gc-jsrt |
Bounded QuickJS evaluator for requires_js specs (rquickjs) |
See docs/ARCHITECTURE.md for the full design — data flow, dependency graph, key design decisions, and performance characteristics.
| Feature | zsh | bash | fish |
|---|---|---|---|
| Auto-trigger on typing | Yes | No | No |
| Ctrl+/ manual trigger | Yes | Yes | Yes |
| PTY proxy wrapping | Yes | Yes | Yes |
| OSC 133 prompt markers | Yes | Yes | Yes |
GHOSTTY_RESOURCES_DIR, KITTY_WINDOW_ID, WEZTERM_UNIX_SOCKET, ALACRITTY_SOCKET, ITERM_SESSION_ID).gc-pty. The first paint is gated by popup.render_block_ms (default 80ms, range 0-300ms): set to 0 for instant paint with later merging, or higher to race fast generators into the same frame as static flags.requires_js: true are evaluated by the embedded gc-jsrt runtime (QuickJS via rquickjs, default on). The sandbox enforces resource caps (memory, stack, time) and a restricted host API; long-running native operations (pathological regex, large JSON.parse) are not preempted at the exact deadline. The runtime can be disabled wholesale via [suggest.providers] js_runtime = false. See docs/JS_RUNTIME.md.How is this different from zsh/fish built-in autocomplete?
Built-in completions work great — Ghost Complete doesn't replace them. It adds a visual popup layer on top, like the difference between typing from memory and having an IDE dropdown. Suggestions are fuzzy-ranked from multiple sources (completion specs, filesystem, git branches, command history) and displayed in a single view. Think of it as complementary, not a replacement.
Why a PTY proxy instead of a zsh plugin?
The PTY proxy sits between the terminal and the shell, rendering popups via pure ANSI escape sequences. This means no zle widget conflicts, no plugin manager dependencies, no RPROMPT corruption, and no fragile shell internals to hook into. It's more complex under the hood, but the UX is cleaner — one binary, works immediately after install.
Why custom JSON specs instead of using the shell's built-in completions?
Specs are declarative and fast — microsecond loads, no shell execution. They use the same format Fig used, so there's a large existing ecosystem to draw from. Ghost Complete ships with 711 specs today, and many include dynamic generators that execute shell commands for live results (e.g., listing running containers, git branches, installed packages). Commands without a spec fall back to filesystem completions. Adding new specs is straightforward — see docs/COMPLETION_SPEC.md, and contributions are welcome.
Where's the config documentation? I'm having popup alignment issues.
Full config reference lives at docs/CONFIGURATION.md. Running ghost-complete install generates a commented default config at ~/.config/ghost-complete/config.toml with all available options.
For popup alignment: Ghost Complete uses ANSI cursor positioning within the terminal grid, so popups always track the cursor position directly. This avoids the window-level coordinate issues that plague Accessibility API approaches (the kind of drift reported with tools like Amazon Q / Kiro). If popups are misaligned, it's likely a terminal compatibility issue — please open an issue with your setup details.
Ghost Complete logs through tracing. In proxy mode the default sink is a file under $XDG_STATE_HOME/ghost-complete/ghost-complete.log (falling back to ~/.local/state/ghost-complete/ghost-complete.log when XDG_STATE_HOME is unset). stderr is not used by default in proxy mode, so log output never corrupts the terminal stream.
--log-level <trace|debug|info|warn|error> sets the level (default: warn). Level hierarchy: error < warn < info < debug < trace.--log-file <path> overrides the default log path.RUST_LOG takes precedence over --log-level. It supports per-crate filters, e.g. RUST_LOG=gc_suggest=debug,gc_pty=info.Tail the log in real time:
tail -f "${XDG_STATE_HOME:-$HOME/.local/state}/ghost-complete/ghost-complete.log"
Reporting a bug: run with --log-level debug, reproduce the issue, and attach the log file to your issue.
See docs/CONFIGURATION.md for the full reference.
See CONTRIBUTING.md.
$ claude mcp add ghost-complete \
-- python -m otcore.mcp_server <graph>