Skip to content

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.

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 → Renderer

Every 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 run

Spawns 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=SECONDS

rune run --timeout=SECONDS -- overrides the 30s default. A timeout returns a normal Result with exit code 124, not an unhandled exception.

Structured parsers

Rune::Parsers

TableParser (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::Script

wait_for, send_keys, and pause steps drive multi-step TUI interactions: automating prompts and menus without a human at the keyboard.

CorvidLabs-native

plugin.toml

Ships 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)

$ rune run -- echo "hello"
echo hello (6.2ms, exit 0)

hello

Agent JSON (--json, or piped)

$ rune version | cat
{"status":"ok","data":{
  "name": "rune",
  "version": "0.1.3"}}

Agent NDJSON (--ndjson, streaming)

$ rune run --ndjson -- echo "hi"
{"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.

rune run <command...>

Execute any CLI/TUI command in a PTY, return structured output.

--timeout=SECONDS, --json, --ndjson

rune watch <command...>

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

rune version

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

v0.2.1 is live

v0.2.1 shipped yesterday (Jul 29, 2026).

Feed rune run --json's output straight into augur/attest-gated pipelines the way fledge tasks already do.