The agent bridge
Human at a terminal,
agent on a pipe. Same tool.
Most CLIs are built for one audience or the other. rune wraps any
command or interactive TUI in a real pseudo-terminal, strips the ANSI
noise, and hands back the same structured result as colorized text to
a human or clean JSON /
NDJSON to an agent, no flag
required when stdout isn't a TTY.
$ rune run --json -- echo "hello agent"
{"status":"ok","data":{"command":"echo hello\ agent",
"exit_code":0,"clean_output":"hello agent\n",
"duration_ms":8.09}}
- 0
- runtime dependencies
- Ruby stdlib only, by design
- 3
- output modes
- human TTY, --json, --ndjson
- 153
- RSpec examples
- 0 failures, 0 RuboCop offenses
- 30s
- default PTY timeout
- overridable via --timeout=SECONDS
What it gives you
One CLI, human and agent both first-class.
rune isn't a wrapper bolted onto an existing tool: every command is
designed from the ground up to return the same structured
Result regardless of who or
what is calling it.
Dual output, one code path
Result → RendererEvery command returns a Result; a Renderer decides whether to print human-colored text or JSON based on TTY detection or an explicit flag. Pipe rune version | cat and you get JSON with no flag at all.
Universal PTY runner
rune runSpawns any CLI or TUI inside a real pseudo-terminal, strips ANSI/cursor/control sequences, disables pagers (PAGER=cat), and measures wall-clock duration in milliseconds.
Configurable timeout
--timeout=SECONDSrune run --timeout=SECONDS -- overrides the 30s default. A timeout returns a normal Result with exit code 124, not an unhandled exception.
Structured parsers
Rune::ParsersTableParser (space- or pipe-delimited, with an explicit format: :auto|:pipe|:space override), KeyValueParser, and TextSanitizer turn raw terminal text into typed Ruby hashes.
Interactive script DSL
Rune::Scriptwait_for, send_keys, and pause steps drive multi-step TUI interactions: automating prompts and menus without a human at the keyboard.
CorvidLabs-native
plugin.tomlShips as a native fledge plugin, integrates with the trust toolchain (spec-sync contracts in specs/, augur risk scoring, attest provenance), zero runtime dependencies.
The contract
Three output modes, one command.
rune picks a rendering mode automatically based on how it's invoked, or you can force one explicitly. All three execute the exact same command logic; only the output format differs.
Human TTY (default, interactive terminal)
✓ echo hello (6.2ms, exit 0)
hello
Agent JSON (--json, or piped)
{"status":"ok","data":{
"name": "rune",
"version": "0.1.3"}}
Agent NDJSON (--ndjson, streaming)
{"event":"result","status":"ok",
"data":{"exit_code":0,...}}
The CLI
Two commands. The whole surface.
rune run for executing anything in a PTY,
rune version for environment + toolchain
detection.
Every flag is in the getting-started guide.
Execute any CLI/TUI command in a PTY, return structured output.
--timeout=SECONDS, --json, --ndjson
Live bidirectional passthrough: raw-mode terminal forwarding, streamed output, and an NDJSON event log an agent can tail while a human drives it.
--log=PATH
Print rune + Ruby version and CorvidLabs toolchain detection (fledge, spec-sync present?).
--json, --ndjson
a timeout is a result, not a crash
rune run --timeout=1 -- sleep 3 returns
exit code 124 with a
[rune] Execution timed out message:
a normal structured Result, never an unhandled exception.
Where it ships
- Language
- Ruby (>= 3.0)
- Dependencies
- Zero: stdlib only (pty, timeout, shellwords, optparse, json, io/wait, io/console)
- Distribution
- GitHub Packages, fledge plugin, source
- Trust toolchain
- fledge · spec-sync · augur · attest
- License
- MIT