A practical guide to Herdr plugins

By

Install, inspect, configure, run, and build Herdr plugins, with practical commands and the security checks to make before trusting one.

~~~

Herdr plugins are executable workflow packages.

They can create a project layout, add an action, react to an event, open a terminal pane, or connect Herdr to another local tool.

A plugin can be written in Bash, JavaScript, PowerShell, Lua, Rust, or any other language your machine can run.

There is no separate plugin SDK.

Herdr provides the host: installation, the manifest, keybindings, events, panes, logs, and runtime context. The plugin calls the normal Herdr CLI or socket API when it needs to control the workspace.

In this guide we’ll install a plugin, inspect it, run an action, and build a small local plugin.

For the broader terminal and agent model, read my Herdr deep dive first.

Find a plugin

Community plugins are listed at herdr.dev/plugins.

The marketplace is an automatic index of public GitHub repositories tagged with herdr-plugin. A listing is not a security review.

Before installing anything:

  1. Open the repository.
  2. Read herdr-plugin.toml.
  3. Check the build and runtime commands.
  4. Inspect the scripts or source code those commands run.
  5. Decide whether you trust the author.

Herdr plugins run as your user. They inherit your environment and can call the full Herdr CLI. They are not sandboxed.

Treat one like a shell script or editor extension you are about to run locally.

Install a plugin from GitHub

The install command accepts GitHub shorthand:

herdr plugin install owner/repository

If the repository contains several plugins, add the subdirectory:

herdr plugin install owner/repository/path/to/plugin

For example, the official documentation uses this community example:

herdr plugin install \
  ogulcancelik/herdr-plugin-examples/agent-telegram-notify

In an interactive terminal, Herdr shows the source and the commands it plans to run before asking for confirmation.

Do not add --yes the first time you install a plugin. That flag skips the interactive confirmation and is better reserved for a source and revision you have already reviewed.

You can pin a Git ref:

herdr plugin install \
  owner/repository/path/to/plugin \
  --ref v1.2.0

Herdr uses Git, runs the build commands declared in the manifest, stores the checkout in a managed directory, and registers the plugin.

If a build command fails, the plugin is not registered.

List and inspect installed plugins

List everything:

herdr plugin list

Ask for structured output when you are scripting:

herdr plugin list --json

Filter by plugin ID:

herdr plugin list --plugin examples.agent-telegram-notify

The plugin ID comes from its manifest. It does not have to match the GitHub repository name.

Plugin installation and enabled state are global for the current user. Install a plugin in one named Herdr session and it is available in the others too.

Configure a plugin

Each plugin gets a stable configuration directory.

Print it with:

herdr plugin config-dir examples.agent-telegram-notify

Put user-editable settings such as an .env file there when the plugin documentation asks for them.

Do not put credentials inside the managed plugin checkout. Reinstalling a GitHub plugin replaces that checkout.

Herdr also gives a plugin a separate state directory at runtime. The plugin owns the files and data format inside it.

Run plugin actions

List the actions a plugin exposes:

herdr plugin action list \
  --plugin examples.agent-telegram-notify

Invoke one:

herdr plugin action invoke \
  examples.agent-telegram-notify.send-test

The exact action IDs depend on the manifest.

If action names collide across plugins, use the fully qualified form:

plugin.id.action

You can bind an action in ~/.config/herdr/config.toml:

[[keys.command]]
key = "prefix+l"
type = "plugin_action"
command = "example.layout.apply"
description = "apply layout"

Reload the configuration:

herdr server reload-config

Open a plugin pane

A plugin can declare terminal pane entrypoints.

List or read the plugin documentation to find the entrypoint ID, then open it:

herdr plugin pane open \
  --plugin example.layout \
  --entrypoint board

Herdr supports several placements:

You can override the manifest placement:

herdr plugin pane open \
  --plugin example.layout \
  --entrypoint board \
  --placement popup \
  --width 80% \
  --height 20

A popup is intentionally temporary. Normal split, tab, zoomed, and overlay panes participate in the usual Herdr pane APIs.

Read plugin logs

If an action fails, inspect its command log:

herdr plugin log list \
  --plugin example.layout \
  --limit 20

The log tells you which declared command ran and how it exited.

It does not interpret the tool’s output for you. A failing Node, Bash, or Rust command is still debugged as that kind of program.

Disable, enable, and remove plugins

Temporarily disable a plugin:

herdr plugin disable example.layout

Enable it again:

herdr plugin enable example.layout

Uninstall a GitHub-managed plugin:

herdr plugin uninstall example.layout

You can also use the original source shorthand:

herdr plugin uninstall owner/repository/path/to/plugin

There is no separate plugin update command in the current plugin system. Reinstall the GitHub source to refresh its managed checkout.

Build a small local plugin

Let’s create an action that lists the current Herdr workspaces.

The directory has two files:

workspace-tools/
  herdr-plugin.toml
  index.js

The manifest is:

id = "example.workspace-tools"
name = "Workspace Tools"
version = "0.1.0"
min_herdr_version = "0.7.0"
description = "Small workspace helpers"
platforms = ["linux", "macos", "windows"]

[[actions]]
id = "list-workspaces"
title = "List workspaces"
contexts = ["workspace"]
command = ["node", "index.js"]

Herdr runs commands as argv arrays. It does not send them through a shell, so shell expansion does not happen unless the declared command starts a shell itself.

The JavaScript file can call the installed Herdr binary:

const { spawnSync } = require('node:child_process')

const herdr = process.env.HERDR_BIN_PATH ?? 'herdr'

const result = spawnSync(
  herdr,
  ['workspace', 'list'],
  {
    encoding: 'utf8',
    stdio: ['ignore', 'pipe', 'pipe'],
  },
)

process.stdout.write(result.stdout)
process.stderr.write(result.stderr)
process.exit(result.status ?? 1)

HERDR_BIN_PATH is better than hardcoding herdr. It points to the binary that owns the running session and works across Unix sockets and Windows named pipes.

During development, link the local directory:

herdr plugin link /absolute/path/to/workspace-tools

List and invoke the action:

herdr plugin action list \
  --plugin example.workspace-tools

herdr plugin action invoke \
  example.workspace-tools.list-workspaces

Read the log if it fails:

herdr plugin log list \
  --plugin example.workspace-tools

When you are done testing, unlink it:

herdr plugin unlink example.workspace-tools

Unlinking removes the registration and leaves your local files alone.

Notice that plugin link does not run manifest build commands. You are working from a live checkout, so you build it yourself.

What a manifest can declare

A plugin manifest can currently define:

EntryUse
[[build]]Prepare a GitHub-installed plugin
[[startup]]Run one initialization command after server restore
[[actions]]Expose commands that people, keys, or tools can invoke
[[events]]React to known Herdr events
[[panes]]Open a terminal interface managed by the plugin
[[link_handlers]]Route matching terminal links to a plugin action

Startup hooks are one-shot initialization commands, not supervised background services.

Actions and panes are declared in the manifest. Runtime action registration and native non-terminal plugin interfaces are not part of the current v1 surface.

Runtime context

Herdr starts plugin commands inside the plugin directory and injects useful variables, including:

HERDR_BIN_PATH
HERDR_ENV
HERDR_PLUGIN_ID
HERDR_PLUGIN_ROOT
HERDR_PLUGIN_CONFIG_DIR
HERDR_PLUGIN_STATE_DIR
HERDR_PLUGIN_CONTEXT_JSON
HERDR_WORKSPACE_ID
HERDR_TAB_ID
HERDR_PANE_ID

Not every invocation has every workspace, tab, or pane value.

HERDR_PLUGIN_CONTEXT_JSON can include the focused pane, worktree, agent, selected text, or clicked URL. Use it when the action needs more than the common IDs.

My recommendation

Start by installing one small plugin from a repository you have read.

Learn these four commands first:

herdr plugin list
herdr plugin action list --plugin ID
herdr plugin action invoke ID.ACTION
herdr plugin log list --plugin ID

Then build one local action and link it.

Herdr plugins are deliberately simple. The manifest describes how a workflow connects to Herdr, while the actual program remains a normal command you can run, inspect, and debug.

The complete manifest reference is in the official Herdr plugin guide. If you want an agent to operate the workspace for you, read how to use the Herdr skill.

Tagged: AI · All topics
~~~

Related posts about ai: