---
title: herdr (plugin)
description: Drive gwm from inside the herdr multiplexer — the actions shipped by herdr-plugin-gwm, its adopt-only rule, install and configuration.
---
# herdr (plugin)
[herdr](https://herdr.dev) is a terminal multiplexer with workspaces, panes and a plugin API. [`herdr-plugin-gwm`](https://github.com/kbrdn1/herdr-plugin-gwm) wires gwm into it: create, switch, remove, review a PR, exec and clean across worktrees, and gwm's own TUI in a pane — each worktree reflected as a herdr workspace.
The plugin is glue-only bash. It holds no worktree logic of its own: every script is `gwm <cmd> --format=json` → `jq` → a herdr CLI call, riding the frozen 1.0 JSON contract of [`list`, `path` and `doctor`](/cli/reference).
## the one rule
> The plugin never calls `herdr worktree create` or `worktree open --branch`. Creation and removal always go through gwm; herdr only reflects, via `worktree open --path` (adopt) and `workspace close` / `workspace focus`.
That is what keeps a single source of truth. Break it and herdr starts creating git worktrees outside gwm's control — two writers on the same repo, drifting apart on the first `gwm remove`. The plugin enforces it rather than documenting it: one helper (`adopt_worktree`) is the only path to herdr, and a grep-assert in its test suite fails the build if any script reaches around it.
## install
| herdr marketplace | `herdr plugin install kbrdn1/herdr-plugin-gwm` |
| Local checkout | `herdr plugin link "$PWD"` |
There is no build step — plain bash, nothing to compile.
**Requirements:** herdr ≥ 0.7.4 (popup panes) · `gwm` on `PATH` · `jq` · `fzf` · bash · macOS or Linux.
## the actions
Invoke from any pane inside a herdr workspace sitting in a gwm-managed repo:
```bash
herdr plugin action invoke gwm.switch
```
| `gwm.create` | branch type → issue number → description → `gwm create`, then adopts the new worktree, resolved by its linked issue | split pane |
| `gwm.switch` | fzf over `gwm list --format=json` with live badges (issue `#N`, `PR#N`, dirty `±`, ahead `↑`, behind `↓`) — focuses the workspace if herdr already reflects the pick, adopts otherwise | popup |
| `gwm.remove` | fzf over removable worktrees (never the main checkout) → confirm gate → `gwm remove` (branch kept) → `workspace close` | popup |
| `gwm.review` | fzf over `gh pr list` → `gwm review <N>` materialises the PR as its own worktree → adopt | split pane |
| `gwm.exec` | `gwm exec -- <cmd>` across every worktree, with a `✓/✗` rollup | split pane |
| `gwm.clean` | `gwm clean` reports reclaimable build artifacts, deletes after a confirm | split pane |
| `gwm.dashboard` | gwm's TUI, as-is | zoomed pane |
Pick-and-go pickers are session-modal popups so the tiled layout does not move; the panes whose *output* is the point (`exec`, `clean`) or that run long git or network work (`create`, `review`) stay split — a modal that blocks the session for a 30-second clone reads as frozen.
Two things happen without being invoked:
- **A clicked GitHub PR URL** (`https://github.com/<owner>/<repo>/pull/<N>`) triggers `gwm.review`. The pattern is anchored and the script re-extracts the number itself, so only an integer ever reaches gwm — never a raw URL.
- **`worktree.created`**, fired when a worktree is created on the herdr side, outside gwm, runs `gwm bootstrap` on its path so it gets the same file copies, hooks and preset as a `gwm create` one. Adopts fire `worktree.opened`, not `.created`, so this never double-runs on the plugin's own work.
## binding a key
In `~/.config/herdr/config.toml`, then `herdr server reload-config`:
```toml
[[keys.command]]
key = "prefix+ctrl+shift+g"
type = "plugin_action"
command = "gwm.switch"
description = "gwm: switch worktree"
```
## configuration
Presentation only — the plugin has no behaviour to configure, since gwm owns the behaviour. Create `~/.config/herdr/plugins/config/gwm/config.toml` (or run `herdr plugin config-dir gwm`):
```toml
# "workspace" (default) → adopt as a nested worktree workspace in the sidebar.
# "tab" → lighter: open a tab with the worktree cwd.
open_mode = "workspace"
# "user" (default) → inherit your FZF_DEFAULT_OPTS (colors, borders); the picker
# only neutralizes file-browser bits that would garble
# non-file lines or rebind keys.
# "clean" → drop FZF_DEFAULT_OPTS entirely for a bare picker.
fzf_theme = "user"
```
Worktrees are adopted under the repo's *root* workspace, so invoking an action from inside a linked-worktree pane does not hit herdr's `linked_worktree_source` rejection.
## limits
Multi-repo mode (`gwm --workspace`) is not wired through the actions yet: the plugin operates on the single repo of the current workspace. Everything else — create, switch, remove, review, exec, clean, dashboard, bootstrap-on-create — is implemented.