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 multiple recording segments and checkpoints per run
- 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 segmented savesscenarios/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 checkpoints and multiple output segmentsscenarios/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 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 segments existptymotion record <scenario.toml>execute scenario and require at least one recording segment
[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_recording"
[[actions]]
type = "type_text"
text = "ls --color=always"
interval_millis = 60
[[actions]]
type = "send_key"
key = "Enter"
[[actions]]
type = "save_recording"
name = "listing"
[[actions]]
type = "run"
command = "top"
[[actions]]
type = "wait"
seconds = 2.0
[[actions]]
type = "send_key"
key = "q"
[[actions]]
type = "stop_recording"
[output]
dir = "./artifacts"
save_event_log = true- PTY output is captured continuously from session start.
start_recordingopens a segment window.save_recordingwrites a segment checkpoint and keeps recording active.stop_recordingcloses the active segment.- Multiple segments per run are supported.
Each run creates artifacts/run-*/ (or your configured output dir).
session*.mp4rendered MP4 videossession*.gifGIF versions of each segmentscreenshots/*.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.mdsegment/checkpoint 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/.