agentrun
May 14, 2026 ยท View on GitHub
agentrun runs Claude Code from scripts.
By default it behaves like claude -p: one prompt in, output out, then the Claude process exits. Its tmux-backed persistent session mode is opt-in for workflows that need follow-up steering.
Key features:
- drop-in
claude -psyntax viaagentrun -p - stdin prompt support for large orchestrator prompts
- native Claude
text,json, andstream-jsonoutput - opt-in persistent sessions with follow-up steering via
--persist-sessionand-s - detached/background starts via
-d - passthrough of Claude launch flags such as
--model,--permission-mode, and--allowed-tools
Requirements
- Go 1.24+
claudeCLI authenticated and available inPATHtmuxonly for--persist-session,-s,--last, or-d
Install
go install github.com/melonamin/agentrun/cmd/agentrun@latest
For local development:
go build -o agentrun ./cmd/agentrun
Run local checks:
just check
Run opt-in comparison checks against real claude -p behavior. This uses Claude quota:
just compare-claude-p
Build cross-platform release archives locally:
just dist
Releases
CI runs on every push and pull request. Pushing a tag that starts with v builds Linux and macOS artifacts for amd64/arm64, generates checksums.txt, and publishes a GitHub release:
git tag v0.1.0
git push origin v0.1.0
Drop-in claude -p compatibility
For the easiest migration, replace only the binary name:
- claude -p "summarize this repo"
+ agentrun -p "summarize this repo"
agentrun -p accepts the print-mode flags from Claude Code:
agentrun -p --output-format text "do stuff"
agentrun -p --output-format json "do stuff"
agentrun -p --output-format stream-json --include-partial-messages --include-hook-events "do stuff"
agentrun -p --input-format stream-json --output-format stream-json < input.jsonl
Flags specific to claude -p are accepted by agentrun and forwarded to Claude:
-p, --print
--output-format <text|json|stream-json>
--input-format <text|stream-json>
--include-partial-messages
--include-hook-events
--replay-user-messages
Other Claude flags are passed through to the claude command:
agentrun -p --model sonnet --permission-mode dontAsk --allowed-tools "Read,Bash" "do stuff"
Compatibility defaults:
agentrun -p "prompt"defaults to--output-format text, matchingclaude -p.agentrun "prompt"also runs an ephemeralclaude --printturn.- tmux-backed persistence requires
--persist-session,-s,--last, or-d.
Comparison testing
The repository includes an opt-in parity check against the real claude -p command:
just compare-claude-p
It verifies text output, JSON result fields, stream-json output, and stream-json input/replay behavior. This command makes live Claude calls and uses quota.
Ralphex Provider
agentrun can be used as Ralphex's claude_command provider. Ralphex passes prompts on stdin, appends --print, and normally supplies --output-format stream-json; agentrun forwards that directly to Claude, so Ralphex receives Claude-compatible stream-json without any Ralphex-specific mode.
Ralphex config locations are ~/.config/ralphex/config globally or .ralphex/config inside a project. The minimal config is:
claude_command = /absolute/path/to/agentrun
That works with Ralphex's default claude_args:
claude_args = --dangerously-skip-permissions --output-format stream-json --verbose
On the Ralphex path, agentrun:
- reads the full prompt from stdin
- tolerates future/unknown Claude flags instead of failing wrapper startup
- runs Claude as a normal child process instead of moving work into tmux
- forwards Claude stdout/stderr so signal text such as
<<<RALPHEX:ALL_TASKS_DONE>>>passes through unchanged - kills the Claude process group on
--turn-timeout, SIGINT, or SIGTERM
Provider-level compatibility does not implement the Ralphex orchestrator itself: plan execution loops, review phases, dashboards, worktrees, Docker wrappers, and branch management remain Ralphex responsibilities.
Direct Usage
Run one prompt through claude --print:
agentrun "summarize this repo"
Select Claude output formats:
agentrun --output-format text "summarize this repo"
agentrun --output-format json "summarize this repo"
agentrun --output-format stream-json "summarize this repo"
Persistent Session Usage
Start a new tmux-backed Claude session, send a prompt, wait until the turn appears complete, and print processed JSON parsed from Claude's JSONL transcript:
agentrun --persist-session "summarize this repo"
Follow up in an existing session and stream that turn:
agentrun -s 1 --stream "now run the tests"
agentrun --persist-session --stream streams Claude Code's persisted JSONL transcript events, including tool calls, tool results, hooks, attachments, and assistant messages.
Start in detached mode and return immediately:
agentrun -d "refactor the parser"
Send a follow-up to an existing session:
agentrun -s 1 "also add tests"
Use the most recently updated session:
agentrun --last "continue"
Assistant text only:
agentrun -q "write a changelog entry"
Session commands
agentrun list
agentrun status -s 1
agentrun attach -s 1
agentrun transcript -s 1
agentrun kill -s 1
list and status also default to JSON. Use --text for tabular/human output:
agentrun list --text
agentrun status -s 1 --text
Flags
Native agentrun flags:
--persist-session Start a tmux-backed persistent session
-s, --session <id-or-name> Send to an existing session
--last Use the most recently updated session
-d, --detach Send prompt and return immediately
--name <name> Name a new agentrun session
--cwd <dir> Working directory for a new session
--stream Stream raw transcript JSONL in persistent mode
--text Human-readable text output
-q, --quiet Assistant text only
--idle-timeout <duration> Transcript stability duration for turn completion
--turn-timeout <duration> Maximum wait for a turn
claude -p compatibility flags implemented by agentrun:
-p, --print
--output-format <text|json|stream-json>
--input-format <text|stream-json>
--include-partial-messages
--include-hook-events
--replay-user-messages
Other Claude flags are passed through to Claude.
How it works
By default, agentrun starts claude --print as a direct child process, forwards stdin/stdout/stderr, and kills Claude's process group on timeout or cancellation.
In persistent mode:
agentrunstartsclaudeinside a detachedtmuxsession namedagentrun-<id>-<state-hash>.- Prompts are injected with literal chunked
tmux send-keys, then Enter. agentrundiscovers Claude Code JSONL transcripts under~/.claude/projects/*/*.jsonl.- Output is parsed from JSONL events, not from the
tmuxpane. - Turn completion is detected with a conservative idle heuristic: once assistant text appears and the transcript file has stopped changing for
--idle-timeout.
State
Session registry defaults to:
$XDG_STATE_HOME/agentrun/sessions.json
or:
~/.local/state/agentrun/sessions.json
Override with:
AGENTRUN_STATE_DIR=/tmp/agentrun agentrun list
Override Claude transcript root with:
AGENTRUN_CLAUDE_DIR=/path/to/.claude agentrun --persist-session "prompt"
Current MVP limitations
- Busy-session queueing is not implemented yet.
- Interrupt/resume controls are not implemented yet.
- JSONL parsing is schema-tolerant but intentionally minimal.
- Persistent-session turn completion relies on transcript-idle heuristics unless Claude Code exposes stronger lifecycle markers.
- Persistent
--streamoutput uses Claude Code's persisted transcript schema. - Persistent-session partial message chunks are emitted only if the interactive transcript contains them.
Roadmap
tail --follow--queue--interrupt- richer tool-use summaries
- integration tests with a fake
claudebinary - configurable Claude/tmux binary paths