The terminal multiplexer built for AI coding agents — panes that know whether the agent inside is working, blocked, idle, or done, on a server that survives closing the lid.
Prebuilt binaries are on the releases page if you'd rather not pipe a script to a shell — a reasonable instinct, and worth doing on a machine you don't fully control.
| Concept | What it is | Notes |
|---|---|---|
| Server | The background process everything runs inside. | Survives closing the terminal, losing the network, and rebooting — sessions come back. |
| Workspace | The top-level grouping, usually one per project. | Addressed as w1. Created with prefix+shift+n or the CLI. |
| Tab | A layout of panes within a workspace. | Like a tmux window. |
| Pane | One real terminal. Usually one agent. | Addressed as w1:p1 — that ID is what the CLI and socket API target. |
| Agent state | working / blocked / idle / done, per pane. | The whole point. See the Agents tab for how it's detected. |
| Worktree | Git worktree integration, configured under [worktrees]. | Lets several agents work on separate branches without fighting over one checkout. |
| Plugin | Extends panes and workflows. | There's a marketplace. |
- If you run one agent at a time, probably not. tmux already does panes and detach, and you'll notice a single blocked agent without help.
- If you run several in parallel, this is the differentiator. State awareness plus
herdr agent waitis what tmux fundamentally lacks. - It's tmux-style deliberately —
ctrl+bprefix,h/j/k/lnavigation — so the muscle memory transfers. - Mouse support is first-class too: click, drag, and split without the prefix dance.
- One Rust binary, no Electron, runs inside whatever terminal you already use.
| Group | Action | Binding |
|---|---|---|
| Prefix | The prefix key itself | ctrl+b |
| Panes | Split right | prefix + v |
| Panes | Split down | prefix + minus |
| Panes | Move between panes | prefix + h / j / k / l |
| Panes | Swap panes | prefix + shift + h / j / k / l |
| Panes | Zoom focused pane | prefix + z |
| Panes | Enter resize mode | prefix + r |
| Panes | Enter copy mode | prefix + [ |
| Panes | Close pane | prefix + x |
| Tabs | New tab | prefix + c |
| Tabs | Next / previous tab | prefix + n / prefix + p |
| Tabs | Jump to tab 1–9 | prefix + 1..9 |
| Tabs | Rename tab | prefix + shift + t |
| Tabs | Close tab | prefix + shift + x |
| Workspaces | New workspace | prefix + shift + n |
| Workspaces | Workspace picker | prefix + w |
| Workspaces | Rename workspace | prefix + shift + w |
| Workspaces | Close workspace | prefix + shift + d |
| Navigate | Goto picker | prefix + g |
| Navigate | Toggle sidebar | prefix + b |
| Session | Detach — agents keep running | prefix + q |
| Agent | Commands menu | ctrl+p |
| Agent | Cycle bypass permissions | shift+tab |
| Agent | Interrupt | esc |
Identify the agent
Herdr detects the foreground process in each pane and matches it to an agent manifest.
If your agent runs inside a container, VM, or wrapper script, process detection fails — set HERDR_AGENT=<agent> in that environment to name the manifest explicitly.
Determine state — lifecycle hooks (authoritative)
Where a direct integration is installed, the agent reports its own state. This is exact.
Install the integration for any agent you rely on. It's the difference between knowing and guessing.
Determine state — screen manifest (inferred)
Without hooks, Herdr reads the bottom of the terminal buffer and matches TOML rules against screen content, terminal titles, and progress sequences.
This works well but is heuristic. An agent with unusual output, or one whose CLI changed its prompt in a recent release, can be misread — usually showing idle when it's actually blocked.
Override locally when a manifest is wrong
Manifests also update from a remote source automatically. Disable with [update] manifest_check = false if you need them pinned.
| State | Means | What to do |
|---|---|---|
| working | Actively processing. | Leave it. This is the state you want most panes in. |
| blocked | Waiting on you — a question, a permission prompt, a decision. | The one that matters. This is the state Herdr exists to surface. |
| idle | A live pane with nothing running. | Free capacity — give it work. |
| done | Finished its task. | Review the output before assuming success. |
- Well-tested: Claude Code, Codex, Cursor Agent CLI, Amp, OpenCode, GitHub Copilot CLI, Grok CLI, Devin CLI, Droid, Qwen Code, Kimi Code CLI, Qoder CLI, Kilo Code CLI, MastraCode, Hermes Agent, Antigravity CLI, Kiro CLI, Maki, Pi, OMP.
- Marked less tested: Gemini CLI, Cline.
- Around two dozen supported at time of writing, and the list moves — check the agents page for current coverage.
- Rename a pane's agent label with
herdr agent rename <target> <name>.
- Newline-delimited JSON over a socket. Every request echoes its
idand returns eitherresultor anerror. - Pane methods:
pane.current,pane.list,pane.get,pane.split,pane.swap,pane.move,pane.resize,pane.zoom,pane.layout,pane.focus_direction,pane.neighbor. - Agent methods:
agent.list,agent.get,agent.wait,agent.prompt,agent.start,agent.read,agent.explain. events.subscribestreams lifecycle notifications — keep the connection open.session.snapshotreturns the full bootstrap state: version metadata, focus, and every workspace, tab, pane, and agent.
{"id":"req_1","method":"pane.current","params":{"caller_pane_id":"w1:p1"}}- Run
herdr api schema --jsonto get the authoritative schema rather than working from examples. herdr statusfirst — a protocol mismatch after an update is the likeliest cause of an unexplained API failure.
| Section | Controls |
|---|---|
| [keys] | Every keybinding, including the prefix. |
| [terminal] | Shell defaults and terminal behaviour. |
| [theme] | Colours and theming. |
| [ui] | Layout and appearance. [ui.toast] for notifications, [ui.sound] for audio alerts. |
| [server] | Headless terminal dimensions. |
| [session] | Agent restoration after a restart. |
| [worktrees] | Git worktree directory. |
| [remote] | SSH connection management. |
| [update] | Includes manifest_check for remote agent-manifest updates. |
| [experimental] | Features still in flux — expect these to change. |
Gotchas
- Screen-based state detection is heuristic. Install the lifecycle integration (
herdr integration install <agent>) for any agent you actually depend on — otherwise a CLI update that changes its prompt can quietly break state reporting. - Agents in containers or VMs won't be detected by process name. Set
HERDR_AGENT=<agent>inside that environment. - Agent manifests update from a remote source by default. Pin them with
[update] manifest_check = falseif you need reproducible behaviour. - The server keeps agents running after you detach. That's the feature, but it also means a runaway agent keeps burning tokens while you're away — check
herdr agent listafter a long detach. shift+tabcycling bypass permissions is convenient and worth thinking about — it lowers the guardrails on agents that can modify your filesystem.- Most config reloads live, but startup-only settings still need a full restart.
- Piping an install script straight to a shell is convenient, not careful. Prefer the release binaries or Homebrew on machines that matter.
- The project is moving quickly — verify command syntax against the docs rather than any cheatsheet, including this one.
Tips
Before anything else, run herdr integration install for each agent you use. Authoritative state beats inferred state, and it's a one-time step.
agent wait in scriptsherdr agent wait w1:p1 --until blocked lets a script or another agent sleep until intervention is genuinely needed, instead of polling.
Configure [worktrees] and give each agent its own branch checkout. Several agents on one working tree is a merge conflict generator.
The server persists independently of any client, so you can SSH in from anywhere — a phone included — and pick the session back up.
herdr --default-config emits every option with its default, which is a better reference than the docs for discovering what's tunable.
[ui.toast] and [ui.sound] mean you hear about a blocked agent instead of discovering it later — the whole value proposition, made ambient.