# herdr: the test target needs bun, the published crate excludes the tests, and restart loses the processes

> herdr is a Rust terminal workspace manager for AI coding agents, Apache-2.0 licensed, built around a background server that owns your agent terminals and a socket API that lets agents drive each other. The build and packaging configuration is where the sharp edges are.

**ogulcancelik/herdr** — agent multiplexer that lives in your terminal. **agents can use herdr too**, a pure socket api: agents spawn panes, read output, wait on each other.

- Repository: https://github.com/ogulcancelik/herdr
- Website: https://herdr.dev
- Stars: 41,429 · Forks: 3,185
- Language: Rust
- License: Apache-2.0
- Published: 2026-08-04 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/ogulcancelik-herdr

## just test is not unit tests, and it will not run without bun

The README annotates the target as unit tests:

```bash
just test        # unit tests
just check       # formatting, tests, and maintenance checks
```

The justfile says otherwise. The test target runs cargo nextest first, with --locked, --status-level fail and --success-output never, then chains four more targets. One of them, maintenance-test, runs thirteen Python unittest modules by name, covering agent detection manifests, the changelog, config reference checks, docs translation parity, the Hermes integration asset, Windows ConPTY packaging, previews, releases, the Unix installer, both vendored libraries and Windows input. It then runs bun test scripts/release-workflows.test.ts. So a contributor needs Python 3, cargo-nextest and the bun runtime installed before the target the README calls unit tests can complete, and a failure in a release workflow test will read as a test failure with no obvious relation to your change. The comment is not harmless: it sets the expectation that this is a quick loop.

## The published crate ships six paths, and none of the tests are among them

Cargo.toml carries an explicit include list, so what lands on a registry is deliberate: the src tree, assets/sounds/*, docs/next/api/herdr-api.schema.json, skills/herdr/SKILL.md, distribution/install.ps1, README.md, LICENSE and Cargo.toml. Note what is missing. There is no tests directory, no scripts directory, no justfile and no docs beyond the single JSON schema file. That is a sensible size decision for a binary, and it has a consequence for anyone auditing a published build: the thirteen maintenance contract tests, the vendor checks and the UI hot-path architecture test all live in scripts and tests, none of which exist inside the installed artifact. The docs-contract and config-reference tests in particular verify that documentation and configuration agree, and that agreement cannot be re-checked from a copy you downloaded. Download the source to review it, not the crate.

## portable-pty is vendored and patched, which behaves differently for you than for the author

Two details in the manifest explain a lot about the terminal layer. The dependency is pinned to an exact version, portable-pty = "=0.9.0", with no caret, and there is a patch section that redirects it to a local path:

```toml
[patch.crates-io]
portable-pty = { path = "vendor/portable-pty" }
```

The workspace also contains crates/ghostty-vt as a second member, referenced by path rather than by version, and there are dedicated maintenance tests for both vendored libraries. The author is therefore building against a fork they control and the exact upstream release underneath it. The catch is how Cargo treats a patch section: it applies when you build this repository, and it is not carried into a dependency's published manifest. So a consumer resolving herdr from a registry gets the upstream portable-pty at whatever version satisfies the pin, not the vendored fork. Any behaviour that depends on the fork is a difference between the developer's build and your install, and there is no note in the README telling you to check for it.

## A restart restores the layout and loses the processes, and the resumable set is not named

This is the feature most people will care about and the one with the sharpest edge. herdr keeps terminals running in a background server, so closing the client or losing an SSH connection does not stop the work. But the next sentence is explicit about the other case: after a server or machine restart, herdr restores the saved layout and can resume supported agent sessions, while the original processes do not survive. So the guarantee is asymmetric, and by design. The word to press on is supported. The README does not name which agents can be resumed, and the session state documentation is a link away rather than a list here. Plan for the answer: an agent conversation that cannot be resumed is gone, along with any scratch file it had not yet written and any approval you had given it. If your work depends on surviving a reboot, verify your specific agent against the session state page before you rely on it.

## Pane status is a detection manifest, so an agent it does not know about shows nothing

The pitch is that every pane is marked working, blocked, or idle, and that when an agent stops and needs an answer, herdr says so. The implementation of that promise is per-agent detection, and the maintenance suite includes a test named for an agent detection manifest, alongside a test for an integration asset. So the working, blocked and idle states are not inferred from the terminal in a general way; they come from recognising specific programs. That is why the supported list is named as a set, running what you already run, with claude code, codex, cursor, opencode and grok given as examples, and why there is a whole documentation page on adding herdr support to your agent. The practical consequence: launch an agent herdr has not been taught about and its pane carries no meaningful status, and the feature that makes the tool worth using quietly stops applying to that pane.

## Windows gets its own installer line, its own lint tool, and a test that wipes your clipboard

Windows is handled as a separate path throughout. Installation is a PowerShell one-liner rather than the shell script used elsewhere:

```powershell
powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"
```

There is a separate page for Windows installs behind an endpoint-protected network, and a separate maintenance test named for Windows ConPTY packaging. Linting diverges too: on unix the lint target runs cargo fmt --check followed by cargo clippy --all-targets --locked with -D warnings, while on Windows it shells out to scripts/windows_check.ps1 with the -M flag. Most striking is a recipe marked as never running in normal CI, a local interactive Windows Terminal input qualification that calls the PowerShell script with -AllowInputInjection and -ClearClipboard. It injects keystrokes into a terminal and empties your clipboard. That is a reasonable thing to do deliberately on a test machine and an unpleasant surprise if you run the full target list on your desktop.

## Five install surfaces and a preview tag on the same day as two releases

The packaging footprint is wide: Cargo.toml with a committed Cargo.lock, a build.rs, a pinned rust-toolchain.toml, a clippy.toml, a .cargo directory, .githooks, flake.nix with flake.lock and a nix directory, a packaging directory, a distribution directory holding install.ps1, and a scripts directory whose tests cover the Unix installer, the release, previews and cross-platform Windows behaviour. Five install routes are advertised, the shell script, brew, mise, PowerShell and prebuilt binaries, plus the Nix flake. Keeping those consistent is exactly what the maintenance contract tests are for. The release feed shows the churn that creates: v0.9.3 at 19:29 on 2026-09-29, v0.9.2 at 13:19 the same day, and a preview-2026-09-29 build tagged at 12:12 with a commit hash in its name. When a preview and two releases share a date, the tag you copy has to be the one you mean.

## A socket API with no stated authentication is the feature to think hardest about

The part of herdr with no tmux equivalent is that agents drive it. The CLI and a pure socket API let an agent spawn panes, read output, prompt other agents, and wait until another agent is genuinely blocked, which is a coordination primitive rather than a display feature. The dependency list backs it up, with interprocess for local sockets and schemars generating a JSON schema that ships inside the crate at docs/next/api/herdr-api.schema.json. What the README does not state is any authentication, permission model or access control for that socket. The consequence follows from it being a local socket API: anything running as you, including every other agent you launched, can read pane output and prompt panes, and pane output is whatever your coding agents have printed. If you run herdr on a shared host or a machine with untrusted local processes, that boundary needs checking before you point an agent at it.

## Conclusion

herdr fits someone running several coding agents at once who wants a single window, a visible working, blocked or idle state on every pane, and a way to close the laptop without killing the work. It does not fit someone who needs processes to survive a reboot, who wants tmux semantics on that point, or who wants a dependency-light contributor setup, since the test target needs Python, cargo-nextest and bun. Before you rely on it, read the session state documentation and find out which agents are in the resumable set, check what your socket API exposes to anything that can open a local socket, and build from source with just check rather than trusting a prebuilt binary.

## FAQ

### What is herdr?

A Rust terminal workspace manager for AI coding agents, released as one binary with no Electron, licensed under Apache-2.0. It owns the terminals your agents run in, marks each pane working, blocked or idle, and exposes a CLI and socket API that agents can drive themselves.

### How do I install Herdr?

With curl -fsSL https://herdr.dev/install.sh | sh, or brew install herdr, or mise use -g herdr. On Windows the route is a PowerShell one-liner that runs https://herdr.dev/install.ps1, and prebuilt binaries are published on the releases page.

### is herdr tmux

It uses tmux-style prefix keys, and ctrl+b q detaches while running herdr reattaches, so the muscle memory carries over. The behaviour differs on the point that matters most: after a server or machine restart, herdr restores the saved layout and can resume supported agent sessions, but the original processes do not survive.

### how do I use herdr with opencode

herdr runs the agents you already run and does not wrap or replace them, with opencode named alongside claude code, codex, cursor and grok. It owns their terminals, so you start opencode in a pane and use the working, blocked or idle marking to know when it needs you.

### is herdr safe

It is a single Rust binary with no Electron component, Apache-2.0 licensed, and its install scripts are covered by maintenance tests in the repository, including one for the Unix installer and one for Windows ConPTY packaging. The README states no authentication model for the socket API that agents use to drive panes, so check that boundary yourself on a shared machine.

## Sources

- [Official documentation](https://herdr.dev)
- [Official README](https://github.com/ogulcancelik/herdr#readme)
- [Project repository](https://github.com/ogulcancelik/herdr)
- [Release notes](https://github.com/ogulcancelik/herdr/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ogulcancelik-herdr
