aboutsummaryrefslogtreecommitdiff
path: root/website/src/content/docs/plugins.mdx
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-06-15 19:02:40 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-06-15 19:03:24 +0300
commitbefe629312d9ddf0fea91d1c70f1e4c69afeaf76 (patch)
treed076758594991240682ef5ab28ccfc563a4edd3a /website/src/content/docs/plugins.mdx
parent99bf8dadeb03afcee6f1d0ff3af9b6f174a422f9 (diff)
docs: finalize 0.7.0 release docs
Diffstat (limited to 'website/src/content/docs/plugins.mdx')
-rw-r--r--website/src/content/docs/plugins.mdx294
1 files changed, 294 insertions, 0 deletions
diff --git a/website/src/content/docs/plugins.mdx b/website/src/content/docs/plugins.mdx
new file mode 100644
index 00000000..09d89bc0
--- /dev/null
+++ b/website/src/content/docs/plugins.mdx
@@ -0,0 +1,294 @@
+---
+title: Plugins
+description: Author local Herdr plugins with manifest actions, event hooks, and panes.
+---
+
+Herdr plugins are shareable, executable workflow packages. A plugin can be a
+Bash script, JavaScript app, Lua script, Rust binary, or any other argv command
+your machine can run. Herdr owns the host surface: installation, manifest
+validation, keybindings, terminal panes, events, invocation context, and socket
+access. The plugin owns its implementation language, dependencies, files, and
+durable state.
+
+Plugins exist so Herdr can stay lean. The core stays focused on terminal
+workspaces, panes, agents, and a stable CLI/socket API. Plugins turn that
+existing extension surface into reusable workflows that people can build,
+install, and share without adding every workflow to Herdr itself.
+
+A plugin is not an SDK integration. It is a directory with a
+`herdr-plugin.toml` manifest and commands Herdr can launch. Herdr validates the
+manifest, injects runtime context, starts the declared commands, and records
+logs. The commands call back into Herdr through the CLI or socket when they need
+to do more work.
+
+There is no separate plugin SDK or restricted command set. The entire Herdr CLI
+is the plugin API: every command in the [CLI reference](/docs/cli-reference/) is
+available to a plugin, and anything you can run as `herdr ...` yourself a plugin
+can run too. Most plugins should call Herdr through `HERDR_BIN_PATH`, which
+points at the running Herdr binary. That keeps plugins portable across Unix
+sockets and Windows named pipes. Use the [socket API](/docs/socket-api/) when
+you want to send raw JSON requests yourself.
+
+Runtime action registration and native non-terminal plugin UI are not part of
+plugin v1. Actions, event hooks, panes, and link handlers are all declared in
+the manifest.
+
+## Manifest
+
+The manifest is the contract between Herdr and the plugin. It declares package
+metadata, supported platforms, optional build commands, and the entrypoints
+Herdr can run.
+
+```toml
+id = "example.layout"
+name = "Layout"
+version = "0.1.0"
+min_herdr_version = "0.7.0"
+description = "Apply project layouts"
+platforms = ["linux", "macos", "windows"]
+
+[[build]]
+command = ["npm", "ci"]
+
+[[build]]
+command = ["npm", "run", "build"]
+platforms = ["linux", "macos"]
+
+[[actions]]
+id = "apply"
+title = "Apply layout"
+contexts = ["workspace"]
+command = ["node", "dist/apply.js"]
+
+[[events]]
+on = "worktree.created"
+command = ["herdr", "workspace", "list"]
+
+[[panes]]
+id = "board"
+title = "Project board"
+placement = "overlay"
+command = ["herdr-board"]
+
+[[link_handlers]]
+id = "github-issue"
+title = "Open GitHub issue"
+pattern = "^https://github\\.com/[^/]+/[^/]+/(issues|pull)/[0-9]+$"
+action = "apply"
+```
+
+Top-level `id`, `name`, `version`, and `min_herdr_version` are required.
+Set `min_herdr_version` to the oldest Herdr version that supports the plugin
+APIs, event names, and manifest fields your plugin uses. Herdr refuses to link
+or install a plugin when its minimum version is newer than the current binary.
+`description` is optional. Plugin ids may use ASCII letters, digits, dot,
+colon, underscore, and hyphen.
+
+Action ids, pane ids, and link handler ids are local ids inside the plugin.
+They may use ASCII letters, digits, colon, underscore, and hyphen, but not
+dots. Each id type must be unique inside a plugin. Herdr qualifies action ids
+as `plugin.id.action` when it needs a globally unique name.
+
+Use `platforms = ["linux", "macos", "windows"]` to declare where the plugin
+can run. Build commands, actions, event hooks, panes, and link handlers can
+also declare their own `platforms`; item-level platforms override the top-level
+list. Local plugins without top-level `platforms` link with a warning.
+
+`command` values are argv arrays. Herdr does not run them through a shell, so
+there is no shell expansion unless your command starts a shell itself. Put
+language-specific behavior in your script or binary.
+
+## First plugin
+
+Start with a directory that contains `herdr-plugin.toml` and one executable
+script or program:
+
+```text
+my-plugin/
+ herdr-plugin.toml
+ index.js
+```
+
+```toml
+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"]
+```
+
+Inside the command, call back into Herdr with `HERDR_BIN_PATH`:
+
+```js
+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);
+```
+
+This example uses Node, but nothing about plugins requires Node. The manifest
+could launch Bash, PowerShell, Python, Rust, Go, Lua, Bun, or any other command
+available on the user's machine.
+
+## Install and link
+
+Install an example plugin:
+
+```bash
+herdr plugin install ogulcancelik/herdr-plugin-examples/agent-telegram-notify
+herdr plugin config-dir examples.agent-telegram-notify
+herdr plugin list
+herdr plugin action list --plugin examples.agent-telegram-notify
+```
+
+When you are authoring a local plugin, link the working directory instead:
+
+```bash
+herdr plugin link /path/to/plugin
+herdr plugin config-dir example.layout
+herdr plugin action list --plugin example.layout
+herdr plugin action invoke example.layout.apply
+herdr plugin pane open --plugin example.layout --entrypoint board
+herdr plugin log list --plugin example.layout
+```
+
+`plugin install` accepts GitHub shorthand only, such as
+`owner/repo/subdir`. It clones with `git`, shows a preview in interactive
+terminals, runs supported build commands, then stores the checkout under
+Herdr-managed plugin data and registers it. Use `--yes` for noninteractive
+installs. Reinstalling a GitHub-managed plugin replaces that managed checkout.
+Installing over a locally linked plugin is refused; unlink or uninstall the
+local plugin first. `plugin install` and `plugin link` create the plugin's
+config and state directories, and `plugin config-dir <id>` prints the config
+directory for setup docs and shell scripts.
+
+`plugin uninstall <id-or-source>` unregisters the plugin. For GitHub-managed
+installs it also removes the managed checkout, and it accepts either the plugin
+id or the same `owner/repo[/subdir...]` shorthand used by install.
+`plugin unlink <id>` only unregisters a plugin and leaves files alone, which is
+useful for local development. There is no separate `plugin update` in v1;
+reinstall from GitHub to refresh a managed plugin.
+
+The example cookbook repo is `ogulcancelik/herdr-plugin-examples`. It contains
+separate example plugins in subdirectories, including `agent-telegram-notify`,
+`github-link-preview`, and `dev-layout-bootstrap`. These are examples to copy,
+not maintained official plugins.
+
+## Build commands
+
+Build commands run during GitHub `plugin install` after confirmation and before
+Herdr registers the plugin. If a build command fails, install aborts and the
+plugin is not registered. `plugin link` does not run build commands; local
+authors build their working tree themselves. Build commands may generate files,
+but changing `herdr-plugin.toml` after the install preview aborts install. Build
+failures show the plugin id, build index, working directory, command, exit
+status or spawn error, and capped stdout/stderr without interpreting tool output.
+
+Build commands are plain argv commands too, but they do not receive runtime
+plugin context or Herdr socket env. Plugin authors should document required
+system tools such as `cargo`, `npm`, `bun`, or `lua`; Herdr reports build
+failures but does not install missing toolchains.
+
+## Commands and environment
+
+Runtime commands run with the plugin directory as their working directory. Herdr
+injects `HERDR_SOCKET_PATH`, `HERDR_BIN_PATH`, `HERDR_ENV=1`,
+`HERDR_PLUGIN_ID`, `HERDR_PLUGIN_ROOT`, `HERDR_PLUGIN_CONFIG_DIR`,
+`HERDR_PLUGIN_STATE_DIR`, `HERDR_PLUGIN_CONTEXT_JSON`, and any available
+`HERDR_WORKSPACE_ID`, `HERDR_TAB_ID`, and `HERDR_PANE_ID`. Action commands also
+receive `HERDR_PLUGIN_ACTION_ID`; event hooks receive `HERDR_PLUGIN_EVENT` and
+`HERDR_PLUGIN_EVENT_JSON`; pane commands receive `HERDR_PLUGIN_ENTRYPOINT_ID`.
+
+`HERDR_PLUGIN_ROOT` is the installed or linked plugin directory. Do not store
+user credentials or durable state there, because GitHub-installed plugin roots
+are managed source checkouts. Put user-editable config such as `.env` files
+under `HERDR_PLUGIN_CONFIG_DIR`, and put local runtime state under
+`HERDR_PLUGIN_STATE_DIR`. Herdr creates those directories and seeds
+`HERDR_PLUGIN_CONFIG_DIR` from the legacy plugin config locations when present,
+but it does not validate, sync, or delete their contents. The plugin owns the
+file format and lifecycle.
+
+`HERDR_PLUGIN_CONTEXT_JSON` can include workspace, tab, focused pane, worktree,
+agent, selected text, clicked URL, and link handler fields when they are
+available for that invocation. Shell plugins can read the individual env vars
+for common ids, or parse the context JSON for the full shape.
+
+Use `HERDR_BIN_PATH` when a plugin needs to call Herdr portably from Node,
+PowerShell, Bash, or another runtime. The raw socket transport behind
+`HERDR_SOCKET_PATH` is OS-specific: Unix clients connect to a Unix socket path,
+while Windows clients connect to a named pipe. CLI calls through
+`HERDR_BIN_PATH` avoid that transport difference. See the
+[CLI reference](/docs/cli-reference/) for available commands and
+[socket API](/docs/socket-api/) for raw request shapes.
+
+## Panes
+
+Manifest pane `placement` defaults to `overlay`, which opens a temporary zoomed
+overlay over the active pane and restores the previous focus and zoom when it
+closes. A `plugin.pane.open` request can override the manifest placement with
+`overlay`, `split`, `tab`, or `zoomed`.
+
+Plugin panes are normal Herdr panes after they open. Plugins can call standard
+pane APIs such as `pane.move`, `pane.swap`, `pane.resize`, and `pane.zoom`
+through the socket or CLI; Herdr keeps plugin pane ownership attached to the
+underlying pane when it moves across tabs or workspaces.
+
+On Windows, build commands, action commands, and event commands resolve common
+`PATHEXT` shims such as `npm.cmd`, `bun.cmd`, and `pnpm.cmd` when the bare
+command is on `PATH`. Pane commands use Herdr's normal Windows pane launcher and
+must still be valid Windows argv commands.
+
+## Keybindings
+
+Bind a key to an installed plugin action:
+
+```toml
+[[keys.command]]
+key = "prefix+l"
+type = "plugin_action"
+command = "example.layout.apply"
+description = "apply layout"
+```
+
+## Link handlers
+
+Use `[[link_handlers]]` to route modified clicks on matching terminal URLs to a
+plugin action instead of opening the URL in the browser. The modified-click
+modifier is Control on every platform, including macOS, because captured
+terminal mouse reports do not expose Command/Super separately from a plain
+click. `pattern` is a Rust regular expression matched against the clicked URL,
+and `action` must
+name an action declared by the same plugin. Link handler actions receive
+`invocation_source = "link_click"`, `clicked_url`, and `link_handler_id` in
+`HERDR_PLUGIN_CONTEXT_JSON`; shell plugins can also read
+`HERDR_PLUGIN_CLICKED_URL` and `HERDR_PLUGIN_LINK_HANDLER_ID`. Handlers are
+checked in manifest order inside each plugin.
+
+## Storage
+
+There is no Herdr-managed plugin storage API in v1. Plugins that need durable
+state should own their files or database.
+
+## Marketplace
+
+A plugin marketplace is coming. Plugins are already shareable today: publish a
+GitHub repository with `herdr-plugin.toml`, then share
+`herdr plugin install owner/repo[/subdir]`.
+
+If you want the plugin to appear in the website marketplace when discovery
+launches, add the GitHub topic `herdr-plugin` to the repository now. See
+[Marketplace](/docs/marketplace/) for how publishing and discovery will work.