# herdr plus — Complete Documentation > herdr-plus is a collection of tools that supercharge herdr — quick actions and projects for your terminal. Free and open-source, 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 for [herdr](https://herdr.dev), built as a first-class [herdr plugin](https://herdr.dev/docs/plugins/). It is free and open source, built by [Cloudmanic Labs](https://github.com/cloudmanic/herdr-plus). ## The mental model You install herdr-plus once with `herdr plugin install`. herdr clones the repo, builds it, and registers the plugin's **actions** with herdr. From then on you run those actions — from herdr's action menu, or from a key you bind to them — and they spring to life inside herdr. Two actions ship today: | Action id | What it does | |-----------|--------------| | `cloudmanic.herdr-plus.projects` | Opens a full-screen fuzzy browser of your **Projects** — declarative templates that spin up a whole herdr workspace. | | `cloudmanic.herdr-plus.quick-actions` | Opens the **Quick Actions** launcher — a fuzzy finder that runs a one-off action in the directory you launched from. | Everything herdr-plus does is driven by plain TOML files you own, kept in herdr's managed plugin config directory. We expect the list of features to grow. ## Where to start - **[Quick Start](quick-start/)** — the fastest path from zero to a working keybinding. - **[Installation](installation/)** — installing the plugin, the optional standalone binary, and how upgrades work. - **[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. - **[Worktree Auto-Layout](worktrees/)** — auto-open a tab layout whenever herdr creates a matching git worktree, with a per-layout on/off switch. If you just want the reference, jump to [Keybindings](keybindings/), 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 plugin in four steps: install herdr, install the plugin, run an action, and optionally bind a key. Source: https://herdrplus.com/docs/quick-start/ This is the fastest path from zero to running herdr-plus. Four steps, a couple of minutes. ## 1. Make sure herdr is installed and running herdr-plus is a plugin for [herdr](https://herdr.dev) and needs **herdr ≥ 0.7.0**. Follow the [herdr install guide](https://herdr.dev/docs/install/), and make sure you're inside a herdr session — herdr-plus does its work by talking to the running herdr server. ## 2. Install the plugin ```bash herdr plugin install cloudmanic/herdr-plus ``` herdr clones the repo, builds it (with or without Go), and registers the plugin's actions. That's the whole install — see [Installation](../installation/) for local development, the optional standalone binary, and how upgrades work. ## 3. Run an action herdr-plus registers two actions. You can run either one straight from **herdr's action menu** — no configuration required: - `cloudmanic.herdr-plus.projects` opens the **Projects** browser — a full-screen fuzzy picker. With no project files yet, it shows an onboarding card explaining how to add your first one. - `cloudmanic.herdr-plus.quick-actions` opens the **Quick Actions** launcher — a fuzzy finder over your actions. The first time you open it, herdr-plus seeds your config with editable example actions so you have something to try right away. ## 4. (Optional) Bind a key If you'd rather not open the action menu each time, bind each action to a herdr key. Add two `[[keys.command]]` entries with `type = "plugin_action"` to your herdr `config.toml`: ```toml [[keys.command]] key = "prefix+up" type = "plugin_action" command = "cloudmanic.herdr-plus.projects" description = "herdr-plus: projects" [[keys.command]] key = "prefix+down" type = "plugin_action" command = "cloudmanic.herdr-plus.quick-actions" description = "herdr-plus: quick actions" ``` Then reload with `herdr server reload-config` (or restart herdr). Now press your prefix (default `ctrl+b`), release it, and press the bound key — `up` for Projects, `down` for Quick Actions. See [Keybindings](../keybindings/) for the full story. ## Next steps - [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 as a herdr plugin with herdr plugin install — plus the optional standalone binary, supported platforms, and how upgrades work. Source: https://herdrplus.com/docs/installation/ herdr-plus is a [herdr plugin](https://herdr.dev/docs/plugins/). Installing it is one command — herdr does the rest. > **Note:** herdr-plus is an add-on for [herdr](https://herdr.dev) and requires > **herdr ≥ 0.7.0**. Install and set up herdr first — herdr-plus does its work by > talking to a running herdr server. ## Install the plugin ```bash herdr plugin install cloudmanic/herdr-plus ``` herdr clones the repository, runs the manifest's build step, and registers the plugin's actions. The build step **prefers a local Go toolchain** (an exact build of the cloned source) and **falls back to downloading the latest prebuilt release binary**, so it works **with or without Go**. > **Windows** (herdr's Windows support is in preview): the plugin's Windows build > step compiles straight from source with the Go toolchain — there is **no > prebuilt-binary fallback** like the Linux/macOS `sh` script has — so **Go must > be on your `PATH`** to install. On Windows the plugin talks to herdr over a > named pipe rather than a unix socket. After it finishes, manage the plugin with: ```bash herdr plugin list # confirm it's registered herdr plugin action list --plugin cloudmanic.herdr-plus # see its actions herdr plugin uninstall cloudmanic.herdr-plus # remove it ``` > Uninstalling removes the plugin's clone and registration but **preserves your > config directory**, so your projects and quick actions survive a reinstall. ## How upgrades work Re-running the install command **is** the upgrade — herdr re-clones, rebuilds, and re-registers in place: ```bash herdr plugin install cloudmanic/herdr-plus ``` Every merge to `main` cuts a new release, so a re-install always pulls the latest. You can pin a specific ref with `--ref ` if you need a particular version. ## Local development To hack on herdr-plus, build the binary and link your checkout in place instead of installing from GitHub: ```bash make build herdr plugin link /path/to/herdr-plus # or: make plugin-link ``` herdr then runs the freshly built `./bin/herdr-plus` for the plugin's actions. Undo with `herdr plugin unlink cloudmanic.herdr-plus`. ## The optional standalone binary You don't need the `herdr-plus` binary on your `PATH` — the plugin install handles everything. But if you'd like it there (for example to run `herdr-plus version`), prebuilt binaries are published on every release. **Homebrew** — the repository 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). It detects your OS/arch, downloads the matching archive from the latest GitHub Release, and drops the static binary into place: ```bash curl -fsSL https://raw.githubusercontent.com/cloudmanic/herdr-plus/main/install.sh | sh ``` > The standalone binary on its own does **not** register the plugin with herdr — > use `herdr plugin install` (above) for that. ### Install-script overrides | 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. | ## Supported platforms Releases are cross-compiled for **Linux** and **macOS** on `amd64` (x86_64) and `arm64` (aarch64), plus **Windows** on `amd64` (shipped as a `.zip`). Windows support tracks herdr's Windows beta and is validated against it; installing on Windows builds from source, so it needs Go on your `PATH` (see the note above). ## Checking the version ```bash herdr-plus version ``` (`--version`, `-v`, and `-V` all work too.) ## Next steps With the plugin installed, run an action from herdr's action menu, or [bind it to a key](../keybindings/), then jump into the [Quick Start](../quick-start/). ================================================================================ # Keybindings Bind herdr keys to herdr-plus's plugin actions with [[keys.command]] entries (type = plugin_action), or just run them from herdr's action menu. Source: https://herdrplus.com/docs/keybindings/ herdr-plus registers two herdr **actions**: | Action id | Opens | |-----------|-------| | `cloudmanic.herdr-plus.projects` | The Projects browser | | `cloudmanic.herdr-plus.quick-actions` | The Quick Actions launcher | You can run either one **from herdr's action menu** without binding anything. If you'd rather trigger them with a keystroke, bind each to a key. ## Binding a key Keybindings are a one-time edit to **your** herdr `config.toml` — herdr-plus never touches it. Add a `[[keys.command]]` entry with `type = "plugin_action"` whose `command` is the action id: ```toml [[keys.command]] key = "prefix+up" type = "plugin_action" command = "cloudmanic.herdr-plus.projects" description = "herdr-plus: projects" [[keys.command]] key = "prefix+down" type = "plugin_action" command = "cloudmanic.herdr-plus.quick-actions" description = "herdr-plus: quick actions" ``` The keys above (`prefix+up` / `prefix+down`) are just a convention — bind whatever you like. ### Where the config lives herdr reads `$XDG_CONFIG_HOME/herdr/config.toml` if `XDG_CONFIG_HOME` is set, otherwise `~/.config/herdr/config.toml`. After editing it, reload so the bindings go live: ```bash herdr server reload-config # or just restart herdr ``` ## The herdr prefix herdr keybindings are *prefixed*: you press your herdr prefix (default `ctrl+b`), release it, then press the bound key. So to launch the action 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`. ## See also - [Installation](../installation/) — installing the plugin. - [Quick Start](../quick-start/) — the four-step path from zero. - [Troubleshooting](../troubleshooting/) — what to check when a key does nothing. ================================================================================ # Projects Projects are declarative herdr workspace templates — pick one from a full-screen fuzzy browser and herdr-plus spins up a whole workspace of tabs and panes. Source: https://herdrplus.com/docs/projects/ **Projects** are declarative herdr workspace templates that spin up a fully laid-out workspace with a single keypress. ## What it does Trigger the `cloudmanic.herdr-plus.projects` action — from herdr's action menu, or a [bound key](../keybindings/) — and herdr-plus opens a **full-screen fuzzy browser** of your projects. Fuzzy-find a project, press `enter` (or click it), and herdr-plus spins up a whole workspace — every tab created, every split laid out, and every startup command running — then drops you straight into it. Cancel with `esc` to close the browser and return to where you were. > **Note:** With no project files yet, the browser 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 the `projects/` subdirectory of [herdr-plus's config directory](../configuration/), **one TOML file per project**. The file name doesn't matter — only its contents. Find the directory with: ```bash herdr plugin config-dir cloudmanic.herdr-plus ``` 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. - `working_dir` — optional. The directory this tab starts in, overriding the project's. See [A directory per tab](#a-directory-per-tab). The first tab reuses the workspace's root tab (it's renamed to the tab's name); every later tab is created behind it. ## A directory per tab The project's `working_dir` is where every tab starts. A tab can override it, which is what a monorepo usually wants — the frontend and the backend each in their own subdirectory: ```toml name = "Shop" working_dir = "~/dev/shop" [[tabs]] name = "web" working_dir = "frontend" # relative to the project → ~/dev/shop/frontend command = "npm run dev" [[tabs]] name = "api" working_dir = "backend" # → ~/dev/shop/backend command = "make run" [[tabs]] name = "shell" # no working_dir → the project's ~/dev/shop ``` A **relative** path is resolved against the project's `working_dir`, so `"frontend"` means what it looks like rather than something relative to wherever herdr happens to be running. Absolute paths, `~`, and `$VARS` behave exactly as they do at the project level. Every directory must already exist. A missing one is reported *before* anything opens, so a typo never leaves a half-built workspace behind. ## 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"`. - `ratio` — optional. How much of the split this pane takes, between `0` and `1`. Omitted, the split is even. - `working_dir` — optional. The directory this pane starts in. Omitted, it inherits its tab's. See [A pane in its own directory](#a-pane-in-its-own-directory). The **first pane is the tab's root**, so its `split` and `ratio` are ignored. Each later pane splits off the one before it. ### Sizing a split `ratio` is the share the pane it is written on gets; the pane it splits off keeps the rest. Here the editor fills three quarters of the tab and lazygit sits in the last quarter: ```toml [[tabs]] name = "editor" [[tabs.panes]] command = "nvim" [[tabs.panes]] command = "lazygit" split = "right" ratio = 0.25 ``` A ratio outside `0`–`1` (a percentage like `30`, say) is a load-time error rather than a silently clamped layout. ### A pane in its own directory Panes start in their tab's directory. A pane that wants a different one says so, and the rest of the tab is unaffected: ```toml [[tabs]] name = "stack" working_dir = "frontend" [[tabs.panes]] command = "npm run dev" # frontend/ [[tabs.panes]] command = "psql shop" split = "right" working_dir = "../backend/db" # its own directory instead ``` A pane's `working_dir` resolves the same way a tab's does — relative to the project's `working_dir`, with `~` and `$VARS` expanded. ### `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 — 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. ## Opening a project by name The browser is interactive, but a project can also be opened directly — no picker, no fuzzy-typing — with the `open` subcommand: ```sh herdr-plus open harbor-sysadmin ``` It loads the same project templates the browser shows, resolves the one whose `name` matches — exactly first, then case-insensitively, so `open Harbor-Sysadmin` still finds `harbor-sysadmin` — and builds its workspace through the **same code path** the browser uses. There is one source of truth for turning a template into a live workspace. A name that matches nothing fails with the list of what is available. Run it from **inside herdr** — a pane's shell, a keybinding, a script, another tool. Like every herdr-plus command it reaches the running herdr over its socket, and it asks herdr where your templates live, so it finds exactly the ones the browser shows. That makes it the scriptable way to spin up a known workspace in one shot, which is handy for the two or three projects you open constantly: ```sh alias work='herdr-plus open my-work-app' ``` To get `herdr-plus` onto your `PATH`, see [Just the binary](https://github.com/cloudmanic/herdr-plus#just-the-binary) — installing the plugin alone does not put it there. > **Note:** A project whose `working_dir` is `{prompt}` can't be opened this way — > there's no picker to ask for the path. Use the browser for those. ## Adding and removing projects The model is one file per project: - **Add a project** — drop a new `.toml` file into the `projects/` subdirectory of [herdr-plus's config dir](../configuration/). - **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. - [Examples & Cookbook](../examples/) — ready-to-copy project files. - [Quick Actions](../quick-actions/) — the other feature. ================================================================================ # Quick Actions The fuzzy launcher: pick an action and run it in the directory you launched from. 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. Trigger it, type a few characters to filter, pick an action, and it runs — in the directory you launched from. ## What it does Trigger the `cloudmanic.herdr-plus.quick-actions` action — from herdr's action menu, or a [bound key](../keybindings/) — and herdr-plus opens a focused launcher over your workspace. The launcher 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, herdr-plus runs it and then **closes the launcher**, handing focus back to where you were. The command runs in the **working directory of the pane you launched from**, so actions act on the right place. > **Tip:** A fast command's output would flash by before the launcher closes. To > hold it 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. ================================================================================ # Worktree Auto-Layout Automatically lay a project-style tab layout into a git worktree the moment herdr creates or opens it, driven by the plugin's worktree.created and worktree.opened events. Source: https://herdrplus.com/docs/worktrees/ herdr-plus can open a project-style tab layout **automatically** when herdr creates or opens a git worktree — no keypress, no picker. It's the plugin system's [`[[events]]`](https://herdr.dev/docs/plugins/) hook put to work: herdr-plus subscribes to the `worktree.created` and `worktree.opened` events and fills the worktree's workspace for you. ## How it works When you run `herdr worktree create` (or `herdr worktree open`, or use herdr's right-click worktree dialog), herdr: 1. Creates or opens the git worktree. 2. Makes a fresh herdr **workspace** for it, rooted at the worktree's directory. 3. Fires a `worktree.created` event (for a new worktree) or `worktree.opened` event (for an existing one). herdr-plus catches either event, looks at the worktree's **repo** (and branch), finds a matching layout, and opens that layout's tabs and panes in the workspace herdr just made — running every startup command. Because herdr has already created the workspace and its first tab, herdr-plus only has to fill it in. This reuses the exact same tab/pane model as [Projects](../projects/), so a worktree layout can do everything a project tab can, including multi-pane splits. ## Configuring a layout Layouts live in `~/.config/herdr-plus/worktrees/` (honoring `$XDG_CONFIG_HOME`), one TOML file per layout — the file name doesn't matter. A layout is a `repo` matcher plus an ordered list of `[[tabs]]`: ```toml repo = "options-cafe" # matches the worktree's repo name (case-insensitive) [[tabs]] name = "claude" command = "claude --dangerously-skip-permissions --chrome" [[tabs]] name = "lazygit" command = "lazygit" [[tabs]] name = "terminal" # no command — just an empty shell ``` Create a worktree of `options-cafe` and you land in a workspace with three tabs — `claude` running, `lazygit` running, and an empty `terminal` — every time. ## Turning a layout on and off The switch is simply **whether the file exists**: - **On:** a `*.toml` file in `worktrees/` for the repo. Create a worktree of that repo and the layout opens. - **Off:** delete the file (or move it out of `worktrees/`). Worktrees of that repo then open as a plain workspace, unchanged. With no `worktrees/` directory — or an empty one — herdr-plus does nothing at all. The event still fires for every worktree; herdr-plus just has no layout to apply. There's no separate enable/disable flag to keep in sync: the file's presence *is* the switch. ## Matching rules - **`repo`** (required) is matched case-insensitively against the new worktree's repository name (the repo's basename, e.g. `options-cafe`). It also matches the basename of the repo's root path, so it works regardless of how the worktree was created. - **`branch`** (optional) narrows a layout to worktrees created on exactly that branch (case-insensitive). Leave it off to apply to every branch of the repo. - When **more than one layout matches** the same worktree, a branch-specific layout wins over a repo-only one; otherwise the first by file name is used. ```toml # A branch-specific layout: only worktrees on the "release" branch get this one. repo = "options-cafe" branch = "release" [[tabs]] name = "deploy" command = "./scripts/release.sh" ``` ## Tabs and split panes The `[[tabs]]` format is identical to a project's. A tab can run a single `command`, or hold up to four panes via `[[tabs.panes]]` with `split = "down"` or `"right"` and an optional `ratio`, and either can set a `working_dir`. See [Split panes within a tab](../projects/#split-panes-within-a-tab) for the full vocabulary. A layout has no `working_dir` of its own — the worktree's checkout is the root — so a tab's relative `working_dir` is resolved against the worktree, which is what makes one layout work for every worktree of the repo. ## When nothing matches Every worktree creation fires the event, but if no layout matches the repo, herdr-plus does nothing — the feature is opt-in and silent. With no `worktrees/` directory at all, it's simply inert. ## Where it runs The handler is wired to the plugin's `worktree.created` and `worktree.opened` events, declared in `herdr-plugin.toml`. herdr runs it for you (you never invoke it by hand), and its output is captured in the plugin log: ```bash herdr plugin log list --plugin cloudmanic.herdr-plus ``` A line like `applied worktree layout "options-cafe.toml" to repo "options-cafe"` confirms a layout fired. `no worktree layout matches repo …` means nothing did — either there's no file for that repo, or its `repo`/`branch` didn't match. ## See also - [Projects](../projects/) — the on-demand cousin: pick a project and spin up its workspace by hand. - [Configuration](../configuration/) — where herdr-plus config lives. - [Troubleshooting](../troubleshooting/) — what to check when a layout doesn't fire. ================================================================================ # 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 herdr-plus's `quick-actions/` config directory (see [Configuration](../configuration/)). 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: herdr's managed plugin dir, the projects/, quick-actions/, and worktrees/ subdirs, the file-per-entry model, and per-repo overrides. Source: https://herdrplus.com/docs/configuration/ herdr-plus keeps its configuration in herdr's **managed plugin directory**. There's no central config file — everything is a file per entry. ## Finding the config directory Ask herdr where it is: ```bash herdr plugin config-dir cloudmanic.herdr-plus # → ~/.config/herdr/plugins/config/cloudmanic.herdr-plus ``` herdr provisions this directory for the plugin and **keeps it across uninstall and upgrade**, so your projects and quick actions survive a reinstall. > **Running outside herdr:** if you run the `herdr-plus` binary directly (not > through herdr), there's no managed directory to use, so it falls back to > `~/.config/herdr-plus/`, honoring `$XDG_CONFIG_HOME`. Inside herdr — the normal > case — the managed directory above always wins. ## Directory layout ```text / projects/ # one *.toml per project options-cafe.toml bevio.toml ... quick-actions/ # one *.toml per action github.toml google.toml ... worktrees/ # one *.toml per worktree auto-layout options-cafe.toml ... ``` - **`projects/`** holds your [project templates](../projects/). Each `*.toml` defines one project. This directory **starts empty** — the Projects browser'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 open the launcher. - **`worktrees/`** holds your [worktree auto-layouts](../worktrees/). Each `*.toml` defines one layout that fires when herdr creates a matching git worktree. This directory is **never created or seeded** — add it yourself to opt in. A layout is on simply by existing; delete the file to turn it off. ## 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 the Projects onboarding empty-state. - `worktrees/` is never created or seeded. It exists only if you add it, which is how the [worktree auto-layout](../worktrees/) feature stays opt-in. ## Per-project (per-repo) overrides A repo can ship its own quick actions. Add a `.herdr-plus/` directory at the repo root 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. ## See also - [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 the `quick-actions/` subdirectory of [herdr-plus's config dir](../configuration/), or a project into `projects/` — one file per entry, file name up to you. Find the directory with `herdr plugin config-dir cloudmanic.herdr-plus`. ## 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 `= 0.7.0: herdr plugin install cloudmanic/herdr-plus Find the config directory (projects/ and quick-actions/ live here): herdr plugin config-dir cloudmanic.herdr-plus Bind keys (optional — or run the actions from herdr's action menu). Add to herdr's config.toml, then run `herdr server reload-config`: [[keys.command]] key = "prefix+up" type = "plugin_action" command = "cloudmanic.herdr-plus.projects" [[keys.command]] key = "prefix+down" type = "plugin_action" command = "cloudmanic.herdr-plus.quick-actions" Optional standalone binary (only to get `herdr-plus` on your PATH; does NOT register the plugin with herdr): brew tap cloudmanic/herdr-plus https://github.com/cloudmanic/herdr-plus brew install cloudmanic/herdr-plus/herdr-plus curl -fsSL https://raw.githubusercontent.com/cloudmanic/herdr-plus/main/install.sh | sh License: MIT · Maintainer: Cloudmanic Labs, LLC (https://cloudmanic.com)