CLI Reference
The @termless/cli package is a command-line tool built around the four recording-domain verbs — record, view, play, compare — plus the config and diagnostic surfaces backends, doctor, themes, and the mcp server.
For the MCP server tool list, see the MCP Reference.
Installation
npm install @termless/clibun add @termless/clipnpm add @termless/cliyarn add @termless/cliOr run directly:
$ bunx termless record -o demo.gif -- bun km view ~/Vaulttermless record
Capture a terminal session into a Recording and write it to one or more output files. Alias: termless rec.
record has exactly one output flag — -o. The shape of each -o value picks the mode; there is no separate format flag and no separate screenshot flag.
| Invocation | Output |
|---|---|
termless record -- <cmd> (no -o) | out.gif — a single file in the cwd |
termless record -o demos/ -- <cmd> | demos/ folder — out.rec · out.gif · out.cast · out.tape |
termless record -o a.gif -o b.cast | exactly a.gif + b.cast (-o is repeatable) |
termless record -o shot.png -- <cmd> | a single still PNG |
termless record (no command) | shows a help gate, then records a live $SHELL on Enter |
The -o extension picks the format; the format decides whether a renderer is involved:
| Extension | Format | Renderer |
|---|---|---|
.gif .apng | raster animation | the renderer — auto (see below) |
.png | raster still | the renderer — auto (see below) |
.svg | vector still/animation | none (vector) |
.html | scrubbable browser viewer | none server-side |
.rec .tape .cast | recording data | none |
Renderers
A renderer rasterizes captured frames into pixels. --renderer picks one; the default is auto.
| Renderer | How it works | Use it for |
|---|---|---|
swash | Renders the cell grid directly (no SVG) via the pure-Rust swash crate — composites full-colour emoji from their native colour tables. Bundled font chain: JetBrains Mono + Noto Sans Symbols 2 + Symbols Nerd Font + Noto Emoji. | The default — highest fidelity. |
resvg | Renders each frame's SVG via @resvg/resvg-js, handed the same bundled fonts. Clean glyph coverage; no native build. | Cross-platform fallback. |
canvas | Rasterizes the SVG through @napi-rs/canvas. Its drawImage path ignores registered fonts, so some glyphs tofu. | Niche; prefer resvg. |
browser | Rasterizes each frame's SVG in headless Chromium (Playwright) — a real browser text engine for Chrome-identical shaping, font fallback, ligatures, and colour emoji. Absolute-max fidelity. | Premium opt-in: marketing assets + a fidelity oracle against swash/canvas. |
auto | Resolves to swash, falling back to resvg then canvas. Never browser. | The default. |
auto prefers swash — it consumes the cell grid directly, so colour emoji, Nerd Font icons and box-drawing all render faithfully. Where the swash native binding is unavailable it falls back to resvg, which renders the SVG path with the same bundled fonts.
browser — the premium opt-in tier
browser is the highest-fidelity renderer: it hosts each frame's SVG in a headless-Chromium page and screenshots it, so output matches Chrome exactly (shaping, fallback, ligatures, colour emoji). It is opt-in only and never chosen by auto — Chromium is a hundreds-of-MB dependency, too heavy for a default or CI. Reach for it for one-off README/blog assets, or as a correctness oracle (render the same frame via browser and swash, diff them).
Playwright is an optional dependency — a default bun install omits it and swash/resvg/canvas are unaffected. Install it before using --renderer browser:
bun add -d playwright
npx playwright install chromiumWithout playwright, --renderer browser fails fast with that exact install hint.
# Bare record — shows a help gate, then records a live $SHELL on Enter
$ termless record
# Record a command — no -o → out.gif in the cwd
$ termless record -- bun km view ~/Vault
# Folder bundle — a trailing slash writes out.{rec,gif,cast,tape}
$ termless record -o demos/ -- bun km view ~/Vault
# Named files — -o is repeatable; the extension picks the format
$ termless record -o demo.gif -o demo.cast -- bun km view ~/Vault
# A single still PNG
$ termless record -o shot.png -- bun km view ~/Vault
# Force the resvg renderer (the common case never touches --renderer)
$ termless record --renderer resvg -o demo.gif -- bun km view ~/Vault
# Compat capture: record in a real desktop terminal app (macOS)
$ termless record --compat -o c.png -- bun km view ~/VaultOptions
| Option | Description | Default |
|---|---|---|
-o, --output <path...> | Output path — extension picks the format, trailing / a folder bundle (repeatable) | out.gif |
--renderer <kind> | Raster renderer: resvg, swash, canvas, browser, or auto | auto |
-t, --tape <commands> | Inline tape commands (scripted mode) | -- |
-b, --backend <name> | Backend for scripted mode | vterm |
--cols <n> | Terminal columns | 80 |
--rows <n> | Terminal rows | 30 |
--timeout <ms> | Wait timeout in ms | 5000 |
--keys <keys> | Comma-separated key names to press, then capture a still | -- |
--wait-for <text> | Wait for text before pressing keys | content |
--text | Print terminal text to stdout | off |
--chrome <style> | Window chrome on rendered output: none, macos, windows | none |
--title <text> | Title text in the window chrome bar | the command |
--compat | Compat capture — record in a real desktop terminal app | off |
--terminal <name> | Compat terminal app: ghostty, kitty, iterm, terminal | auto-detect |
--cwd <path> | Working directory for the recorded command (with --compat) | -- |
record's defaults are tuned for a README-droppable artifact: the ghostty backend (truecolor + real glyph shaping), 80×30 (GitHub renders README images at ~880px content width), ~12 fps, and a ~300-frame cap so a long session never produces a 50 MB GIF. Power users override every default.
Window chrome
--chrome wraps the rendered output in a window frame — the finishing touch for a README or blog image. It composites uniformly across PNG, SVG, and GIF output (the frame is baked into every captured frame).
| Style | Look |
|---|---|
none | No chrome — the bare terminal grid (default; byte-identical to omitting the flag) |
macos | Rounded top corners, three traffic-light dots, a soft drop shadow, a small margin |
windows | A flat title bar with minimize / maximize / close glyphs |
The bar background is derived from the terminal theme (a touch lighter on dark themes, darker on light ones). --title sets the bar's title text; it defaults to the recorded command. The macOS preset centers the title, the Windows preset left-aligns it.
# A framed GIF, ready to drop into a README
$ termless record --chrome macos -o demo.gif -- bun km view ~/Vault
# A Windows-style framed still, with a custom title
$ termless record --chrome windows --title "km — Knowledge Machine" \
--keys "j,j,Enter" -o shot.png -- bun km view ~/VaultCompat capture (macOS)
termless record --compat records against the peekaboo backend — it spawns the user's real desktop terminal app (Ghostty / kitty / iTerm / Terminal.app), runs the command after --, screenshots the window, and cleans up. Pixel-perfect for that terminal plus the user's font and theme.
$ termless record --compat -- bun km view ~/Vault
$ termless record --compat --terminal ghostty --cols 140 --rows 40 -o c.png -- bun kmCompat capture is macOS-only and needs a GUI session plus Screen Recording permission. For routine visual iteration use plain record (the resvg renderer) — the compat path is slow and pops a real window.
See Recording Sessions for detailed usage.
termless view
Present a recording — a single .rec file or a bare frame-trace directory. By default view writes a self-contained, scrubbable viewer.html alongside the recording; with --format gif it animates the recording's frames into a GIF.
# Scrub a recording in the browser (writes viewer.html next to it)
$ termless view ./mysession.rec
# Animate a recording to a GIF
$ termless view ./trace --format gif -o demo.gifOptions
| Option | Description | Default |
|---|---|---|
-o, --output <path> | Output file for --format | -- |
--format <type> | Animate the recording to a file: gif | scrub |
Writing a GIF is not a separate "export" command — it is view with an animation format and a file sink. See Tracing Visual Bugs for the scrubbable viewer.
termless play
Re-execute a recording into a terminal. Accepts any recording format. Produce terminal text, screenshots, or animated output.
# Play a recording (prints terminal text)
$ termless play demo.tape
$ termless play demo.cast
# Generate an animated GIF
$ termless play -o demo.gif demo.tape
# Generate an animated SVG
$ termless play -o demo.svg demo.tapeOptions
| Option | Description | Default |
|---|---|---|
-o, --output <path> | Output file, format detected from extension | -- |
-b, --backend <name> | Backend(s), comma-separated; use all for every ready backend | vterm |
--compare <mode> | Comparison mode — a thin alias for termless compare | -- |
--cols <n> | Override terminal columns | -- |
--rows <n> | Override terminal rows | -- |
termless compare
Play one recording across two or more backends and diff the results — "does my TUI look the same in every terminal?" compare shares its execution core with play; play --compare <mode> is a thin alias for it.
# Side-by-side comparison
$ termless compare demo.tape -b vterm,ghostty --compare side-by-side -o comparison.svg
# Compare every installed, ready backend
$ termless compare demo.tape -b all --compare grid -o all-backends.svg
# Diff mode — pixel-diff overlays against the baseline backend
$ termless compare demo.tape -b vterm,ghostty --compare diff -o diff.svgOptions
| Option | Description | Default |
|---|---|---|
-b, --backend <name> | Backend(s), comma-separated; use all for every ready backend | vterm |
--compare <mode> | separate, side-by-side, grid, diff | -- |
-o, --output <path> | Output file or directory | -- |
See Recording Sessions for the comparison modes.
Backend Management
Manage backend installation with Playwright-inspired commands. Backend versions are pinned in backends.json — upgrading termless upgrades all backends together.
termless backends
List all available backends with their type, install status, and version. termless backends list is the same command.
$ termless backends
$ termless backends listtermless backends install
Install backends. With no arguments, installs the default set (xtermjs, ghostty, vt100).
$ termless backends install
$ termless backends install ghostty
$ termless backends install ghostty alacrittytermless backends update
Check upstream registries (npm, crates.io, GitHub) for newer backend versions, compared against the versions pinned in backends.json.
$ termless backends update # dry run
$ termless backends update --apply # apply to backends.jsontermless doctor
Check installation health: verify installed backends load correctly, detect version mismatches, and report missing dependencies.
$ termless doctortermless themes
List the color themes available for recording screenshots and animations.
$ termless themesUse a theme with termless play --theme dracula demo.tape, or Set Theme "dracula" inside a .tape file.
termless mcp
Start a stdio MCP server for AI agents (Claude Code, etc.).
$ termless mcpThe full tool list and Claude Code integration are documented in the MCP Reference.
Session Manager (Programmatic)
The session manager is also available as a library:
import { createSessionManager } from "@termless/cli"
const manager = createSessionManager()
const { id, terminal } = await manager.createSession({
command: ["my-app"],
cols: 120,
rows: 40,
waitFor: "ready>",
timeout: 5000,
})
terminal.press("ArrowDown")
await terminal.waitForStable()
console.log(terminal.getText())
await manager.stopSession(id)
// or: await manager.stopAll()createSession(options?)
| Option | Type | Default | Description |
|---|---|---|---|
command | string[] | -- | Command to spawn |
env | Record<string, string> | -- | Additional env vars |
cwd | string | -- | Working directory |
cols | number | 120 | Terminal columns |
rows | number | 40 | Terminal rows |
waitFor | string | "content" | "stable" | "content" | What to wait for after spawn |
timeout | number | 5000 | Wait timeout in ms |
getSession(id)
Get a Terminal instance by session ID. Throws if not found.
listSessions()
Returns an array of { id, command, cols, rows, alive } for all sessions.
stopSession(id) / stopAll()
Close the terminal and kill the process for one or all sessions.
Key Names
Keys use the same format as terminal.press():
- Single characters:
a,1,/ - Named keys:
Enter,Tab,Backspace,Delete,Escape,Space - Arrow keys:
ArrowUp,ArrowDown,ArrowLeft,ArrowRight - Navigation:
Home,End,PageUp,PageDown - Function keys:
F1throughF12 - With modifiers:
Ctrl+c,Shift+Tab,Alt+x