# herdr plus — Complete Documentation > herdr-plus supercharges herdr with quick actions and projects — an open-source extension platform for the herdr terminal. Free, by Cloudmanic Labs. This single file inlines the full herdr-plus documentation so an agent can learn the whole product from one fetch. Source site: https://herdrplus.com/ Repository: https://github.com/cloudmanic/herdr-plus Generated by Hugo from the same markdown that powers the human docs. ================================================================================ # Overview Source: https://herdrplus.com/docs/ herdr-plus is an add-on platform for [herdr](https://herdr.dev) — a place to build extensions and plugins on top of herdr's terminal panes. It is free and open source, built by [Cloudmanic Labs](https://github.com/cloudmanic/herdr-plus). ## The mental model herdr-plus ships as a single binary. The same binary can run in different **modes**, and each mode decides what to do when it talks to herdr. You bind a mode to a herdr keybinding, press your prefix plus that key, and the mode springs to life inside herdr. We're in explore mode: the list of modes will grow over time. Today there are two. ## Modes Pick a mode with `--mode=`. With no flag, the default mode (`control`) runs. | Mode | Slug | Default key | What it does | |------|------|-------------|--------------| | Control | `control` (default) | `prefix+up` | herdr-plus's home base — a full-screen workspace for driving herdr. First feature: **Projects**. | | Quick Actions | `quick-actions` | `prefix+down` | A fuzzy launcher: pick an action and run it in a split pane. | Each mode has its own default key, so the two can be installed side by side. ## Where to start - **[Quick Start](quick-start/)** — the fastest path from zero to a working keybinding. - **[Installation](installation/)** — every install method (Homebrew, install script, from source) and how upgrades work. - **[Control Mode & Projects](projects/)** — declarative workspace templates that spin up a whole herdr workspace of tabs and panes. - **[Quick Actions](quick-actions/)** — the fuzzy launcher and per-project actions. If you just want the reference, jump to [Keybindings](keybindings/), [Modes](modes/), the [Actions Reference](actions/), [Template Variables](variables/), [Configuration](configuration/), the [Examples & Cookbook](examples/), or [Troubleshooting](troubleshooting/). ================================================================================ # Quick Start Go from zero to a working herdr-plus keybinding in four steps: install herdr, install herdr-plus, bind a key, press it. Source: https://herdrplus.com/docs/quick-start/ This is the fastest path from zero to a working herdr-plus keybinding. Four steps, a couple of minutes. ## 1. Make sure herdr is installed and running herdr-plus is an add-on for [herdr](https://herdr.dev). You need a working herdr install first — follow the [herdr install guide](https://herdr.dev) — and you need to be running inside a herdr session, because herdr-plus talks to the running herdr server over a local socket. > **Note:** herdr-plus only does something useful from inside herdr. If you run > it outside herdr it can't find a pane to work with. ## 2. Install herdr-plus Pick whichever you prefer. **Homebrew** (the repo is its own tap): ```bash brew tap cloudmanic/herdr-plus https://github.com/cloudmanic/herdr-plus brew install cloudmanic/herdr-plus/herdr-plus ``` **Install script** (Linux/macOS, no Homebrew): ```bash curl -fsSL https://raw.githubusercontent.com/cloudmanic/herdr-plus/main/install.sh | sh ``` See [Installation](../installation/) for from-source builds, install-location overrides, and how upgrades work. ## 3. Install the keybindings `herdr-plus install` wires herdr-plus into herdr's `config.toml` as keybindings and reloads the running herdr server, so the bindings are live immediately. A bare install binds **every mode at once**, each on its own default key: ```bash herdr-plus install # binds prefix+up -> control AND prefix+down -> quick-actions herdr-plus install --mode=quick-actions # bind just quick-actions (prefix+down) ``` Each mode claims its own default key, so the two coexist. Override a single mode's key with `--key=prefix+a`. See [Keybindings](../keybindings/) for the full story. ## 4. Press your prefix, then the key In herdr, press your prefix (default `ctrl+b`) followed by the bound key: - `prefix` then `up` opens **Control mode** — a full-screen "Herdr Plus" workspace with the Projects browser. - `prefix` then `down` opens the **Quick Actions** launcher — a fuzzy finder in a split beneath your current pane. That's it. The first time you open Quick Actions, herdr-plus seeds your config with editable example actions so you have something to try right away. ## Next steps - [Control Mode & Projects](../projects/) — build workspace templates. - [Quick Actions](../quick-actions/) — the launcher and per-project actions. - [Actions Reference](../actions/) — write your own actions. - [Configuration](../configuration/) — where everything lives on disk. ================================================================================ # Installation Install herdr-plus via Homebrew, the install.sh one-liner, or from source — with supported platforms, install locations, and upgrades. Source: https://herdrplus.com/docs/installation/ herdr-plus is a single static binary. There are three ways to install it: Homebrew, the install script, or from source. All of them are free and open source. > **Note:** herdr-plus is an add-on for [herdr](https://herdr.dev). Install and > set up herdr first — herdr-plus does its work by talking to a running herdr > server. ## Homebrew The herdr-plus repository is its own Homebrew tap. Tap it, then install: ```bash brew tap cloudmanic/herdr-plus https://github.com/cloudmanic/herdr-plus brew install cloudmanic/herdr-plus/herdr-plus ``` To upgrade later: ```bash brew upgrade cloudmanic/herdr-plus/herdr-plus ``` ## Install script A POSIX `sh` installer detects your OS and architecture, downloads the matching archive from the latest GitHub Release, extracts the static binary, and drops it into place. It works under plain `sh`, so it's fine on Alpine/BusyBox and minimal SSH targets, not just bash. ```bash curl -fsSL https://raw.githubusercontent.com/cloudmanic/herdr-plus/main/install.sh | sh ``` Re-running the script performs an upgrade. ### Environment overrides The script honors two environment variables: | Variable | Default | What it does | |----------|---------|--------------| | `INSTALL_DIR` | `~/.local/bin` (else `/usr/local/bin`) | Where the binary is installed. | | `VERSION` | the latest GitHub Release | Pin a specific release tag to install. | Examples: ```bash # Install into a custom directory. curl -fsSL https://raw.githubusercontent.com/cloudmanic/herdr-plus/main/install.sh | INSTALL_DIR=/opt/bin sh # Pin a specific version (tags are prefixed with "v"). curl -fsSL https://raw.githubusercontent.com/cloudmanic/herdr-plus/main/install.sh | VERSION=v0.0.1 sh ``` ## From source Clone the [repository](https://github.com/cloudmanic/herdr-plus) and build with the Makefile: ```bash make build # build the herdr-plus binary make install-bin # build, then install the binary onto your PATH ``` Or use the Go toolchain directly: ```bash go build -o herdr-plus . go test ./... ``` ## Supported platforms Releases are cross-compiled for: - **Operating systems:** Linux and macOS. - **Architectures:** `amd64` (x86_64) and `arm64` (aarch64). The install script maps `uname` output onto those tokens and refuses to run on anything else, telling you exactly what it detected. ## Where the binary lands The install script chooses, in order: 1. The directory in `INSTALL_DIR`, if you set it. 2. `~/.local/bin` — preferred, because it needs no `sudo`. 3. `/usr/local/bin` — the fallback, which may prompt for `sudo`. > **Tip:** If the chosen directory isn't on your `$PATH`, the script prints the > exact `export PATH=...` line to add to your shell rc. Without that, your shell > won't find the `herdr-plus` command. ## Checking the version Confirm what's installed at any time: ```bash herdr-plus version ``` (`--version`, `-v`, and `-V` all work too.) It prints `herdr-plus` followed by the release version. ## How upgrades work Every merge to `main` auto-bumps the patch version and cuts a new GitHub Release with cross-compiled binaries. To pull the latest: - **Homebrew:** `brew upgrade cloudmanic/herdr-plus/herdr-plus` - **Install script:** re-run the `curl ... | sh` one-liner. - **From source:** `git pull` and `make install-bin` again. ## Next steps Once herdr-plus is on your PATH, bind it to a key: [Keybindings](../keybindings/), then jump into the [Quick Start](../quick-start/). ================================================================================ # Keybindings How herdr-plus install binds a herdr key to a mode: per-mode defaults, overriding the key, idempotency, and how to trigger an action. Source: https://herdrplus.com/docs/keybindings/ You launch herdr-plus by pressing a herdr keybinding. The `herdr-plus install` command wires those bindings into herdr for you. ## What `herdr-plus install` does A bare `herdr-plus install` installs **every mode at once**, each on its own default key (control → `prefix+up`, quick-actions → `prefix+down`). For each one it adds a `[[keys.command]]` entry to herdr's `config.toml`, then reloads the running herdr server so the bindings are live immediately. Pass `--mode` to install just a single mode. One entry looks like this: ```toml # herdr-plus — added by `herdr-plus install` [[keys.command]] key = "prefix+up" type = "shell" command = "'/absolute/path/to/herdr-plus' --mode=control" description = "herdr-plus: control" ``` A few important details: - **It binds the absolute path of the binary you invoked.** That means the keybinding works no matter where herdr-plus lives or what your current directory is. If the binary was reached through a symlink, the symlink is resolved to its real target first. - **It writes to herdr's config.** That's `$XDG_CONFIG_HOME/herdr/config.toml` if `XDG_CONFIG_HOME` is set, otherwise `~/.config/herdr/config.toml`. The file (and its directory) are created if they don't exist. - **It reloads herdr.** After writing, it runs `herdr server reload-config` so you don't have to restart herdr. If the reload fails it tells you to run that command yourself or restart herdr. ### It's idempotent Running `install` again for the same mode won't duplicate the binding. herdr-plus detects an existing binding that runs the exact same command (same binary, same `--mode`) and simply reports where it lives instead of adding another. Because each mode's command carries its own `--mode` flag, the two modes never collide with each other — installing `control` doesn't trip over an existing `quick-actions` binding. ### It refuses to clobber other bindings If the key you're asking for is already bound to something *else*, `install` stops and tells you what's there, suggesting you pick a different key with `--key`. It never overwrites a binding it didn't create. ## Per-mode default keys Each mode claims its own conventional key, so the two can be installed side by side without conflicting: | Mode | Slug | Default key | |------|------|-------------| | Control | `control` | `prefix+up` | | Quick Actions | `quick-actions` | `prefix+down` | When you run `install` for a single mode without `--key`, it uses that mode's default. ## Installing both, side by side A bare `install` does this in one shot — it walks every mode and binds each to its default key: ```bash herdr-plus install # prefix+up -> control AND prefix+down -> quick-actions ``` Now `prefix+up` opens Control mode and `prefix+down` opens Quick Actions. (You can still install them one at a time with `--mode` if you only want one.) ## Overriding the key Pass `--key` to bind any herdr key you like, for any mode: ```bash herdr-plus install --key=prefix+a # control on prefix+a herdr-plus install --mode=quick-actions --key=prefix+space ``` If the chosen key is taken, `install` will refuse and ask you to pick another. ## The herdr prefix, and triggering an action herdr keybindings are *prefixed*: you press your herdr prefix (default `ctrl+b`), release it, then press the bound key. So to launch a mode bound to `prefix+up`: > Press `ctrl+b`, then press `up`. The `prefix+` part of the key name is herdr's placeholder for "whatever your prefix is" — it isn't the literal text `prefix`. After a successful install, herdr-plus prints the exact reminder, e.g. *"Press your prefix, then up, to launch."* ## See also - [Modes](../modes/) — the mode concept and the `--mode` flag. - [Installation](../installation/) — getting the binary onto your PATH. - [Troubleshooting](../troubleshooting/) — what to check when a key does nothing. ================================================================================ # Modes One herdr-plus binary, multiple modes. How --mode works, the available modes, and how to invoke each. Source: https://herdrplus.com/docs/modes/ herdr-plus is an add-on platform for [herdr](https://herdr.dev): the same binary can be invoked many times in different herdr panes, and a `--mode` flag tells each invocation what to do when it talks to herdr. We expect this list of modes to grow. ## How modes work One binary, multiple behaviors. You pick a mode with `--mode=`. With no flag, the **default mode (`control`)** runs — it's the front door of herdr-plus, so the bare binary lands there. An unrecognized slug is an error (so typos fail loudly instead of silently doing the wrong thing). For example, `herdr-plus --mode=quikactions` exits with an `unknown mode` message. ## Available modes | Mode | Slug | Default key | What it does | |------|------|-------------|--------------| | Control | `control` (default) | `prefix+up` | herdr-plus's home base — a full-screen "Herdr Plus" workspace for driving herdr. First feature: **Projects**. | | Quick Actions | `quick-actions` | `prefix+down` | A fuzzy launcher: pick an action and run it in a split pane. | Each mode has its own default key, so the two can be installed side by side. The slug is also the name of the mode's per-mode config subdirectory under `~/.config/herdr-plus/` (see [Configuration](../configuration/)). ## Invoking herdr-plus ```bash herdr-plus # default mode (control) herdr-plus --mode=quick-actions # the fuzzy launcher herdr-plus version # print the version and exit ``` In day-to-day use you don't run these by hand — you bind them to a herdr key with `herdr-plus install` and press the key instead. See [Keybindings](../keybindings/). ## How adding a mode works herdr-plus is open source and designed to grow. Adding a mode is a small change in the [repository](https://github.com/cloudmanic/herdr-plus): register a new `Mode` value (giving it a slug, title, and default key) in `mode.go`, optionally add bundled example actions under `examples//`, and teach the launcher how the mode should present itself. If you'd like to build one, the repo is the place to start. ## Go deeper - [Control Mode & Projects](../projects/) — the full guide to control mode. - [Quick Actions](../quick-actions/) — the full guide to the launcher. ================================================================================ # Control Mode & Projects Control mode opens a full-screen Herdr Plus workspace with the Projects browser — declarative templates that spin up a whole herdr workspace. Source: https://herdrplus.com/docs/projects/ Control mode is herdr-plus's home base. Today its one feature is **Projects** — declarative herdr workspace templates that spin up a fully laid-out workspace with a single keypress. ## What Control mode does Pressing `prefix+up` opens a brand-new, full-screen herdr workspace titled **Herdr Plus** with a tab named `projects`, and runs the projects browser there. This is control mode — over time it will gain more features; today it has Projects. Fuzzy-find a project, press `enter` (or click it), and herdr-plus spins up a whole workspace — every tab created and every command running — then closes the ephemeral "Herdr Plus" workspace so you land directly in your new project. Cancel with `esc` and the ephemeral workspace is torn down, returning you to where you were. > **Note:** With no project files yet, control mode shows an onboarding screen > explaining how to add your first project. ## What a project is A **project** is a declarative herdr workspace template: a name, a description, a working directory, and an ordered list of tabs (each with an optional startup command, or a set of split panes). It replaces hand-written workspace shell scripts with a simple config file. ## Where projects live Projects live in `~/.config/herdr-plus/projects/` (honoring `$XDG_CONFIG_HOME`), **one TOML file per project**. The file name doesn't matter — only its contents. The directory **starts empty**: unlike quick-actions, it is never seeded with examples, because an empty directory is meaningful (it triggers the onboarding screen). To add a project, drop a `.toml` file in. To remove a project, delete its file. ## The project schema Here is a complete, annotated example covering every field: ```toml # Top-level project fields. name = "Options Cafe" # required: the workspace label description = "The main options.cafe monorepo" # shown in the browser group = "Cloudmanic" # optional: cluster a client's projects under a heading working_dir = "~/Development/options-cafe/options.cafe" # ~ and $VARS expand # Tabs open in file order. The FIRST tab reuses the workspace's root tab; the # rest are created behind it so the first tab stays in front. [[tabs]] name = "claude" # required: the tab label command = "claude --dangerously-skip-permissions --chrome" # runs on startup [[tabs]] name = "lazygit" command = "lazygit" [[tabs]] name = "terminal" # no command — just an empty shell ``` ### `name` Required. The workspace label herdr-plus gives the project's workspace, and the text you fuzzy-find in the browser. ### `description` Optional free text shown next to the name in the browser. ### `group` Optional. A label that clusters related projects in the browser — see [Grouping projects by client](#grouping-projects-by-client). It has no effect on the workspace that opens; it only changes how the browser is laid out. ### `working_dir` The directory the workspace is rooted at. A leading `~` expands to your home directory, and any `$VARS` in the path are expanded from your environment. An empty (or `~`) `working_dir` defaults to your home directory, so a minimal project still opens somewhere sensible. > **Important:** The working directory's existence is checked when you *open* the > project, not when the file is loaded. (The same project file might be valid on > one machine and not another.) If the directory doesn't exist, opening the > project fails with a clear error. ### `[[tabs]]` A project needs **at least one** `[[tabs]]` entry. Tabs are created in file order. Each tab has: - `name` — **required**, the tab's label. - `command` — optional. The startup command, run as if typed at the prompt. A tab with no `command` (and no panes) is just an empty shell. The first tab reuses the workspace's root tab (it's renamed to the tab's name); every later tab is created behind it. ## Split panes within a tab A tab can hold up to **4 panes**. Instead of a single `command`, give the tab `[[tabs.panes]]` entries: ```toml [[tabs]] name = "server" [[tabs.panes]] command = "php artisan serve" [[tabs.panes]] command = "npm run dev" split = "down" ``` Each pane: - `command` — optional. The command to run in that pane on startup. A pane with no command is an empty shell. - `split` — how the pane is created relative to the *previous* pane in the tab: - `"down"` — stacked below (top/bottom). - `"right"` — beside it (side by side). - Omitted — defaults to `"down"`. The **first pane is the tab's root**, so its `split` is ignored. Each later pane splits off the one before it. ### `command` vs. `[[tabs.panes]]` are mutually exclusive A tab uses *either* `command` *or* `[[tabs.panes]]`, not both. Setting both is a config error reported when the project loads. A tab with neither is a single empty shell. > **Tip:** In the projects browser, split tabs are shown with a `×N` pane count > (e.g. `server ×2`) so you can see the layout at a glance. A tab may declare at most 4 panes; more than that is a load-time error. ## Grouping projects by client Give a project a [`group`](#group) and the browser clusters projects that share that label under a heading. This is built for the common case where **one client has several projects** — tag each with the client's name and they sit together: ```toml name = "Acme — Web" group = "Acme Co." working_dir = "~/Clients/acme/web" [[tabs]] name = "editor" command = "spiceedit" ``` How the browser lays out: - **Headings appear only when used.** If no project sets a `group`, the browser is a plain, flat list exactly as it was before — nothing changes. - **Named groups come first**, in case-insensitive alphabetical order by group name. A client's projects keep their usual name order under the heading. - **Group-less projects** fall under a catch-all **Ungrouped** heading at the bottom, so a mix of grouped and ungrouped projects is always clearly labeled. - **Search is unchanged.** Start typing and the headings drop away — you filter a single ranked list across every project, grouped or not. ## Adding and removing projects The model is one file per project: - **Add a project** — drop a new `.toml` file into `~/.config/herdr-plus/projects/`. - **Remove a project** — delete its file. Projects are sorted by name in the browser, and clustered under group headings when any project sets a [`group`](#grouping-projects-by-client). A malformed or invalid project file fails the whole load with a message naming the offending file, so a config mistake surfaces loudly instead of a project silently going missing. ## See also - [Configuration](../configuration/) — the full directory layout and XDG behavior. - [Examples & Cookbook](../examples/) — ready-to-copy project files. - [Quick Actions](../quick-actions/) — the other mode. ================================================================================ # Quick Actions Mode The fuzzy launcher: pick an action and run it in a split. Covers global actions and per-project actions shipped in a repo's .herdr-plus directory. Source: https://herdrplus.com/docs/quick-actions/ Quick Actions is a fuzzy launcher. Press `prefix+down`, type a few characters to filter, pick an action, and it runs in a split pane. ## What it does Pressing `prefix+down` opens a focused split *beneath* your current pane and runs the picker there. The picker is a fuzzy finder over your actions: - `↑`/`↓` (or `ctrl+p`/`ctrl+n`, or the mouse wheel) move the highlight. - Type to filter the list. - `enter` or a left-click runs the highlighted action. - `esc` (or `ctrl+c`) cancels. When you choose an action, the picker runs it in that split, then **closes its own pane** so focus returns to where you launched from. (The launch directory is the working directory of the pane you launched from, so actions run in the right place.) > **Tip:** A fast command's output would flash by before the pane closes. To hold > the pane open so you can read it, end the command with a wait — see the > [Actions Reference](../actions/) and [Examples](../examples/) for the > keep-open patterns (`read **Note:** This very repository ships a per-project set as a live example — > `make build` and `make test` — so you can see the `Project` grouping in action. ## What goes in an action file Every action — global or per-project — is a TOML file with a `name`, `description`, `command`, and `type`. There are three types: `command`, `select`, and `form`. The full format is documented in the [Actions Reference](../actions/), and the variables available to a command are in [Template Variables](../variables/). ## See also - [Actions Reference](../actions/) — the complete action file format. - [Template Variables](../variables/) — context you can use in a command. - [Examples & Cookbook](../examples/) — ready-to-copy actions. - [Configuration](../configuration/) — the on-disk layout. ================================================================================ # Actions Reference The complete action file format: the command, command/select/form types, separators and headings, and how the value is passed. Source: https://herdrplus.com/docs/actions/ An action is one entry in the quick-actions picker, loaded from a TOML file in the mode's config directory. This page documents the complete file format. ## The basics Every action has four fields: | Field | Required | Meaning | |-------|----------|---------| | `name` | yes | Shown in the picker; the text you fuzzy-find. | | `description` | no | Dim text shown next to the name. | | `command` | yes | The shell command run when the action completes. | | `type` | no | `command` (default), `select`, or `form`. | `name` and a non-empty `command` are required; an action missing either fails to load with a clear error. An unknown `type` is also a load-time error. ## How the command runs The `command` is run through `sh -c`, in the working directory you launched herdr-plus from, with the run context exported as `HERDR_PLUS_*` environment variables. Running through `sh -c` means commands can use pipes, arguments, and full scripts. The `command` is also a [Go text/template](https://pkg.go.dev/text/template) rendered against the run context — so it can reference fields like `{{.Value}}`, `{{.WorkDir}}`, and `{{.SessionTitle}}` (see [Template Variables](../variables/)). ## Type: `command` (default) Runs immediately when selected — no further input. This is the simplest possible action: just a name, a description, and a command. `type` defaults to `command` when omitted. ```toml name = "GitHub" description = "Open https://github.com" command = "open https://github.com" ``` ## Type: `select` Shows a second fuzzy list of options. The chosen option's `value` becomes `{{.Value}}` in the command. ```toml name = "Open Repo on GitHub" description = "Pick a repo and open it" type = "select" command = "open https://github.com/cloudmanic/{{.Value}}" [[options]] label = "Herdr Plus" value = "herdr-plus" description = "cloudmanic/herdr-plus" [[options]] label = "Options Cafe" value = "options-cafe" description = "cloudmanic/options-cafe" ``` Each option: - `label` — what the user sees in the list. **Required for a selectable option.** - `value` — what gets substituted into the command. **If omitted, the `label` is used as the value too.** - `description` — optional dim text shown next to the label. The `value` itself is never shown, so you can encode data into it (e.g. a host and URL) without cluttering the list. A `select` action needs at least one selectable option (one with a label), or it fails to load. ### Separators and headings To visually group options, add a **separator**: an option with **no `label`**. Give it a `heading` to show a dim group title, or leave it blank for a plain spacer. ```toml [[options]] heading = "Cascade" # a labeled group header [[options]] label = "Options Cafe" value = "cascade https://github.com/users/cloudmanic/projects/8" [[options]] # a blank spacer (no label, no heading) [[options]] label = "Options Cafe (Rager)" value = "rager https://github.com/users/cloudmanic/projects/8" ``` Separators are **not selectable**, are **skipped** when navigating, and **disappear** while you filter. ## Type: `form` Shows a single text field. Whatever you type becomes `{{.Value}}` in the command. The `[form]` table is optional. ```toml name = "Search Google" description = "Type a query and open the results" type = "form" command = "open 'https://www.google.com/search?q={{.Value | urlquery}}'" [form] prompt = "Search Google for" placeholder = "e.g. herdr terminal multiplexer" ``` The `[form]` table customizes the field: - `prompt` — the label rendered above the input. Defaults to `Enter a value`. - `placeholder` — the greyed-out hint in the empty field. Defaults to `Type a value…`. Your input is trimmed of surrounding whitespace before it becomes `{{.Value}}`. ## Passing the value For `select` and `form` actions there's a resolved value (the option's value or your typed text). herdr-plus passes it to the command one of two ways: - **If your command references `{{.Value}}`,** the value is substituted exactly there. - **If it doesn't,** the value is appended as a **single shell-quoted final argument** — so `command = "my-script"` becomes `my-script 'the value'`. This lets a command either position the value precisely with `{{.Value}}` or just receive it as its last argument. > **Note:** A plain `command` action has no value, so nothing is appended. ## Template functions Because the command is a Go `text/template`, the standard template functions are available. The most useful for actions is `urlquery`, which escapes text so it's safe inside a URL: ```toml command = "open 'https://www.google.com/search?q={{.Value | urlquery}}'" ``` ## See also - [Template Variables](../variables/) — every field you can reference. - [Examples & Cookbook](../examples/) — ready-to-copy actions. - [Quick Actions](../quick-actions/) — how actions are launched. ================================================================================ # Template Variables Every context field an action's command can use, both as a Go template field and as a HERDR_PLUS_* environment variable. Source: https://herdrplus.com/docs/variables/ Every action's command template can use these fields. The same values are also exported to the command's environment with a `HERDR_PLUS_` prefix — so a script that would rather not bother with templating can read them straight from the environment. ## The variables | Template | Env var | Meaning | |----------|---------|---------| | `{{.Value}}` | `HERDR_PLUS_VALUE` | Selected option / entered text (select & form). | | `{{.WorkDir}}` | `HERDR_PLUS_WORKDIR` | Directory you launched herdr-plus from. | | `{{.SessionTitle}}` | `HERDR_PLUS_SESSION_TITLE` | herdr workspace label (often the repo name). | | `{{.SessionId}}` | `HERDR_PLUS_SESSION_ID` | herdr workspace id. | | `{{.WorkspaceLabel}}` | `HERDR_PLUS_WORKSPACE_LABEL` | Same as SessionTitle. | | `{{.WorkspaceId}}` | `HERDR_PLUS_WORKSPACE_ID` | Same as SessionId. | | `{{.TabLabel}}` | `HERDR_PLUS_TAB_LABEL` | herdr tab label. | | `{{.TabId}}` | `HERDR_PLUS_TAB_ID` | herdr tab id. | | `{{.PaneId}}` | `HERDR_PLUS_PANE_ID` | Pane you launched from. | | `{{.TerminalId}}` | `HERDR_PLUS_TERMINAL_ID` | herdr terminal id. | | `{{.Agent}}` | `HERDR_PLUS_AGENT` | Agent running in the pane, if any. | | `{{.AgentSessionId}}` | `HERDR_PLUS_AGENT_SESSION_ID` | That agent's session id. | | `{{.Home}}` | — | Your home directory. | ## Two ways to use them Every field above is available **both** as a Go template field in the `command` and as a `HERDR_PLUS_` environment variable when the command runs. For example, `{{.WorkDir}}` is also `$HERDR_PLUS_WORKDIR`. > **Note:** `{{.Home}}` is the one exception — it is available as a template > field but has **no** environment variable. ## Examples Using a variable in the command template — open the launch directory in your file manager: ```toml name = "Reveal Working Dir" description = "Open the launch directory" type = "command" command = "open {{.WorkDir}}" ``` Using the environment variable instead — a command that prefers `$HERDR_PLUS_*` over templating: ```toml name = "Print Context" description = "Echo the workspace label and working dir" type = "command" command = 'echo "workspace=$HERDR_PLUS_WORKSPACE_LABEL dir=$HERDR_PLUS_WORKDIR"' ``` > **Tip:** Any field herdr can't supply is left empty rather than failing — a > partial context is better than refusing to launch. Fields like `{{.Agent}}` or > `{{.AgentSessionId}}` will be blank when no agent is running in the pane. ## See also - [Actions Reference](../actions/) — where these variables are used. - [Examples & Cookbook](../examples/) — actions that use context variables. ================================================================================ # Configuration The herdr-plus config directory layout: projects/, quick-actions/, the file-per-entry model, per-repo overrides, and XDG_CONFIG_HOME. Source: https://herdrplus.com/docs/configuration/ All herdr-plus configuration lives under `~/.config/herdr-plus/`, honoring `$XDG_CONFIG_HOME`. There's no central config file — everything is a file per entry. ## Directory layout ```text ~/.config/herdr-plus/ projects/ # one *.toml per project (control mode) options-cafe.toml bevio.toml ... quick-actions/ # one *.toml per action (quick-actions mode) github.toml google.toml ... ``` - **`projects/`** holds your [project templates](../projects/) for control mode. Each `*.toml` defines one project. This directory **starts empty** — control mode's onboarding screen explains how to add your first one. - **`quick-actions/`** holds your [quick actions](../quick-actions/). Each `*.toml` defines one action. This directory is **seeded with editable examples** the first time you run the mode. The per-mode subdirectory name is the mode's slug (`quick-actions`), so future modes get their own folder. Projects hang directly off the config root (not under a mode slug) because they're a first-class concept. ## The file-per-entry model In both directories the rule is the same: **add a file to add an entry, delete a file to remove it.** File names don't matter — only the contents. Entries are sorted by their `name` in the UI. > **Important:** A malformed or invalid file fails the whole load for that > directory, with an error naming the offending file. This is deliberate: a typo > surfaces loudly instead of an entry silently going missing. ### Seeding behavior - `quick-actions/` is seeded with bundled examples **only** when the directory doesn't yet exist. Once it exists, herdr-plus leaves it alone — so deleting an example won't make it reappear. - `projects/` is never seeded. An empty directory is meaningful: it triggers control mode's onboarding empty-state. herdr-plus only ever creates the empty folder for you to drop files into. ## Per-project (per-repo) overrides A repo can ship its own quick actions. Add a `.herdr-plus/` directory at the repo root that mirrors the global layout, with one `*.toml` per action in its `quick-actions/` subdirectory: ```text your-repo/ .herdr-plus/ quick-actions/ make-build.toml make-test.toml ``` When you launch the quick-actions picker from inside that repo, these actions appear grouped under a `Project` heading above your `Global` ones. The directory is **read-only and never auto-created** — it's read only when a repo actually provides it. See [Quick Actions](../quick-actions/) for the full behavior. ## `XDG_CONFIG_HOME` behavior herdr-plus follows the XDG convention: - If `XDG_CONFIG_HOME` is set, config lives in `$XDG_CONFIG_HOME/herdr-plus/`. - Otherwise it falls back to `~/.config/herdr-plus/`, so the location is the same on macOS and Linux. > **Note:** herdr's own config (the `config.toml` that `herdr-plus install` > writes to) follows the same rule under `herdr/` rather than `herdr-plus/`. See > [Keybindings](../keybindings/). ## See also - [Control Mode & Projects](../projects/) — the project file format. - [Actions Reference](../actions/) — the action file format. - [Examples & Cookbook](../examples/) — ready-to-copy files. ================================================================================ # Examples & Cookbook A copy-pasteable gallery of complete quick actions and project templates — commands, selects, forms, splits, and context variables. Source: https://herdrplus.com/docs/examples/ A gallery of complete, copy-pasteable examples. Drop a quick action into `~/.config/herdr-plus/quick-actions/`, or a project into `~/.config/herdr-plus/projects/` — one file per entry, file name up to you. ## Quick actions ### A plain command The simplest action: run a command immediately. ```toml # google.toml name = "Google" description = "Open https://google.com" type = "command" command = "open https://google.com" ``` ### Open a URL `type` defaults to `command`, so you can omit it. ```toml # github.toml name = "GitHub" description = "Open https://github.com" command = "open https://github.com" ``` ### Open the current repo on GitHub Uses the launch context. This opens the `origin` remote of whatever repo your pane is in, in your browser. ```toml # open-repo-on-github.toml name = "Open This Repo on GitHub" description = "Open the current repo's GitHub page" type = "command" command = "open \"$(git -C {{.WorkDir}} remote get-url origin | sed -E 's#git@github.com:#https://github.com/#; s#\\.git$##')\"" ``` ### A `select` with grouped options and separators A second fuzzy list. Headings group the options; a blank separator adds a spacer. ```toml # open-repo.toml name = "Open Repo on GitHub" description = "Pick one of our repos and open it" type = "select" command = "open https://github.com/cloudmanic/{{.Value}}" [[options]] heading = "Apps" [[options]] label = "Options Cafe" value = "options-cafe" description = "cloudmanic/options-cafe" [[options]] label = "Skyclerk" value = "skyclerk" description = "cloudmanic/skyclerk" [[options]] # blank spacer [[options]] heading = "Tools" [[options]] label = "Herdr Plus" value = "herdr-plus" description = "cloudmanic/herdr-plus" ``` ### A `form` with `urlquery` Type a query; `urlquery` escapes it so it's URL-safe. ```toml # google-search.toml name = "Search Google" description = "Type a query and open the results" type = "form" command = "open 'https://www.google.com/search?q={{.Value | urlquery}}'" [form] prompt = "Search Google for" placeholder = "e.g. herdr terminal multiplexer" ``` ### A "search docs" form Same idea, pointed at a docs site. ```toml # search-docs.toml name = "Search herdr Docs" description = "Open the docs search for a term" type = "form" command = "open 'https://herdr.dev/?q={{.Value | urlquery}}'" [form] prompt = "Search the docs for" placeholder = "e.g. keybindings" ``` ### Using a context variable Open the directory you launched from in your file manager. ```toml # reveal-working-dir.toml name = "Reveal Working Dir" description = "Open the launch directory in Finder" type = "command" command = "open {{.WorkDir}}" ``` ### A project-local action that keeps the pane open For per-project actions (in a repo's `.herdr-plus/quick-actions/`), end the command with a wait so its output doesn't flash by before the picker pane closes. The action's stdin is `/dev/null`, so the wait must read the terminal directly via ` **Note:** The *keybinding* itself uses the binary's **absolute path**, so a > bound key works even when `herdr-plus` isn't on your PATH. The "command not > found" error only bites when you type `herdr-plus` at a prompt. ## "key is already bound to: ..." `install` refuses to overwrite a key that's bound to something else — it never clobbers a binding it didn't create. Pick a different key: ```bash herdr-plus install --key=prefix+a ``` If you really want that key, remove the conflicting `[[keys.command]]` entry from herdr's `config.toml` first, then re-run `install`. > **Tip:** Re-running `install` for a mode that's already bound is safe — it > won't duplicate the binding, it just reports where the existing one lives. ## My config / action / project isn't picked up 1. **Right directory?** Quick actions go in `~/.config/herdr-plus/quick-actions/`; projects go in `~/.config/herdr-plus/projects/`. Per-project quick actions go in a repo's `.herdr-plus/quick-actions/`. 2. **`XDG_CONFIG_HOME` set?** If it is, config lives under `$XDG_CONFIG_HOME/herdr-plus/`, not `~/.config/herdr-plus/`. See [Configuration](../configuration/). 3. **Is the file `*.toml`?** Only files ending in `.toml` are loaded. 4. **Is the TOML valid?** A malformed or invalid file fails the **whole** load for that directory, with an error naming the offending file. herdr-plus leaves the pane open so you can read the error. Fix the named file. 5. **Required fields present?** Actions need a `name` and a non-empty `command`; `select` actions need at least one option with a label. Projects need a `name` and at least one `[[tabs]]` entry, and each tab needs a `name`. ## My per-project actions don't show up 1. **`.herdr-plus/quick-actions/` at the repo root?** The directory must mirror the global layout and sit at the root of the repo. 2. **Launched from inside the repo?** Project actions appear only when the pane's working directory is inside that repo — that's the launch directory herdr-plus uses. 3. **The directory is never auto-created.** herdr-plus won't make it for you; the repo has to provide it. See [Quick Actions](../quick-actions/) for the full behavior. ## A project's working directory error Opening a project fails with "working directory does not exist" when its `working_dir` doesn't resolve to a real directory on this machine. The path is checked at open time, not load time, so the same file can be valid elsewhere. Fix the `working_dir` (remember `~` and `$VARS` expand). See [Control Mode & Projects](../projects/). ## Template errors in a command The `command` is a Go `text/template`. A bad field name or malformed `{{...}}` produces a parse or render error when the action runs (printed to stderr). - Check your field names against [Template Variables](../variables/) — they're case-sensitive (`{{.WorkDir}}`, not `{{.workdir}}`). - Make sure braces are balanced: `{{.Value}}`, not `{{.Value}` or `{.Value}}`. ## My action's output flashed by before I could read it The quick-actions pane closes itself once the command finishes. To hold it open, end the command with a wait that reads the terminal directly (its stdin is `/dev/null`): ```text read _