{"id":50398568,"url":"https://github.com/hegner123/tui-test-ghost","last_synced_at":"2026-05-30T22:01:41.771Z","repository":{"id":344231657,"uuid":"1181049503","full_name":"hegner123/tui-test-ghost","owner":"hegner123","description":"Zig-native TUI testing toolkit built on Ghostty's terminal emulation core","archived":false,"fork":false,"pushed_at":"2026-05-16T10:17:29.000Z","size":227,"stargazers_count":2,"open_issues_count":17,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-16T12:31:07.463Z","etag":null,"topics":["mcp","mcp-server","terminal","testing","tui","zig"],"latest_commit_sha":null,"homepage":"","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hegner123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-13T17:36:28.000Z","updated_at":"2026-05-16T10:17:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hegner123/tui-test-ghost","commit_stats":null,"previous_names":["hegner123/tuikit","hegner123/tui-test-ghost"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/hegner123/tui-test-ghost","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hegner123%2Ftui-test-ghost","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hegner123%2Ftui-test-ghost/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hegner123%2Ftui-test-ghost/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hegner123%2Ftui-test-ghost/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hegner123","download_url":"https://codeload.github.com/hegner123/tui-test-ghost/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hegner123%2Ftui-test-ghost/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33711018,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mcp","mcp-server","terminal","testing","tui","zig"],"created_at":"2026-05-30T22:01:39.432Z","updated_at":"2026-05-30T22:01:41.763Z","avatar_url":"https://github.com/hegner123.png","language":"Zig","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tui-test-ghost\n\nA TUI testing toolkit for programmatic interaction with terminal applications. Built in Zig on [Ghostty's](https://github.com/ghostty-org/ghostty) `ghostty-vt` terminal emulation core.\n\nDeveloped specifically to test [Bubble Tea](https://github.com/charmbracelet/bubbletea) interfaces agentically — letting AI agents spawn, drive, and assert against TUI applications through MCP without needing a display.\n\n## Platforms\n\n- macOS (aarch64, x86_64)\n- Linux (x86_64)\n\n## Quick Start\n\n### Install from release\n\n```bash\n# macOS (Apple Silicon)\ncurl -fsSL https://github.com/hegner123/tui-test-ghost/releases/latest/download/tui-test-ghost-v0.3.0-macos-aarch64.tar.gz | tar xz\nmv tui-test-ghost /usr/local/bin/\n\n# Linux (x86_64)\ncurl -fsSL https://github.com/hegner123/tui-test-ghost/releases/latest/download/tui-test-ghost-v0.3.0-linux-x86_64.tar.gz | tar xz\nmv tui-test-ghost /usr/local/bin/\n```\n\n### Install from source\n\nRequires [Zig 0.15.1+](https://ziglang.org/download/). Ghostty is fetched automatically.\n\n```bash\ngit clone https://github.com/hegner123/tui-test-ghost.git\ncd tui-test-ghost\nzig build -Doptimize=ReleaseSafe\njust install\n```\n\n### Add to Claude Code\n\n```bash\nclaude mcp add tui-test-ghost -- tui-test-ghost\n```\n\n## Usage\n\n### MCP Server\n\n```bash\ntui-test-ghost\n```\n\nStarts a JSON-RPC MCP server on stdin/stdout with these tools:\n\n| Tool | Description |\n|------|-------------|\n| `tui_start` | Start a TUI program and return initial screen state. Params: `command` (required), `args`, `cols` (default 80), `rows` (default 24), `region`. Returns `session_id`, `text`, `cursor_row`, `cursor_col`, `cols`, `rows`. |\n| `tui_send` | Send input and return screen state. Params: `session_id` (required), `keys` (array of key tokens), `settle_ms` (default 50), `region`. Legacy: `text`, `key`, `mods`. Returns `text`, `cursor_row`, `cursor_col`, `cols`, `rows`. |\n| `tui_screen` | Get screen content. Params: `session_id` (required), `region`. Returns `text`, `cursor_row`, `cursor_col`, `cols`, `rows`. |\n| `tui_cell` | Inspect a single cell. Params: `session_id`, `row`, `col` (all required). Returns `char`, `bold`, `italic`, `underline`, `strikethrough`, `dim`, `fg`, `bg`. |\n| `tui_wait` | Wait for a condition and return screen state. Params: `session_id` (required), plus one of: `text`, `stable_ms`, `cursor_row`+`cursor_col`. Optional `timeout_ms` (default 5000, max 30000), `region`. Returns `matched`, `text`, `cursor_row`, `cursor_col`, `cols`, `rows`. |\n| `tui_resize` | Resize terminal and return screen state. Params: `session_id`, `cols`, `rows` (all required), `region`. Returns `text`, `cursor_row`, `cursor_col`, `cols`, `rows`. |\n| `tui_snapshot` | Capture screen snapshot. Params: `session_id` (required), `golden_path` (optional — compares against baseline if provided, creates it if missing). |\n| `tui_stop` | Stop session and get exit code. Params: `session_id` (required). Returns `exit_code`. |\n| `tui_record_start` | Start recording tool calls to a JSONL file. Params: `path` (required). |\n| `tui_record_stop` | Stop recording and close the file. No params. |\n\n### Replay\n\n```bash\ntui-test-ghost replay test.jsonl\n```\n\nReplays a recorded JSONL session and reports pass/fail for each entry. Action tools (`tui_start`, `tui_send`, `tui_screen`, `tui_cell`, `tui_resize`) are re-executed without comparison. Assertion tools (`tui_wait`, `tui_stop`, `tui_snapshot`) compare key result fields against the recorded values.\n\nExits 0 if all assertions pass, 1 if any fail. Single-session recordings only (one `tui_start` per file).\n\nJSONL format — one JSON object per line:\n\n```jsonl\n{\"tool\":\"tui_start\",\"args\":{\"command\":\"myapp\"},\"result\":{\"session_id\":0,\"text\":\"...\"}}\n{\"tool\":\"tui_send\",\"args\":{\"session_id\":0,\"keys\":[\"down*3\",\"enter\"]},\"result\":{\"text\":\"...\"}}\n{\"tool\":\"tui_wait\",\"args\":{\"session_id\":0,\"text\":\"Settings\"},\"result\":{\"matched\":true,\"text\":\"...\"}}\n{\"tool\":\"tui_stop\",\"args\":{\"session_id\":0},\"result\":{\"exit_code\":0}}\n```\n\n### CLI\n\n```bash\ntui-test-ghost --cli --command htop --screen\ntui-test-ghost --cli --command vim --send \"ihello\" --wait-for \"hello\" --screen\n```\n\n| Flag | Description |\n|------|-------------|\n| `--command \u003ccmd\u003e` | Program to run (required) |\n| `--send \u003ctext\u003e` | Text to send to stdin |\n| `--wait-for \u003ctext\u003e` | Wait until text appears on screen (5s timeout) |\n| `--screen` | Print screen content to stdout |\n\n## Features\n\n- **Real terminal emulation** — Ghostty's VT parser handles SGR, cursor movement, alternate screen buffer, scrollback\n- **PTY-based** — programs run in a real pseudo-terminal, behaving exactly as they would in a real terminal\n- **Cell-level inspection** — query individual cell attributes: character, bold, italic, underline, strikethrough, dim, foreground/background color (default, palette, RGB)\n- **Wait conditions** — poll until text appears, screen stabilizes, cursor reaches a position, or process exits\n- **Golden file snapshots** — capture screen state to disk, diff against a baseline on future runs\n- **Session pool** — manage up to 16 concurrent terminal sessions\n- **Keyboard input** — send named keys (enter, tab, escape, arrows, F1-F12) with modifier combinations (ctrl, alt, shift)\n- **Key batching** — send multiple keystrokes in a single MCP call with the `keys` array: `[\"down*5\", \"enter\"]`\n- **Auto-screen** — `tui_start`, `tui_send`, `tui_wait`, and `tui_resize` return screen state in every response\n- **Region cropping** — return only a portion of the screen with the `region` parameter to reduce token usage\n- **Resize** — change terminal dimensions mid-session, delivering SIGWINCH to the child process\n- **Record/replay** — record an agent's MCP tool calls to JSONL, replay them as a repeatable test suite with `tui-test-ghost replay`\n\n### Key Token Syntax\n\nThe `keys` parameter on `tui_send` accepts an array of string tokens:\n\n| Token | Meaning |\n|-------|---------|\n| `\"enter\"` | Single key press |\n| `\"ctrl+c\"` | Modified key (ctrl, alt, shift) |\n| `\"down*5\"` | Repeat key 5 times (max 99) |\n| `\"ctrl+shift+up\"` | Multiple modifiers |\n| `\"text:hello world\"` | Send literal text |\n| `\"text:*\"` | Send literal `*` (since `*` is the repeat operator) |\n\nThe `text:` prefix is reserved. Max 64 tokens per call, max 99 repeats.\n\n### Region Parameter\n\nTools that return screen content accept an optional `region` object to crop the output:\n\n```json\n{\"region\": {\"row\": 2, \"col\": 0, \"width\": 40, \"height\": 10}}\n```\n\nAll fields are optional (defaults: row=0, col=0, width=terminal cols, height=terminal rows). Values are clamped to terminal bounds.\n\n## How It Works\n\n```\nTUI Process → PTY → ghostty-vt Terminal Emulator → Screen Query API → MCP / CLI\n```\n\nPrograms run in a real PTY backed by Ghostty's VT parser, providing accurate screen state including SGR attributes, cursor positioning, and alternate screen buffer support. Single-threaded with explicit drain — the caller controls when PTY output is consumed and fed to the terminal emulator.\n\n## Architecture\n\n| Module | Purpose |\n|--------|---------|\n| `Pty.zig` | PTY open/close/read/write/poll/resize |\n| `Process.zig` | Fork/exec, signal handling, wait |\n| `Terminal.zig` | Wrapper around ghostty-vt Terminal |\n| `Session.zig` | Combines PTY + Process + Terminal into a test session |\n| `SessionPool.zig` | Fixed-size pool of up to 16 sessions |\n| `screen.zig` | Screen queries: plaintext, cell attributes, cursor position |\n| `wait.zig` | Polling wait conditions with timeout |\n| `snapshot.zig` | Capture, save, load, and diff screen snapshots |\n| `input.zig` | Key encoding using Ghostty's input system |\n| `mcp.zig` | JSON-RPC message parsing and serialization |\n| `tools.zig` | MCP tool definitions, dispatch, and handlers |\n| `record.zig` | JSONL recorder for tool call capture |\n| `replay.zig` | Replay engine: load, execute, compare, report |\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nMIT License. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhegner123%2Ftui-test-ghost","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhegner123%2Ftui-test-ghost","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhegner123%2Ftui-test-ghost/lists"}