
Kou
Virtual terminal engine
Introduction
kou is a standalone virtual-terminal engine — PTY management, a VT100/ANSI screen emulator, and screen rendering that draws glyphs. It is the vtty core extracted from the tairitsu packager, hardened into a library and CLI of its own.
Three things set it apart from a bare PTY wrapper:
- VT100 screen. The byte stream is run through the vte parser, so CSI cursor moves, erase, scroll and the SGR 16-colour palette are honoured — not the "drop ESC on the floor" stub of the early prototype.
- Build-time font fetching. kou pre-downloads one font per script into a shared cache at build time. Override families or pin local files via environment variables; route downloads through an HTTP(S) proxy when behind a restrictive network. See [Fonts & fetching](#fonts--fetching) for the full list.
- Inband graphics. A frame can be rasterised to PNG, or described to a capable terminal through the kitty (`kitty2`) or iTerm2 graphics protocol — so wezterm / kitty / iTerm2 / Ghostty render the real pixels inline.
Quick Start
CLI
# Launch a command in a virtual terminal and drive it from a REPL.
# > echo hello
# > screen # prints the current screen text
npx (no Rust toolchain required)
Prebuilt binaries are published to npm, so you can run kou with a single command — no cargo build:
The @celestia-island/kou root package pulls the right platform subpackage (-linux-x64 / -darwin-arm64 / -win32-x64) automatically. The Linux binaries are statically linked against musl, so they run unchanged on glibc distributions and on Alpine/distroless hosts. To pin a version:
Library
use ;
async
Graphics protocols
| KOU_GRAPHICS | Protocol | Terminals |
|---|---|---|
| kitty / kitty2 | kitty APC graphics | kitty, wezterm, Ghostty |
| iterm / iterm2 | OSC 1337 inline image | iTerm2, wezterm |
| sixel | DCS sixel | (placeholder — needs a rasterizer) |
| off (default) | none — render a PNG out of band | all |
use ;
let frame = render_graphics;
if let Some = frame
Fonts & fetching
kou pre-downloads one font per script into a shared cache at build time:
| Script | Font |
|---|---|
| Latin | Fira Code |
| CJK (中文 · 日本語 · 한국어) | Source Han Sans SC (思源黑体) |
Override any family at build time with KOU_FONT_PRIMARY / KOU_FONT_CJK, or pin local files with KOU_FONT_PATH / KOU_FONT_CJK_PATH. Downloads can be routed through an HTTP(S) proxy via KOU_DOWNLOAD_PROXY (passed directly to reqwest).
| Env | Purpose |
|---|---|
| KOU_FONT_PRIMARY | Override the Latin font family. |
| KOU_FONT_CJK | Override / disable the CJK font (none to disable). |
| KOU_FONT_MIRROR | Substitute the download host with a mirror. |
| KOU_DOWNLOAD_PROXY | Route downloads through an HTTP(S) proxy (reqwest). |
| KOU_DOWNLOAD_TIMEOUT_SECS | Per-request timeout (default 120). |
| KOU_SKIP_FONT_FETCH | Disable fetching. |
MCP server
Build kou with the mcp feature and run the stdio server — it exposes the virtual-terminal engine to AI coding assistants over the Model Context Protocol (no browser or daemon required):
The server advertises eleven tools — vtty_launch, vtty_kill, vtty_send_keys, vtty_send_text, vtty_screenshot, vtty_wait, vtty_ready, vtty_scrollback, vtty_resize, vtty_list, vtty_ping — each delegating in-process to the same VttyManager the library exposes. Screenshots render through the same font + theme stack as the library, so vtty_screenshot returns a real PNG (or themed text) for vision-capable models.
Wire it into an MCP client:
Set KOU_PROJECT_ROOT to pin the working directory for launched sessions when the client does not advertise a project root.
Development
Screenshots

License
SySL-1.0 (Synthetic Source License). See LICENSE or the SySL website.
MCP Server Deployment
For production or long-running MCP deployments (e.g. with opencode, Claude Desktop, or other MCP clients), we recommend using an auto-restart wrapper to keep the MCP server alive across updates and transient failures without interrupting the client session.
Recommended launcher script
#!/bin/bash while true; do /path/to/kou mcp sleep 0.2 done
How it works
- 1The wrapper runs the MCP server in a while true loop.
- 2If the server process exits, the wrapper restarts it within 0.2 seconds.
- 3The MCP client detects the reconnect and continues without data loss.
- 4To restart after updating the binary: kill $(pgrep -f "kou mcp" | head -1)