Agent automation
Use Herdr as an automation layer for coding agents. A script can control them, or one agent can create work for other agents, inspect their state, and collect their results. Choose the primitive that matches the job.
Three primitives
| Primitive | Responsibility |
|---|---|
Layout (workspace, tab, and pane topology) | Create and organize terminal locations. |
| Pane | Control a raw terminal: run commands, send input, read output, and wait for output. |
| Agent | Control a recognized coding agent by name or pane and lifecycle state. |
A pane exists whether or not it contains an agent. An agent is the
recognized process currently running inside a pane. agent start
therefore requires an existing shell pane and never creates, splits, or
moves layout.
Creating a workspace also creates its first tab and root pane; creating a tab creates its root pane. Use the returned pane ID for the first process, and split only when that layout needs another terminal.
Creation commands print JSON. Capture IDs from the response instead of predicting them:
created=$(herdr workspace create --cwd ~/project --label api --no-focus)pane_id=$(printf '%s\n' "$created" | jq -r '.result.root_pane.pane_id')
split=$(herdr pane split "$pane_id" --direction right --no-focus)review_pane=$(printf '%s\n' "$split" | jq -r '.result.pane.pane_id')
Terminal window
workspace create returns .result.workspace, .result.tab, and
.result.root_pane. tab create returns .result.tab and
.result.root_pane. pane split returns the new pane as
.result.pane.
Moving a pane to another workspace changes its workspace-qualified pane
ID. After any pane move, continue with
.result.move_result.pane.pane_id; the response keeps the old value at
.result.move_result.previous_pane_id. A running process keeps its
launch-time Herdr environment, but the old HERDR_PANE_ID remains an
alias for that terminal, so --current stays safe. New commands can
still resolve the agent by name after the move, but a wait already in
progress ends with agent_not_running.
Use pane commands for shells, tests, servers, CI watchers, and other
ordinary terminal processes. Use agent commands when Herdr needs to
understand which agent is running or whether it is working, blocked,
done, idle, or unknown.
Agent identity and launch
A pane ID such as w1:p2 identifies the terminal location. An agent
name such as reviewer is a convenient alias for the current agent in
that pane. Names must match [a-z][a-z0-9_-]{0,31} and be unique among
live agents. The alias is cleared when that agent exits, is released, or
is replaced; it does not permanently rename the pane.
Agent commands accept either a unique live name or the pane ID that currently hosts the agent.
An available shell pane is at its interactive shell prompt: the shell
itself owns the foreground, with no foreground command, editor, or agent
running. Return the pane to its prompt before calling agent start.
--kind selects a supported agent and its canonical executable.
Supported kinds are pi, claude, codex, gemini, cursor,
devin, agy, cline, omp, mastracode, opencode, copilot,
kimi, kiro, droid, amp, grok, hermes, kilo, qodercli,
qwen, and maki. Arguments after -- are passed unchanged to that
executable.
Successful agent start returns only after Herdr detects the expected
agent in the same terminal and marks it ready for interactive input. If
detection reports blocked during startup, the command returns
agent_not_ready immediately. The name remains available for
agent read and agent send-keys, and becomes ready for prompts after
detection reports idle. Startup waits for 30 seconds by default;
--timeout must be greater than 3000 and no more than 300000
milliseconds.
herdr agent start reviewer --kind codex --pane "$review_pane" -- -m gpt-5.4
Terminal window
Agents launched manually are detected automatically and can be addressed by pane ID. Give one a name when a stable human-readable target is useful:
herdr agent get w1:p2herdr agent rename w1:p2 reviewer
Terminal window
Choose the control surface
| Goal | Command |
|---|---|
| Run a shell command and submit it | pane run |
| Send literal text without Enter | pane send-text |
| Send terminal keys or modifier chords | pane send-keys |
| Wait for text or a regular expression | pane wait-output |
| Start a supported agent in an existing pane | agent start |
| Submit a prompt, optionally waiting for it | agent prompt |
| Send keys to an agent’s interactive UI | agent send-keys |
| Wait for agent lifecycle state | agent wait |
agent prompt submits text plus encoded Enter and honors the terminal’s
live bracketed-paste mode. It can prompt an agent that is already
working. If the agent is already blocked, it returns agent_blocked
without sending terminal input; inspect the dialog and use
agent send-keys for a deliberate response. Use agent send-keys for
interactions such as esc, up, enter, or ctrl+c; escape is
accepted as an alias for esc. Use the pane input commands when you
deliberately want raw terminal control.
Pane input addresses the terminal regardless of its current occupant. Agent input resolves the live agent and rejects the operation if that agent no longer controls the pane.
agent prompt --wait submits immediately unless the agent is already
blocked, in which case it returns agent_blocked without starting the
wait. If an accepted prompt starts from another non-working state, Herdr
must observe a lifecycle change within five seconds. Otherwise, it
returns agent_prompt_stalled instead of waiting indefinitely; a caller
--timeout of five seconds or less returns the normal timeout error.
After Herdr observes activity, it waits for the requested settled
status. It does not track individual turns. If the agent is already
working, completion of that active turn may satisfy the wait. Standalone
agent wait observes the current agent and returns immediately if its
status already matches. Both commands default to idle, done, or
blocked. Repeat --until to accept several exact states, for example
--until idle --until done; use --until unknown explicitly when
needed. On agent prompt, --until requires --wait.
idle means the agent is ready for input and its tab has been seen in
the focused Herdr UI. done is the same underlying idle state after
background work finishes, until that tab is focused or pane focus /
agent focus targets it. Reading through the CLI does not mark it seen.
blocked means Herdr recognized an approval or question UI. unknown
means an agent is present but Herdr cannot classify its lifecycle
confidently; it does not prove successful completion. Use exact
--until states when that distinction matters.
pane wait-output does not interpret agent lifecycle. It polls the
selected terminal snapshot and searches it immediately, so text that was
already present can match. The default source name is recent; matching
treats that source as unwrapped recent output from the latest 80
rendered terminal rows. --lines changes that row limit, and --regex
uses Rust regular-expression syntax and matches one line at a time.
At the CLI, both pane read and agent read print terminal text
directly. The default is UTF-8 text with ANSI escapes stripped; use
--format ansi or --ansi to preserve terminal escapes where the
source exposes them. The detection source is always plain text. For
recent sources, --lines N selects the last N rendered terminal rows
before optional unwrapping; without it, reads default to 80 rows. For
visible and detection, omitting --lines returns the full snapshot,
while specifying it keeps the last N newline-delimited lines. The socket
API returns the text at .result.read.text.
Alternate-screen history reads
Full-screen agents such as Claude Code and OpenCode render transcript
history in the terminal’s alternate screen instead of Herdr’s host
scrollback. For an idle, recognized agent at the bottom of its
transcript, text reads from recent or recent-unwrapped automatically
use the agent’s mouse-scroll interface when --lines requests more than
the visible screen. Herdr collects overlapping pages and returns the
viewport to the bottom before completing the read. The same behavior
applies to pane read when the pane contains that agent; it requires no
additional option.
Other reads remain passive. Herdr does not move the application viewport
for visible, detection, or ANSI reads, output waits and
subscriptions, a manually scrolled agent, a direct attachment, or an
application that does not report mouse-wheel input. An explicit
agent read --lines N that needs alternate-screen history returns
agent_not_idle while the agent is working, blocked, or unknown; wait
for idle and retry, or use --source visible. Other recent reads return
the available screen and host scrollback as before.
If a full response is still unavailable, ask the agent to write it as Markdown in a temporary directory and reply only with the file path, then read the file directly.
Successful agent start, agent prompt, and agent wait commands
return the current agent at .result.agent. pane wait-output returns
.result.pane_id, .result.matched_line, and the matched snapshot at
.result.read.
Wait commands have no default timeout and can wait indefinitely. On timeout or another server error, CLI commands print a JSON error to stderr and exit with status 1; invalid CLI syntax exits with status 2.
Recipes
Start a helper, give it work, and wait for that work to settle:
split=$(herdr pane split --current --direction right --no-focus)review_pane=$(printf '%s\n' "$split" | jq -r '.result.pane.pane_id')herdr agent start reviewer --kind codex --pane "$review_pane" -- -m gpt-5.4herdr agent prompt reviewer "Review the current diff" --wait --timeout 120000herdr agent read reviewer --source recent-unwrapped --lines 120
Terminal window
Wait for an agent to ask for input, inspect it, and interact with its UI:
herdr agent wait reviewer --until blocked --timeout 120000herdr agent read reviewer --source recent-unwrapped --lines 80herdr agent send-keys reviewer esc
Terminal window
Run an ordinary process and wait for its output without treating it as an agent:
herdr pane run w1:p3 "just test --watch"herdr pane wait-output w1:p3 --regex "passed|failed" --timeout 120000
Terminal window
See the CLI reference for the complete command and option list. Shell completions expose the same command tree interactively.
Last updated Oct 08, 2026