Make any interactive CLI non-interactive.
Wraps programs in a PTY, strips ANSI artifacts,
returns clean pipeable UTF-8 text. Zero config. Agent ready.
Install
cargo install shuck Requires Rust 1.70+. Install Rust →
brew install shuck macOS and Linux via Homebrew.
curl -fsSL https://shuck.build/install.sh | sh Works on Linux and macOS. Installs to /usr/local/bin.
npx shuck-cli <command> Or install globally: npm install -g shuck-cli
pip install shuck-cli Python wrapper around the native binary.
Features
No scripts. No learning curve. Just shuck <command> and get clean output instantly. Works with any interactive program.
Structured JSON output with --json, conventional exit codes (124=timeout, 127=not-found), MCP server support.
Single-pass state machine ANSI stripping — O(n) with zero allocations. Written in Rust. The bottleneck is always the child process.
Architecture
shuck allocates a pseudo-terminal so the child process believes it's running interactively. All output passes through the VTE stripper before reaching your pipeline.
forkpty via nix crate $CI) Comparison
Every existing tool solves one piece of the puzzle. shuck solves all of them.
| Feature | shuck ✦ | expect | unbuffer | script | empty |
|---|---|---|---|---|---|
| Allocates PTY | ✓ | ✓ | ✓ | ✓ | ✓ |
| Strips ANSI sequences | ✓ | ✗ | ✗ | ✗ | ✗ |
| Zero config / scripting | ✓ | ✗ | ✓ | ✓ | ✗ |
| JSON structured output | ✓ | ✗ | ✗ | ✗ | ✗ |
| Conventional exit codes | ✓ | ~ | ~ | ✗ | ~ |
| MCP server | ✓ | ✗ | ✗ | ✗ | ✗ |
| Cross-platform (Win) | ✓ | ✗ | ✗ | ✗ | ✗ |
| CI fallback (no PTY) | ✓ | ✗ | ✗ | ✗ | ✗ |
| Single binary, no deps | ✓ | ✗ | ✗ | ✓ | ✗ |