Persistent. Deterministic. Agent-Native.
yup! that's right — no more --yes or command retries
clrun gives AI agents full control over interactive terminal sessions — TUI prompts, select lists, checkboxes, long-running processes, and stateful shells. Every response is structured YAML with contextual hints telling the agent exactly what to do next.
Node.js:
npm install -g clrunPython:
uv tool install clrun-cli(pip: pip install clrun-cli)
Both runtimes share the same CLI commands, YAML output format, and .clrun/ state layout.
Traditional CLI execution gives agents a string and an exit code. clrun gives them:
- Structured context — every response includes
output,hints, andwarnings - Interactive control — navigate TUI prompts with named keystrokes
- Persistent sessions — env vars, cwd, and history survive across calls
- Agent-native errors — failures include the reason, alternatives, and recovery commands
# What an agent sees after running a command:
---
terminal_id: f5e6d7c8-...
command: npx create-vue@latest
output: |
◆ Project name:
│ vue-project
status: running
hints:
send_input: clrun f5e6d7c8 "my-app"
send_keys: clrun key f5e6d7c8 enter
view_output: clrun tail f5e6d7c8 --lines 50
kill: clrun kill f5e6d7c8# Run any command
clrun echo "hello world"
# Start an interactive scaffolder
clrun "npx create-vue@latest"
# Send text input (+ Enter)
clrun <id> "my-project-name"
# Navigate TUI select lists with arrow keys
clrun key <id> down down enter
# Toggle checkboxes in multi-select
clrun key <id> space down space enter
# Accept a default
clrun key <id> enter
# View latest output
clrun tail <id> --lines 50
# Check all sessions
clrun status
# Kill a session
clrun kill <id>CLRUN supports dynamic remote CLIs via SCP (Structured Command Protocol). SCP repo · npm: scp-sdk. Connect to any SCP server and drive its workflow as an interactive terminal: same clrun <id>, clrun key <id>, and clrun tail semantics. The server exposes CLI metadata (hints, next steps, options) at a standardized path; CLRUN fetches it after every state update and renders the flow in the virtual terminal.
# Connect to an SCP server
clrun scp http://localhost:8000
# Send option number or action name (same as PTY input)
clrun <id> "1"
clrun <id> "<action_name>"
# View output and manage session
clrun tail <id> --lines 50
clrun status
clrun kill <id>Node and Python CLRUN both support SCP with identical semantics. Use clrun scp <url> to drive dynamic remote CLI experiences from any SCP-compatible server.
# 1. Start the scaffolder
clrun "npx create-vue@latest"
# → Returns terminal_id and shows "Project name:" prompt
# 2. Enter the project name
clrun <id> "my-vue-app"
# → Advances to feature multi-select
# 3. Select TypeScript, Router, Pinia, and Linter
clrun key <id> space down down space down space down down down space down down enter
# → Advances to experimental features
# 4. Skip experimental features
clrun key <id> enter
# 5. Keep example code (accept default)
clrun key <id> enter
# 6. Install and start dev server
clrun <id> "cd my-vue-app && npm install"
clrun <id> "npm run dev"
# → Vite dev server running at http://localhost:5173/All commands return structured YAML with hints for next actions.
clrun "npm init"
clrun run "docker compose up"---
terminal_id: a1b2c3d4-...
command: npm init
output: "package name: (my-project)"
status: running
hints:
send_input: clrun a1b2c3d4 "<response>"
kill_session: clrun kill a1b2c3d4Sends text followed by Enter. Use for text prompts and shell commands.
clrun <id> "my-project" # Type text + Enter
clrun <id> "" # Just press Enter (accept readline default)Sends raw keystrokes for TUI navigation. No trailing Enter unless you include enter.
clrun key <id> down down enter # Navigate select list
clrun key <id> space down space enter # Toggle checkboxes
clrun key <id> enter # Accept default
clrun key <id> ctrl-c # Interrupt processAvailable keys: up, down, left, right, enter, tab, escape, space, backspace, delete, home, end, pageup, pagedown, ctrl-c, ctrl-d, ctrl-z, ctrl-l, ctrl-a, ctrl-e, y, n
clrun input <id> "yes" --priority 10
clrun input <id> "force" --override--priority <n>— Higher number = sent first (default: 0)--override— Cancel all pending inputs, send immediately
clrun tail <id> --lines 100 # Latest output
clrun head <id> --lines 20 # First output
clrun <id> # Shorthand for tailStart an SCP-backed session. Use clrun <id> "<option or action>" to drive the flow; same tail/status/kill as PTY sessions.
clrun scp http://localhost:8000
clrun <id> "1"
clrun tail <id> --lines 50| You see | Type | Action |
|---|---|---|
◆ Name: │ default |
Text input | clrun <id> "value" or clrun key <id> enter |
● Opt1 ○ Opt2 ○ Opt3 |
Single-select | clrun key <id> down... enter |
◻ Opt1 ◻ Opt2 ◻ Opt3 |
Multi-select | clrun key <id> space down... enter |
● Yes / ○ No |
Confirm | clrun key <id> enter or right enter |
(y/n) |
Simple confirm | clrun <id> "y" or clrun <id> "n" |
package name: (default) |
Readline | clrun <id> "value" or clrun <id> "" |
Counting items in select lists: The first item is highlighted by default. To select the Nth item, send N-1 down presses then enter.
Every clrun response is designed for high-context AI agents:
---
error: "Session not found: a1b2c3d4-..."
hints:
list_sessions: clrun status
start_new: clrun <command>
active_sessions: f5e6d7c8-...
note: Found 1 active session(s).---
input: ""
warnings:
- "Input is empty. If you intended to send $MY_VAR,
use single quotes: clrun <id> 'echo $MY_VAR'"Every success response includes hints — the complete set of valid next commands, copy-pasteable.
| State | Meaning | Accepts input? |
|---|---|---|
running |
PTY is active | Yes |
suspended |
Idle 5 min, env saved | Yes (auto-restores) |
exited |
Command finished | No |
killed |
Manually terminated | No |
detached |
Crashed/orphaned | No |
Sessions suspend after 5 minutes of inactivity, saving environment variables and working directory. Sending any input to a suspended session transparently restores it — no special handling needed.
clrun export MY_VAR=hello
# ... 5+ minutes idle → session suspends ...
clrun <id> 'echo $MY_VAR' # Auto-restores, prints "hello"On first run, clrun installs skill files into .clrun/skills/:
clrun-skill.md— Complete reference with TUI interaction patternsclaude-code-skill.md— Optimized for Claude Code agentsopenclaw-skill.md— Formatted for OpenClaw agents
These teach agents how to identify prompt types, navigate select lists, toggle checkboxes, and handle the full interactive lifecycle — with zero configuration.
All state lives in .clrun/ at the project root. No global state.
.clrun/
sessions/<id>.json # Session metadata
queues/<id>.json # Input queue
buffers/<id>.log # Raw PTY output (append-only)
ledger/events.log # Structured event audit trail
skills/ # Agent skill files
npm install
npm run build
npm test # 50 tests (unit + integration)
npm run dev -- run "echo hello"src/
index.ts # CLI entry + smart routing
worker.ts # Detached PTY worker (suspend/restore)
types.ts # TypeScript types
commands/
run.ts # clrun run / bare commands
input.ts # clrun input (with auto-restore)
key.ts # clrun key (TUI keystrokes)
tail.ts / head.ts # Output viewing
status.ts / kill.ts # Session management
runtime/
lock-manager.ts # File-based locking
crash-recovery.ts # Orphan detection
restore.ts # Transparent session restore
utils/
output.ts # YAML output, ANSI stripping
validate.ts # Runtime assertions, rich errors
paths.ts # Project-scoped path resolution
MIT