ptymotion records scripted terminal scenarios with real PTY behavior inside isolated Docker containers.
It is designed for repeatable terminal demos: deterministic input timing, reproducible render settings, and artifact output as MP4, GIF, and screenshots.
- Runs target apps in Docker with per-session isolation
- Uses a real PTY (
docker exec -it) for full-screen/curses TUIs - Replays captured terminal stream in a dedicated renderer container
- Exports high-quality 60 FPS MP4 + GIF automatically
- Supports start/pause/stop recording windows with pause removal
- Rust (stable)
- Docker daemon
No host Playwright/Bun/ffmpeg installation is required. Renderer dependencies live in a Docker image built automatically.
cargo build --release
./target/release/ptymotion --helpcargo run -- validate scenarios/shell-demo.toml
cargo run -- dry-run scenarios/shell-demo.toml
cargo run -- record scenarios/shell-demo.tomlThe first record run builds ptymotion-renderer:0.3.0 and can take a while.
These scenarios are production-style examples you can run directly:
scenarios/shell-demo.tomlshell walkthrough with natural typing, screenshots, resize, and paused intervals removedscenarios/top-demo.tomlfull-screen TUI capture (top) with clean start/stop timingscenarios/colors-demo.tomlANSI color rendering and theme consistency demoscenarios/flow-demo.tomltyped command flow with pause/resume and named outputscenarios/process-audit-demo.tomlprocess inspection and filtering workflow demoscenarios/log-pipeline-demo.tomllog slicing and pipeline walkthrough demoscenarios/file-audit-demo.tomlfilesystem triage and audit command sequence demoscenarios/system-check-demo.tomlhost/environment diagnostics and sanity checks demoscenarios/stassh-demo.tomlreal-world Stassh installation walkthrough and first-run usage demo
Run any example:
cargo run -- record scenarios/colors-demo.tomlWebsite demo media generated from real runs is stored in website/public/demo/.
ptymotion validate <scenario.toml>validate scenario configptymotion dry-run <scenario.toml>print ordered action execution onlyptymotion run <scenario.toml>execute scenario; renders if recording windows existptymotion record <scenario.toml>execute scenario and require at least one recording window
[app]
image = "ubuntu:24.04"
workdir = "/workspace"
hostname = "demo"
prompt_user = "alice"
prompt_host = "lab"
[[app.env]]
key = "TERM"
value = "xterm-256color"
[terminal]
cols = 120
rows = 36
font_family = "JetBrains Mono"
font_size = 18
line_height = 1.2
padding = 10
[docker]
network_disabled = true
memory_limit = "512m"
cpus = 1.0
pids_limit = 256
[[actions]]
type = "start"
[[actions]]
type = "type_text"
text = "ls --color=always"
interval_millis = 60
[[actions]]
type = "send_key"
key = "Enter"
[[actions]]
type = "pause"
[[actions]]
type = "start"
[[actions]]
type = "run"
command = "top"
[[actions]]
type = "wait"
seconds = 2.0
[[actions]]
type = "send_key"
key = "q"
[[actions]]
type = "stop"
name = "listing_and_top"
[output]
dir = "./artifacts"
save_event_log = trueScenario string values can reference environment variables as ${VAR_NAME}. ptymotion resolves variables from process env first, then from .env files discovered from the scenario directory upward.
- PTY output is captured continuously from session start.
startopens or resumes active capture.pausecloses the active window and removes elapsed pause time from output timeline.stopfinalizes the current recording session and writes one named output file.stoprequiresname.take_screenshotuses full-session time and works at any action timestamp.
Each run creates artifacts/run-*/ (or your configured output dir).
session*.mp4rendered MP4 videossession*.gifGIF versions of each named recordingscreenshots/*.pngtimeline screenshots fromtake_screenshotevents.jsonraw PTY chunks (save_event_log = true)recording_payload.jsonrenderer payloadrender_meta.jsonrenderer metadata
docs/scenario-reference.mdfull config schema and action referencedocs/recording-model.mdstart/pause/stop behavior and namingdocs/architecture.mdruntime architecture and module boundariesdocs/hardening.mdcontainer restrictions and threat tradeoffsdocs/faq.mdcommon issues and fixes
Astro website lives in website/.
cd website
bun install
bun run devDemo assets used by the site are in website/public/demo/.