by ogulcancelik
agent multiplexer that lives in your terminal.
# Add to your Claude Code skills
git clone https://github.com/ogulcancelik/herdrbefore 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:
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.
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, unknownLast scanned: 5/10/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-05-10T06:33:05.628Z",
"semgrepRan": false,
"npmAuditRan": true,
"pipAuditRan": true
}https://github.com/user-attachments/assets/043ec09f-4bdd-41d5-aee0-8fda6b83e267
agent multiplexer that lives in your terminal.
workspaces, tabs, panes. mouse-native: click, drag, split. every agent at a glance: blocked, working, done. detach and reattach, agents keep running. no gui app, no electron, no mac-only native wrapper. you see the agent's own terminal, not someone's interpretation of it.
curl -fsSL https://herdr.dev/install.sh | sh
or download the binary from releases. requires linux or macos.
herdr notifies you when a new version is available. run manually to update:
herdr update
herdr
by default herdr launches or attaches to one background session server. ctrl+b q detaches the client. agents keep running. use herdr server stop to stop the default server. use --no-session for the old single-process mode.
named sessions are runtime/socket namespaces for separate persistent herdr servers. they do not replace workspaces; each named session has its own panes, tabs, workspaces, sockets, and session state while sharing the same global config file.
herdr session list
herdr session attach work
herdr session attach side-project
herdr session stop work
herdr session delete side-project
ctrl+b, then shift+n to create a workspacectrl+b, then to open workspace navigationNo comments yet. Be the first to share your thoughts!
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 — workspace ids look like 1, 2. tab ids look like 1:1, 1:2, 2:1. pane ids look like 1-1, 1-2, 2-1. 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.
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
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
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 togethersplit 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
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.
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 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"
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
herdr pane close 1-3
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
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
herdr pane list
herdr pane read 1-1 --source recent --lines 80
use this pattern when you need to coordinate with a sibling pane:
# inspect what is already there
herdr pane read 1-3 --source recent --lines 40
# wait only for the next output you expect
herdr wait output 1-3 --match "ready" --timeout 30000
# if you need to inspect the same transcript the waiter matched,
# read the unwrapped recent text directly
herdr pane read 1-3 --source recent-unwrapped --lines 40
herdr pane split 1-2 --direction right --no-focus
herdr pane run 1-3 "claude"
herdr wait output 1-3 --match ">" --timeout 15000
herdr pane run 1-3 "review the test coverage in src/api/"
herdr wait agent-status 1-1 --status done --timeout 120000
herdr pane read 1-1 --source recent --lines 100
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.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.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.--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.HERDR_ENV environment variable is set to 1.wctrl+b, then v or minus to split panes, or ctrl+b, then c to create a new tabon first run herdr opens a short onboarding flow. after that, restored sessions land in terminal mode; fresh sessions start in navigate mode.
| | tmux | gui managers | herdr | |--------------------------|------|--------------|-------| | persistent sessions | ✓ | — | ✓ | | detach / reattach | ✓ | — | ✓ | | panes, tabs, workspaces | ✓ | ✓ | ✓ | | agent awareness | — | ✓ | ✓ | | lives in your terminal | ✓ | — | ✓ | | real terminal views | ✓ | — | ✓ | | mouse-native | — | ✓ | ✓ | | lightweight binary | ✓ | — | ✓ | | agents can orchestrate | ? | ? | ✓ |
tmux gives you persistence and panes, but it was built before agents existed. gui managers show agent state, but they make you leave your terminal and use their wrapped view. herdr is persistence and awareness in one tool that stays out of your way.
start herdr where the work lives. locally, run herdr. it starts or attaches to the background session automatically, with no socket setup. run your agents, split panes, do your work. press ctrl+b q to detach. close your terminal, close your laptop; your agents keep running. open a new terminal, run herdr, you're back. same session, same panes, same agents.
need to check on your agents from your phone? just ssh in and run herdr. your shell is remote, herdr runs there, and the panes keep running there after detach. any ssh client works. no app to download, no account to create.
ssh you@yourserver
herdr
or attach from your local terminal through ssh without opening a shell first. your local herdr acts as a thin client, connects over ssh, starts or attaches to the remote herdr server, and streams the ui back to your terminal.
herdr --remote workbox
herdr --remote ssh://you@yourserver:2222
for repeat targets, use your ssh config:
Host workbox
HostName yourserver
User you
Port 2222
same session, same agents, same state.
herdr and herdr --remote attach to the full Herdr session UI. herdr agent attach <target> attaches your current terminal directly to one server-owned terminal, like a single-pane terminal attach. herdr terminal attach <terminal_id> does the same by terminal id.
Direct attach streams the current rendered terminal state first, then live ANSI frames. Your input goes straight to that terminal. Detach with ctrl+b q; send a literal ctrl+b with ctrl+b ctrl+b. One writable client owns input and resize for a terminal. A second attach fails unless you pass --takeover.
the sidebar shows which agents are blocked, working, or done. workspaces roll up to their most urgent state so you can scan the full list at a glance.
states:
detection works by reading foreground process and terminal output. zero config, no hooks required. for agents that expose hooks, the socket api integration gives more robust state reporting.
not a gui window, not a web dashboard, not electron. herdr runs inside whatever terminal you already use. single rust binary, no dependencies. works inside tmux.
the local unix socket lets agents create workspaces, split panes, spawn helpers, read output, and wait for state changes.
# create a workspace and tab
herdr workspace create --cwd ~/project --label "api"
herdr tab create --label "logs"
# split a pane and run
herdr pane split 1-1 --direction right
herdr pane run 1-2 "npm test"
# wait for a pane-level UI attention state
herdr wait agent-status 1-1 --status done
# read output
herdr pane read 1-2 --source recent --lines 50
# read a rendered ANSI snapshot for TUI feedback loops
herdr pane read 1-2 --source visible --ansi
full reference: socket api and SKILL.md.
automatic detection works out of the box. process name matching plus terminal output heuristics.
| agent | idle / done | working | blocked | |-------|-------------|---------|---------| | pi | ✓ | ✓ | partial | | claude code | ✓ | ✓ | ✓ | | codex | ✓ | ✓ | ✓ | | droid | ✓ | ✓ | ✓ | | amp | ✓ | ✓ | ✓ | | opencode | ✓ | ✓ | ✓ | | grok cli | ✓ | ✓ | ✓ | | hermes agent | ✓ | ✓ | ✓ | | kiro cli | ✓ | ✓ | — |
detected but not fully tested: gemini cli, cursor agent, cline, kimi, github copilot cli.
for agents outside the built-in list, herdr still works as a terminal multiplexer with workspaces, panes, and tiling. custom integrations can report agent labels over the socket api. see the socket api docs.
the built-in pi, claude code, codex, opencode, and hermes integrations forward semantic state to herdr over the socket api. install with:
herdr integration install pi
herdr integration install claude
herdr integration install codex
herdr integration install opencode
herdr integration install hermes
see the integrations docs for setup details.
press ctrl+b to enter prefix mode. default actions are prefix-first and tmux-like:
| key | action |
|-----|--------|
| prefix+c | new tab |
| prefix+n / prefix+p | next / previous tab |
| prefix+1..9 | switch tab |
| prefix+w | workspace navigation |
| prefix+shift+n | new workspace |
| prefix+shift+w | rename workspace |
| prefix+shift+d | close workspace |
| prefix+h/j/k/l | focus pane |
| prefix+v / prefix+minus | split pane |
| prefix+x | close pane |
| prefix+b | toggle sidebar |
| prefix+z | zoom pane |
| prefix+r | resize mode |
| prefix+q | detach |
resize mode: h/l resize width, j/k resize height, esc exit.
custom command keybindings can launch detached shell helpers or temporary panes:
[[keys.command]]
key = "prefix+g"
type = "pane" # "shell" or "pane"
command = "lazygit"
if you have old custom keybindings and want the new defaults, run herdr config reset-keys. herdr backs up config.toml, removes only keybinding config, and uses built-in v2 defaults after restart or config reload.
mouse is supported throughout. full reference: configuration docs.
config file: ~/.config/herdr/config.toml
herdr --default-config # print full default config
in-app settings screen for theme, sound, and toast preferences. full reference: [configuration docs](https://herdr.dev/docs/configuration/