montanaflynn/headless-terminal: Puppeteer for TUIs and AI Agents
montanaflynn/headless-terminal: Puppeteer for TUIs and AI Agents
Interactive terminal applications — vim, emacs, htop, nethack, REPLs, debuggers — assume a human at a keyboard. That assumption breaks the moment you want an AI agent, a CI pipeline, or an automated test to drive them. The shell alone won't help: it lacks a pseudo-terminal, a VT parser to interpret screen state, and synchronization primitives to know when the TUI has finished redrawing. montanaflynn/headless-terminal, or ht, is a Go CLI backed by libghostty-vt that solves exactly this problem. It spawns TUIs in headless sessions, sends keystrokes, snapshots rendered output, and even streams sessions live — giving developers the same kind of programmatic control over terminal UIs that Puppeteer provides for browsers.
What is montanaflynn/headless-terminal?
montanaflynn/headless-terminal is an open-source tool (113 GitHub stars, MIT License, last commit April 23, 2026) that provides Puppeteer-style automation for terminal UIs. Written in Go with a Unix-socket daemon architecture, it wraps three low-level primitives most developers never want to build themselves: PTY allocation, VT stream parsing, and screen-state synchronization.
The project is maintained by Montana Flynn and builds directly on libghostty-vt, the terminal emulation library from the Ghostty terminal app. This is a deliberate, significant choice — Ghostty's VT parser is battle-tested and actively developed, meaning ht inherits robust handling of cursor positioning, scrollback, styles, alternate screen buffers, and the full complexity of modern terminal output. The binary statically links libghostty-vt and weighs roughly 6MB with only libc as a runtime dependency.
The tool arrives at a relevant moment. AI agents increasingly need to interact with software that only exposes a TUI — git add -p, gh auth login, language REPLs, editors for surgical file modifications. Existing solutions like expect or pexpect struggle with alternate screen mode, color codes, and cursor-aware applications. ht fills this gap with a clean CLI interface and a daemon that manages session lifecycle independently.
Key Features
PTY-per-session daemon. Each TUI runs in its own pseudo-terminal owned by a background daemon communicating over Unix sockets. Sessions survive the launching shell and can be driven, watched, or snapshotted from any terminal on the same machine.
libghostty-vt terminal emulation. Output streams pass through the same VT parser used by the Ghostty terminal application. This provides authoritative screen grids with correct handling of cursor position, styles, scroll regions, and alternate screen — not raw byte streams that downstream tools must re-parse.
Multiple output formats. The ht view command renders snapshots as plain text, ANSI-colored text, HTML, PNG images, or JSON. This flexibility supports CI assertions (grep plain text), documentation (PNG for READMEs), and programmatic consumption (JSON for agent pipelines).
Vim-style key notation. Keystrokes use familiar bracket syntax: <CR>, <Esc>, <C-c>, <M-x>, <F1> through <F12>, <S-Tab>, and modifier combinations like <C-M-x>. Literal < is escaped as <lt>. This is the same notation developers already use in Vim and Neovim configurations, reducing cognitive load.
Synchronization primitives. ht send offers multiple wait strategies: pacing with configurable per-keystroke delays (--rate), post-send sleeps (--wait-duration), and deterministic conditions (--wait-text, --wait-cursor, --wait-idle, --wait-change, --wait-exit). These compose with AND logic, letting scripts reliably snapshot after the TUI has stabilized.
Live streaming with ht watch. Block until a session exists, then stream its output live to another terminal. Useful for shoulder-surfing agent behavior during skill development or pair debugging.
Session recording. ht record captures sessions as asciicast files, compatible with agg for GIF generation — useful for documentation, demos, and bug reports.
Use Cases
Agentic coding workflows. AI agents that need to modify files through vim, authenticate via interactive CLIs like gh auth login, or scaffold projects with create-next-app can drive these TUIs programmatically. The agent skill included in skills/headless-terminal/ teaches when to reach for ht, key notation conventions, and wait-strategy decision trees — the part agents most often get wrong.
CI testing for terminal applications. Script interactive programs in GitHub Actions: boot the TUI, send keystrokes, assert against rendered screen state. Unlike expect/pexpect, ht handles alternate screen mode, colors, and cursor position correctly. A smoke test might run vim, insert text, and grep the snapshot for expected output.
Documentation and demo generation. Record keystroke-perfect terminal sessions with ht record, render to GIF via agg, or capture one-shot PNG frames for READMEs and bug reports. The deterministic, scriptable nature eliminates the typos and timing inconsistencies of manual recording.
Follow-along debugging. When an agent or detached process drives a TUI, ht watch lets a human observe in real-time from another terminal pane. The watcher blocks until the named session appears, then mirrors output live — no race conditions between setup and observation.
Installation & Setup
The fastest path is Homebrew:
brew install montanaflynn/tap/ht
For manual installation from release binaries:
macOS (Apple Silicon):
curl -L https://github.com/montanaflynn/headless-terminal/releases/latest/download/ht-v0.1.0-darwin-arm64.tar.gz | tar xz
sudo mv ht /usr/local/bin/
Linux (x86_64):
curl -L https://github.com/montanaflynn/headless-terminal/releases/latest/download/ht-v0.1.0-linux-amd64.tar.gz | tar xz
sudo mv ht /usr/local/bin/
Linux (arm64):
curl -L https://github.com/montanaflynn/headless-terminal/releases/latest/download/ht-v0.1.0-linux-arm64.tar.gz | tar xz
sudo mv ht /usr/local/bin/
Note: Update the version segment when newer releases are available. The binary is approximately 6MB and statically links libghostty-vt.
Building from source requires Zig 0.15.2, CMake, pkg-config, and Go 1.22+:
git clone https://github.com/montanaflynn/headless-terminal
cd headless-terminal
make build
The build orchestrates two phases: CMake fetches Ghostty at a pinned commit and builds libghostty-vt.a with Zig; then Go compiles ./ht with cgo, linking the static library via pkg-config. This pins the VT parser version for reproducible builds.
Real Code Examples
Driving vim from an agent or script:
# Start a headless vim session, returns a short session ID.
ht run --name notes vim /tmp/notes.md
# Drive it. Keys use vim-style notation.
ht send notes "ihello from an agent<Esc>:wq<CR>" --view
# Session exited and the file is saved:
cat /tmp/notes.md
# → hello from an agent
# Remove the session completely
ht remove notes
This demonstrates the core workflow: run to create, send to drive with --view for immediate feedback, then remove for cleanup. The --view flag returns the current screen after sending keys, letting callers verify state without a separate command.
CI smoke test with deterministic waits:
# Boot a TUI, send keys, fail the build if the screen doesn't match.
ht run --name smoke vim /tmp/demo.md
ht send smoke "ihello from CI<Esc>" --wait-idle 200ms
ht view smoke | grep -q "hello from CI" || { echo "render failed"; exit 1; }
ht send smoke ":q!<CR>"
Here --wait-idle 200ms blocks until output has been quiet for 200 milliseconds, ensuring vim has finished redrawing before the snapshot. The || construct turns a grep miss into a CI failure.
Capturing a PNG screenshot:
# Drive a session, then grab a PNG of the current frame.
ht run --name demo bash
ht send demo "echo 'headless terminal'<CR>" --wait-idle 200ms
ht view demo --format png > screenshot.png
ht stop demo
This pattern — run, interact, snapshot, stop — is useful for automated documentation generation or visual regression testing of CLI tools.
Live streaming with ht watch:
# Pane A: the watcher blocks until a matching session is created.
ht watch nethack-demo
# Pane B (or an agent): create the session the watcher is waiting for.
ht run --size 78x46 --name nethack-demo nethack -u Claude
ht send nethack-demo "y" --wait-duration 150ms --view
# (pane A now shows nethack, live)
The --size 78x46 sets terminal dimensions before spawning, critical for TUIs that adapt layout to available space. The watcher in pane A automatically connects once the session exists.
Advanced Usage & Best Practices
Prefer deterministic waits over fixed sleeps. The README emphasizes that agents most often fail on wait strategy selection. --wait-text combined with --wait-idle is more reliable than --wait-duration for most cases, since it adapts to actual TUI render time rather than worst-case guessing.
Use named sessions for agent workflows. The --name flag produces stable identifiers that agents can reference without parsing short hex IDs from ht run output. This simplifies error recovery and logging.
Size matters. Set --size explicitly when the TUI layout depends on terminal dimensions — nethack, htop, and many full-screen applications behave differently at 80x24 versus 120x40. The default may not match your assertion expectations.
Clean up exited sessions. ht remove deletes session records; without it, metadata accumulates in the daemon. For CI environments, consider a final ht stop or ht kill followed by ht remove in a trap or finally block.
Consider the agent skill. The skills/headless-terminal/ directory contains an Anthropic-standard skill with progressive disclosure: SKILL.md stays in context, reference docs load on demand. If your agent framework supports the skills format, this reduces prompt engineering for TUI automation. [INTERNAL_LINK: AI agent tooling for developers]
Comparison with Alternatives
| Tool | Approach | Best For | Limitation |
|---|---|---|---|
| montanaflynn/headless-terminal | PTY + libghostty-vt daemon with snapshots | AI agents, CI testing, documentation of full TUIs | Young project (113 stars), single maintainer |
| expect / pexpect | Pattern matching on output streams | Simple interactive scripts, password prompts | No screen grid model; breaks on alternate screen, colors, cursor apps |
| tmux capture-pane | Attach to existing tmux session, dump pane | Ad-hoc inspection of long-running sessions | Requires tmux; not designed for programmatic keystroke injection |
| asciinema rec | Terminal session recording | Human-driven demos, playback | No programmatic control; no snapshot or assertion capabilities |
expect and pexpect remain viable for line-oriented programs but fail for TUIs using alternate screen or cursor positioning — exactly the gap ht targets. tmux can capture output but lacks the structured session management and synchronization primitives of a purpose-built automation layer. ht trades ecosystem maturity for architectural fit with modern TUI automation needs.
FAQ
What license is montanaflynn/headless-terminal released under? MIT License, permitting commercial and derivative use.
Does it work on Windows? The README specifies Unix-socket daemon and PTY usage; Windows compatibility is not documented. Assume Unix-like systems only.
How heavy is the binary?
Approximately 6MB, statically linked with libghostty-vt, depending only on libc at runtime.
Can I drive any TUI, or only specific ones? Any TUI that runs in a terminal — vim, emacs, htop, nethack, REPLs, debuggers, interactive installers. The PTY + VT parser approach is generic.
What Go version is required to build from source? Go 1.22 or later, plus Zig 0.15.2, CMake, and pkg-config.
How do I teach my AI agent to use ht?
Install the skill from skills/headless-terminal/ via npx skills add or copy to your agent's skills directory. It covers key notation, wait strategies, and common recipes.
Is the daemon automatically managed?
Normally auto-started; ht daemon [stop] provides manual control when needed.
Conclusion
montanaflynn/headless-terminal fills a specific, growing need: programmatic control over terminal UIs that existing automation tools cannot reliably handle. By combining PTY sessions, Ghostty's proven VT parser, and thoughtful synchronization primitives, it gives AI agents, CI pipelines, and documentation workflows a stable foundation for driving vim, emacs, and any other interactive terminal application.
The project is early — 113 stars, version 0.1.0 — but the architecture is sound and the problem it solves is increasingly unavoidable as agents penetrate deeper into developer workflows. If your automation hits the limits of expect, or your AI agent needs to interact with TUIs that assume a human operator, ht merits evaluation.
Explore the repository, install via brew install montanaflynn/tap/ht, and review the agent skill at https://github.com/montanaflynn/headless-terminal.
Explore on the BrightCoding network
Hand-picked resources from our other sites.
Stop Cloning Entire Repos! Use ghgrab Instead
Discover ghgrab, the Rust-powered terminal tool for downloading GitHub files without cloning. Features interactive TUI, release asset downloads, agent mode for...
yvgude/lean-ctx: Cut AI Agent Token Costs 60-90% with Local Context Engineering
LeanCTX is a local Rust binary that reduces AI agent token costs 60-90% through context engineering: intelligent compression, cached reads, persistent memory, a...
Stop Paying Salesforce Premiums: Twenty Is the Open-Source CRM Built for AI
Discover Twenty, the #1 open-source CRM alternative to Salesforce built for AI. Learn how its code-first architecture, TypeScript SDK, and native AI agents let...
Continuez votre lecture
The Ultimate Guide to Self-Hosted Workflow Automation Executors: Take Control of Your Automation Empire
AI Research Assistant: How Real-Time Web Scraping is Revolutionizing Knowledge Work in 2025
🎮 The Ultimate Guide to Open Source JavaScript Games: 100+ Free Games & Dev Tools You Can Use Today
Stop Coding Alone: OPC-Skills Gives Your AI Agent Superpowers
Commentaires 0
Aucun commentaire pour l'instant. Soyez le premier à réagir !