Get video proof of what your agents did in TUIs.
brew install stefanmatar/frameterm/frametermHere's opencode driven by frameterm — spawned, waited on, typed into, and recorded as video:
The footer is burned into the exported MP4 automatically:
- Keystroke overlay showing what was typed, like KeyCastr
- Live CPU and memory sparklines for the running process
- Wait-for badge visible while frameterm blocks on a screen state
Your AI agent navigates Kubernetes, and you get a video of exactly what it did.
frameterm spawn --name k9s --cols 120 --rows 40 k9s
frameterm wait-for -s k9s "Context:" # wait for cluster connection
frameterm key -s k9s ":"
frameterm type -s k9s "pods"
frameterm key -s k9s Enter
frameterm wait-for -s k9s "NAME" # wait for pods to load
frameterm snapshot -s k9s --format text # read what's on screen
frameterm key -s k9s Down # navigate
frameterm key -s k9s Down
frameterm key -s k9s Enter # describe a pod
frameterm record export -s k9s --output . # get the videoPoint frameterm at your own app. Wait for it to start. Drive it. Record the result.
frameterm spawn --name app ./my-tui-app
frameterm wait-for -s app "Ready" # wait for your app to boot
frameterm key -s app Tab # navigate
frameterm key -s app Space # toggle
frameterm key -s app Enter # confirm
frameterm snapshot -s app # check screen state as JSON
frameterm record export -s app --output . # export the test as videoThe exported MP4 has anti-aliased text (JetBrains Mono + Noto Emoji), full ANSI colors, and a footer showing every keystroke, wait state, and resource usage.
brew install stefanmatar/frameterm/frameterm- uses: stefanmatar/frameterm@v1Pin a specific version:
- uses: stefanmatar/frameterm@v1
with:
version: "1.2.2"cargo install --path crates/frametermRequires ffmpeg for video export.
frameterm spawn <command> # Start in background PTY
frameterm spawn --name myapp <cmd> # Named session
frameterm spawn --cols 120 --rows 40 <cmd> # Custom terminal size
frameterm spawn --fps 30 <cmd> # Custom recording FPS
frameterm spawn --no-record <cmd> # No recording
frameterm kill # Kill default session
frameterm kill -s myapp # Kill named session
frameterm list-sessions # List active sessions
frameterm stop # Stop daemon and all sessionsframeterm snapshot # JSON with text and content hash
frameterm snapshot --format text # Plain text
frameterm snapshot --format compact # JSON without text field
frameterm snapshot -s myapp # Specific sessionframeterm type "hello" # Type text
frameterm key Enter # Single key
frameterm key Ctrl+C # Key combo
frameterm key Up # Arrow keys
frameterm key "Escape : w q Enter" # Key sequence
frameterm click 10 5 # Click at row, col
frameterm scroll down 5 # Scrollframeterm wait-for "Ready" # Block until text appears
frameterm wait-for "Loading" --not # Block until text disappears
frameterm wait-for "Error" --regex # Regex pattern
frameterm wait-for "Done" --timeout 5000 # Custom timeout
# Wait for screen to change (no more guessing sleep durations)
HASH=$(frameterm snapshot | jq -r '.content_hash')
frameterm key Enter
frameterm snapshot --await-change $HASHframeterm record export # Export as MP4
frameterm record export -s myapp # Specific session
frameterm record export --all # All sessions
frameterm record export --no-overlay # Without input overlay
frameterm record export --no-footer # Terminal only, no footer
frameterm record export --output /tmp # To directory
frameterm record export --width 1920 # Scale to widthframeterm runs a background daemon that manages PTY sessions. Each CLI call communicates with the daemon over a Unix socket, so sessions persist between commands.
CLI ──── Unix socket ──── Daemon
├── Session (k9s) [PTY + vt100 + recording]
├── Session (vim) [PTY + vt100 + recording]
└── Session (htop) [PTY + vt100 + recording]
| Platform | Status |
|---|---|
| macOS (arm64, x86_64) | Supported |
| Linux (x86_64, arm64) | Supported |
| Windows | Not supported |
devbox shell # Rust, ffmpeg, lefthook
cargo build # Build
cargo test # Run tests
cargo clippy # Lint
cargo fmt # FormatMIT
