| name | herdr |
| description | Control herdr from inside it. Manage workspaces and tabs, split panes, spawn agents, read output, and wait for state changes — all via CLI commands that talk to the running herdr instance over a local unix socket. Use when running inside herdr (HERDR_ENV=1). |
herdr — agent skill
before using this skill, check that HERDR_ENV=1. if it is not set to 1, say you are not running inside a herdr-managed pane and stop. do not inspect or control the focused herdr pane from outside herdr.
you are running inside herdr, a terminal-native agent multiplexer. herdr gives you workspaces, tabs, and panes — each pane is a real terminal with its own shell, agent, server, or log stream — and you can control all of it from the cli.
this means you can:
- see what other panes and agents are doing
- create tabs for separate subcontexts inside one workspace
- split panes and run commands in them
- start servers, watch logs, and run tests in sibling panes
- wait for specific output before continuing
- wait for another agent to finish
- spawn more agent instances
the herdr binary is available in your PATH. its workspace, tab, pane, and wait commands talk to the running herdr instance over a local unix socket.
if you need the raw protocol or full api reference, read the socket api docs.
survey before you dispatch — mandatory
before spawning an agent, creating a workspace/tab for a topic, or writing a mission brief for another agent, look. spawning is the last step, not the first.
run all four. do not skip one because the topic "feels new":
herdr workspace list
herdr pane list
tmux ls; for u in <other users>; do sudo -n -u "$u" tmux ls; done
ls /tmp/*<topic>* 2>/dev/null
then, on every match:
herdr agent read <pane> --source recent --lines 120
read what it concluded. an agent that is idle, done, or sitting at a prompt is not spare capacity — it may be a finished piece of work nobody has collected, or an agent stopped mid-task waiting on a human's answer. dispatching a second agent at that topic destroys the first one's result and asks the human the same question twice.
never assert unverified facts in a brief
every commit hash, file path, branch name, and divergence count you put in a mission brief must come from command output you read in the same turn you write it. do not carry facts forward from an earlier turn, another agent's summary, or memory.
a brief that opens with "context already verified" and contains a hash that git cat-file -t rejects is a fabrication. the receiving agent cannot tell your invented hash from a real one, so it acts on it and writes the fiction into its own output as provenance. this is unrecoverable downstream: bad provenance is indistinguishable from good provenance once it is written.
if you have not run the command, write "unverified" next to the claim, or leave it out.
prefer messaging a live lane over spawning its twin
if a lane already exists for the topic, talk to it:
herdr agent send <pane> "<your message>"
herdr pane send-keys <pane> Enter
duplicate lanes are a coordination defect, not extra coverage. two agents on one topic produce two partial truths and no owner.
concepts
workspaces are project contexts. each workspace has one or more tabs. unless manually renamed, a workspace's label follows the first tab's root pane — usually the repo name, otherwise the root pane's current folder name.
tabs are subcontexts inside a workspace. each tab has one or more panes.
panes are terminal splits inside a tab. each pane runs its own process — a shell, an agent, a server, anything.
agent status is detected automatically by herdr. the api exposes one public field for it:
agent_status — idle, working, blocked, done, unknown
done means the agent finished, but you have not looked at that finished pane yet.
plain shells still exist as panes, but herdr's sidebar agent section intentionally focuses on detected agents rather than listing every shell.
ids — as of herdr 0.7.4 (live-verified 2026-07-16, ep137 smoke): workspace ids look like w1, w2; tab ids like w1:t1; pane ids like w1:p1, w1:p2. (Earlier versions of this doc said 1, 1:1, 1-1 — the dashed pane form does not match live herdr 0.7.) Pane rows carry terminal_title/terminal_title_stripped (no title field); a label field appears only after herdr pane rename. These are compact public ids for the current live session.
important: ids can compact when tabs, panes, or workspaces are closed. do not treat them as durable ids. re-read ids from workspace list, tab list, pane list, or create/split responses when you need a current id. do not guess that an older 1-3 is still the same pane later.
discover yourself
see what panes exist and which one is focused:
herdr pane list
the focused pane is yours. other panes are your neighbors.
list workspaces:
herdr workspace list
tab management
list tabs in the current workspace:
herdr tab list --workspace 1
create a new tab:
herdr tab create --workspace 1
without --label, the new tab keeps the default numbered tab name.
create and name it in one step:
herdr tab create --workspace 1 --label "logs"
rename it:
herdr tab rename 1:2 "logs"
focus it:
herdr tab focus 1:2
close it:
herdr tab close 1:2
read another pane
see what is on another pane's screen:
herdr pane read 1-1 --source recent --lines 50
--source visible = current viewport
--source recent = recent scrollback as rendered in the pane
--source recent-unwrapped = recent terminal text with soft wraps joined back together
split a pane and run a command
split your pane to the right and keep focus on your current pane:
herdr pane split 1-2 --direction right --no-focus
that prints json with the new pane nested at result.pane.pane_id. parse that value, then run a command in that pane:
NEW_PANE=$(herdr pane split 1-2 --direction right --no-focus | python3 -c 'import sys,json; print(json.load(sys.stdin)["result"]["pane"]["pane_id"])')
herdr pane run "$NEW_PANE" "npm run dev"
split downward instead:
herdr pane split 1-2 --direction down --no-focus
wait for output
block until specific text appears in a pane. useful for waiting on servers, builds, and tests.
for --source recent, matching uses unwrapped recent terminal text, so pane width and soft wrapping do not break matches. pane read --source recent still shows the pane as rendered. if you want to inspect the same transcript that the waiter matches, use pane read --source recent-unwrapped.
herdr wait output 1-3 --match "ready on port 3000" --timeout 30000
with regex:
herdr wait output 1-3 --match "server.*ready" --regex --timeout 30000
if it times out, exit code is 1.
wait for an agent status
block until another agent reaches a specific status:
herdr wait agent-status 1-1 --status done --timeout 60000
use this when you want the same done / idle distinction the UI shows.
send text or keys to a pane
send text without pressing Enter:
herdr pane send-text 1-1 "hello from claude"
press Enter or other keys:
herdr pane send-keys 1-1 Enter
pane run sends the text and then a real Enter key in one request:
herdr pane run 1-1 "echo hello"
workspace management
create a new workspace:
herdr workspace create --cwd /path/to/project
without --label, the new workspace keeps the default cwd-based name.
create and name one in one step:
herdr workspace create --cwd /path/to/project --label "api server"
create one without focusing it:
herdr workspace create --no-focus
focus a workspace:
herdr workspace focus 2
rename:
herdr workspace rename 1 "api server"
close:
herdr workspace close 2
close a pane
herdr pane close 1-3
recipes
run a server and wait until it is ready
NEW_PANE=$(herdr pane split 1-2 --direction right --no-focus | python3 -c 'import sys,json; print(json.load(sys.stdin)["result"]["pane"]["pane_id"])')
herdr pane run "$NEW_PANE" "npm run dev"
herdr wait output "$NEW_PANE" --match "ready" --timeout 30000
herdr pane read "$NEW_PANE" --source recent --lines 20
run tests in a separate pane and inspect the result
herdr pane split 1-2 --direction down --no-focus
herdr pane run 1-3 "cargo test"
herdr wait output 1-3 --match "test result" --timeout 60000
herdr pane read 1-3 --source recent --lines 30
check what another agent is working on
herdr pane list
herdr pane read 1-1 --source recent --lines 80
watch another pane robustly
use this pattern when you need to coordinate with a sibling pane:
herdr pane read 1-3 --source recent --lines 40
herdr wait output 1-3 --match "ready" --timeout 30000
herdr pane read 1-3 --source recent-unwrapped --lines 40
spawn a new agent and give it a task
herdr pane split 1-2 --direction right --no-focus
herdr pane run 1-3 "claude"
herdr wait output 1-3 --match "shortcuts|Welcome" --regex --timeout 30000
herdr pane run 1-3 "review the test coverage in src/api/"
herdr pane send-keys 1-3 Enter
herdr pane list
coordinate with another agent
herdr wait agent-status 1-1 --status done --timeout 120000
herdr pane read 1-1 --source recent --lines 100
driving agent panes reliably
sends are fire-and-forget: send-text, send-keys, and run print nothing on success and give no delivery guarantee. when a send matters, verify it landed — read the pane or check agent_status. three failure modes recur in real orchestration:
1. agent TUIs swallow the Enter that pane run appends. interactive agent REPLs (claude code and similar) treat rapidly-injected text as a paste; the trailing Enter gets absorbed into the composer instead of submitting, and the prompt sits there while the agent stays idle. after sending a prompt to an agent pane, always follow with an explicit Enter, then confirm the agent actually started:
herdr pane run 1-3 "review the test coverage in src/api/"
herdr pane send-keys 1-3 Enter
herdr pane list
if it is still idle, read the pane: the prompt is probably sitting un-submitted in the composer — send Enter again rather than re-sending the text (re-sending duplicates the prompt).
2. long compound strings can arrive clipped. a long cd /path && long-command sent with pane run can arrive as just the trailing command, silently running in the wrong cwd. send cd as its own run, verify the prompt line shows the new cwd, then send the command. for genuinely long invocations (agent CLIs with many flags), write a small launcher script and send bash path/to/launch.sh instead of the flag soup.
3. freshly created panes lose early keystrokes. a new pane's shell takes a moment to initialize; text sent immediately after split / tab create can be partially eaten or echoed without executing. wait for the shell prompt to render (wait output, or read the pane) before the first run.
4. approval dialogs stall agents silently. even a generous pre-approved tool list will not cover everything: commands with shell expansions ($(…), variables), compound chains, or novel subcommands still raise an approval dialog, and the agent sits blocked until someone answers — a mission can stall for an hour on one unanswered "Do you want to proceed?". treat blocked as a first-class state you own as orchestrator:
- launch agent panes with the permission mode the mission actually needs (a launcher script holding the flags), instead of discovering mid-mission that the default nags.
wait agent-status <pane> --status blocked is a valid wake signal, exactly like done.
- a poll loop can auto-answer permission dialogs — they contain "Do you want to proceed?"; prefer the "don't ask again for:" option when offered so the same command shape never asks twice. never auto-answer a dialog that is not a permission prompt: an agent asking a real question deserves a real answer.
txt=$(herdr pane read "$pane" --source visible --lines 25)
if echo "$txt" | grep -q "Do you want to proceed?"; then
if echo "$txt" | grep -q "ask again"; then herdr pane send-keys "$pane" 2
else herdr pane send-keys "$pane" 1; fi
fi
orchestrating several agents (the loop that works)
- create panes; per pane:
cd (verify cwd in the prompt line) → launch the agent via a launcher script → wait for the REPL to render.
- send the task prompt →
send-keys Enter → confirm agent_status is working.
- watch with
wait agent-status <pane> --status done (long timeout). done means finished and not yet looked at; reading the pane acknowledges it. watch blocked in parallel (or run an auto-approver poll loop — see failure mode 4) so a permission dialog never stalls the mission.
- on wake: read the pane tail or the agent's report file, verify its claims yourself (run the tests), then continue.
when several agents work one repo, give them strict file ownership and a shared handoff file on disk — pane text is for driving, files are for coordination.
notes
workspace list, workspace create, tab list, tab create, tab get, tab focus, tab rename, tab close, pane list, pane get, pane split, wait output, and wait agent-status print json on success.
pane read prints text, not json.
pane read --format ansi or pane read --ansi returns a rendered ANSI snapshot for TUI feedback loops.
pane read --source recent-unwrapped is useful when you want to inspect the same unwrapped transcript that wait output --source recent matches against.
pane send-text, pane send-keys, and pane run print nothing on success.
- parse ids from
workspace create, tab create, and pane split responses when you need new ids. workspace create returns result.workspace, result.tab, and result.root_pane. tab create returns result.tab and result.root_pane. for pane split, the new pane id is at result.pane.pane_id.
- use
pane read for current output that already exists. use wait output for future output you expect next.
--no-focus on split, tab create, and workspace create keeps your current terminal context focused.
- without
--label, workspace create keeps cwd-based naming and tab create keeps numbered naming.
--label on tab create and workspace create applies the custom name immediately.
- if you are running inside herdr, the
HERDR_ENV environment variable is set to 1.