docs: finalize 0.7.0 release docs

This commit is contained in:
Ogulcan Celik 2026-06-15 19:02:40 +03:00
parent 99bf8dadeb
commit befe629312
21 changed files with 946 additions and 98 deletions

View File

@ -2,6 +2,31 @@
## Unreleased
### Added
- Added local plugin v1 support with `plugin.link/list/unlink/enable/disable`, manifest-declared actions, event hooks, managed plugin panes, link handlers, command logs, keybinding integration, and authoring docs under Preview docs.
- Added `herdr plugin install <owner>/<repo>[/subdir...]`, `plugin uninstall`, source metadata in `plugin.list`, offline registry fallback, and a human-readable default `plugin list` with `--json` for scripts.
- Added `herdr plugin config-dir <id>` and automatic plugin config/state directory creation so plugin setup docs can point users at a stable config path.
- Added Devin CLI automatic detection plus `herdr integration install devin` hooks that report session ids for restore with `devin --resume <id>`. Devin state remains screen-detected because Devin hooks do not cover every permission cancellation and user interrupt transition. (#606, #622, thanks @minatoaquaMK2)
- Added supporting plugin host APIs for `pane.current`, `pane.process_info`, `client.window_title.set/clear`, `layout.export/apply`, plugin pane placement, plugin invocation context/env injection, and plugin pane ownership across `pane.move`.
- Added `pane.move` and `herdr pane move` to relocate a running pane into another tab, a new tab, or a new workspace without restarting its terminal process. (#299)
- Tabs containing a zoomed pane are now marked in the tab bar so the zoom state is visible from other tabs.
### Changed
- Bumped the client/server protocol version to 14 for `pane.move` compatibility. (#299)
- Public workspace, tab, and pane ids are now short stable handles such as `w1`, `w1:t1`, and `w1:p1`; closed tab and pane ids no longer retarget later resources. (#569)
### Fixed
- Config startup and reload now warn about unknown top-level table sections, including a `[toast]` hint that points to `[ui.toast]`, instead of silently ignoring them.
- Claude Code session restore now accepts real `/clear`, `/resume`, and compacted session identity changes while still ignoring nested `claude -p` startup sessions that inherit the pane environment. (#620)
- Auto-named tab labels now stay compact after closing, moving, or creating tabs while public tab ids remain stable.
- F1-F4 key presses sent as `ESC[11~` through `ESC[14~` now reach pane apps instead of being dropped. (#574)
- Numeric keypad keys sent through the kitty keyboard protocol now enter their digits and operators instead of being dropped. (#570)
- Pane resize keybindings now shrink panes again instead of only being able to grow them. (#562)
- Windows pane cursor rendering is now stable instead of showing a misplaced or flickering cursor. (#556)
- Tab identity is now preserved across restored sessions.
- Idle panes now poll their PTY less frequently, reducing CPU use while sessions are inactive.
- Captured pane URL clicks, including plugin link handlers, now use Ctrl-click on macOS too because captured terminal mouse reports do not expose Cmd-click separately from plain click. (#307)
## [0.6.10] - 2026-06-11
This is a hotfix release for v0.6.9. See the v0.6.9 notes for the full feature release.
@ -652,7 +677,7 @@ This is a hotfix for v0.6.3. See the v0.6.3 notes for the full feature release.
### Added
- Added a local Unix socket API for controlling running herdr sessions, including workspace and pane management, pane reads, text/key input, pane splitting, and output waits.
- Added event subscriptions over the socket API for workspace and pane lifecycle events, pane output matches, and agent state changes.
- Added CLI wrappers on top of the socket API with `herdr workspace ...`, `herdr pane ...`, and `herdr wait ...`, using compact public ids like `1` and `1-2` for scripting and agent orchestration.
- Added CLI wrappers on top of the socket API with `herdr workspace ...`, `herdr pane ...`, and `herdr wait ...`, using compact public ids for scripting and agent orchestration.
- Added a settings popup with mouse support for changing themes, sound alerts, and toast notifications from inside herdr.
- Added 9 built-in themes: catppuccin, tokyo night, dracula, nord, gruvbox, one dark, solarized, kanagawa, and rosé pine.
- Added interactive pane scrollbars, manual sidebar resizing, and upstream git ahead/behind indicators in the workspace sidebar.

View File

@ -153,7 +153,7 @@ states:
- 🔵 **done** — work finished, you have not looked at it yet
- 🟢 **idle** — done and seen
detection works by reading foreground process and terminal output. zero config, no hooks required. official claude code, codex, github copilot cli, droid, kimi code cli, qodercli, and cursor agent cli integrations provide session restore identity; pi, omp, opencode, kilo code cli, hermes, and custom socket integrations can report their own state.
detection works by reading foreground process and terminal output. zero config, no hooks required. official claude code, codex, github copilot cli, devin, droid, kimi code cli, qodercli, and cursor agent cli integrations provide session restore identity; pi, omp, kimi code cli, opencode, kilo code cli, hermes, and custom socket integrations can report their own state.
## lives in your terminal
@ -187,6 +187,7 @@ automatic detection works out of the box. process name matching plus terminal ou
| [grok cli](https://x.ai/grok) | ✓ | ✓ | ✓ |
| [hermes agent](https://github.com/NousResearch/hermes-agent) | ✓ | ✓ | ✓ |
| [kilo code cli](https://kilo.ai/) | ✓ | ✓ | ✓ |
| [devin cli](https://docs.devin.ai/cli) | ✓ | ✓ | ✓ |
| cursor agent | ✓ | ✓ | ✓ |
| antigravity cli | ✓ | ✓ | ✓ |
| kimi code cli | ✓ | ✓ | ✓ |
@ -200,7 +201,7 @@ for agents outside the built-in list, herdr still works as a terminal multiplexe
### direct integrations
official integrations have two roles. claude code, codex, github copilot cli, droid, kimi code cli, qodercli, and cursor agent cli report session identity for native restore, while their state still comes from screen detection. pi, opencode, kilo code cli, and hermes report both semantic state and session identity. omp reports semantic state without native session restore. install with:
official integrations have two roles. claude code, codex, github copilot cli, devin, droid, qodercli, and cursor agent cli report session identity for native restore, while their state still comes from screen detection. pi, kimi code cli, opencode, kilo code cli, and hermes report both semantic state and session identity. omp reports semantic state without native session restore. install with:
```bash
herdr integration install pi
@ -208,6 +209,7 @@ herdr integration install omp
herdr integration install claude
herdr integration install codex
herdr integration install copilot
herdr integration install devin
herdr integration install droid
herdr integration install kimi
herdr integration install opencode

View File

@ -3,33 +3,16 @@
## Unreleased
### Added
- Added local plugin v1 support with `plugin.link/list/unlink/enable/disable`,
manifest-declared actions, event hooks, managed plugin panes, link handlers,
command logs, keybinding integration, and authoring docs under Preview docs.
- Added `herdr plugin install <owner>/<repo>[/subdir...]`, `plugin uninstall`,
source metadata in `plugin.list`, offline registry fallback, and a
human-readable default `plugin list` with `--json` for scripts.
- Added `herdr plugin config-dir <id>` and automatic plugin config/state
directory creation so plugin setup docs can point users at a stable config
path.
- Added Devin CLI automatic detection plus `herdr integration install devin`
hooks that report session ids for restore with `devin --resume <id>`.
Devin state remains screen-detected because Devin hooks do not cover every
permission cancellation and user interrupt transition.
- Added supporting plugin host APIs for `pane.current`, `pane.process_info`,
`client.window_title.set/clear`, `layout.export/apply`, plugin pane placement,
plugin invocation context/env injection, and plugin pane ownership across
`pane.move`.
- Added local plugin v1 support with `plugin.link/list/unlink/enable/disable`, manifest-declared actions, event hooks, managed plugin panes, link handlers, command logs, keybinding integration, and authoring docs under Preview docs.
- Added `herdr plugin install <owner>/<repo>[/subdir...]`, `plugin uninstall`, source metadata in `plugin.list`, offline registry fallback, and a human-readable default `plugin list` with `--json` for scripts.
- Added `herdr plugin config-dir <id>` and automatic plugin config/state directory creation so plugin setup docs can point users at a stable config path.
- Added Devin CLI automatic detection plus `herdr integration install devin` hooks that report session ids for restore with `devin --resume <id>`. Devin state remains screen-detected because Devin hooks do not cover every permission cancellation and user interrupt transition. (#606, #622, thanks @minatoaquaMK2)
- Added supporting plugin host APIs for `pane.current`, `pane.process_info`, `client.window_title.set/clear`, `layout.export/apply`, plugin pane placement, plugin invocation context/env injection, and plugin pane ownership across `pane.move`.
- Added `pane.move` and `herdr pane move` to relocate a running pane into another tab, a new tab, or a new workspace without restarting its terminal process. (#299)
- Tabs containing a zoomed pane are now marked in the tab bar so the zoom state is visible from other tabs.
### Changed
- Bumped the client/server protocol version to 14 for `pane.move` compatibility. (#299)
- Preview releases are now published only by manual maintainer workflow dispatch, not on a scheduled cron.
- Plugin runtime config directories now use stable, readable plugin-id paths
instead of checkout hashes; existing legacy config directories are copied into
the new location when first seen.
- Plugin manifests must now declare `min_herdr_version`; install and link fail
when a plugin requires a newer Herdr binary.
- Public workspace, tab, and pane ids are now short stable handles such as `w1`, `w1:t1`, and `w1:p1`; closed tab and pane ids no longer retarget later resources. (#569)
### Fixed
@ -39,6 +22,11 @@
- Auto-named tab labels now stay compact after closing, moving, or creating tabs while public tab ids remain stable.
- F1-F4 key presses sent as `ESC[11~` through `ESC[14~` now reach pane apps instead of being dropped. (#574)
- Numeric keypad keys sent through the kitty keyboard protocol now enter their digits and operators instead of being dropped. (#570)
- Pane resize keybindings now shrink panes again instead of only being able to grow them. (#562)
- Windows pane cursor rendering is now stable instead of showing a misplaced or flickering cursor. (#556)
- Tab identity is now preserved across restored sessions.
- Idle panes now poll their PTY less frequently, reducing CPU use while sessions are inactive.
- Captured pane URL clicks, including plugin link handlers, now use Ctrl-click on macOS too because captured terminal mouse reports do not expose Cmd-click separately from plain click. (#307)
## [0.6.10] - 2026-06-11
@ -58,7 +46,7 @@ This is a hotfix release for v0.6.9. See the v0.6.9 notes for the full feature r
- Numeric keypad keys that send VT100 application-keypad escape sequences now enter their digits and operators instead of being dropped. (#493)
- Codex panes now stay marked working when the live status header uses reasoning-summary text such as `Investigating code output` instead of the literal `Working` label. (#501)
- Codex blocker detection now ignores stale prompt text outside the live prompt region, reducing false blocked states from old scrollback.
- Pane URL clicks, including plugin link handlers and native URL opening, now use Ctrl-click on macOS too because captured terminal mouse reports do not expose Cmd-click separately from plain click. (#307)
- Native pane URL clicks now use Cmd-click on macOS and Ctrl-click on other platforms. (#307)
- Worktree open, create, and remove actions now work from bare repositories instead of assuming a normal checkout. (#497)
- Pane mouse handling no longer sends empty PTY writes for mouse events that produce no terminal input. (#496)
- Pane output now renders flag emoji and other multi-codepoint grapheme clusters as complete symbols instead of blank cells. (#243)

View File

@ -302,6 +302,14 @@ herdr plugin unlink <plugin_id>
`plugin link` accepts a plugin directory containing `herdr-plugin.toml` or a direct manifest path. It is still the right command while authoring or testing a plugin from a local checkout. `plugin unlink` unregisters the plugin and leaves files alone. `plugin uninstall` unregisters a plugin and also removes Herdr-managed GitHub checkout files. For GitHub installs, uninstall accepts either the plugin id or the same `owner/repo[/subdir...]` shorthand used by install. Actions, event hooks, panes, and link handlers are declared in the manifest; runtime action registration is not part of v1.
Config directory:
```bash
herdr plugin config-dir <plugin_id>
```
`plugin config-dir` prints the plugin's config directory, creating it (and seeding it from legacy plugin config locations when present) if needed. Use it in setup docs and shell scripts to point users at a stable path for `.env` files and other user-editable config, separate from the managed plugin checkout.
Actions:
```bash

View File

@ -21,12 +21,13 @@ 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.
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 [CLI reference](/docs/cli-reference/) as the
catalog of commands a plugin can call. Use the
[socket API](/docs/socket-api/) when you want to send raw JSON requests
yourself.
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
@ -42,7 +43,7 @@ Herdr can run.
id = "example.layout"
name = "Layout"
version = "0.1.0"
min_herdr_version = "0.6.10"
min_herdr_version = "0.7.0"
description = "Apply project layouts"
platforms = ["linux", "macos", "windows"]
@ -112,7 +113,7 @@ my-plugin/
id = "example.workspace-tools"
name = "Workspace Tools"
version = "0.1.0"
min_herdr_version = "0.6.10"
min_herdr_version = "0.7.0"
description = "Small workspace helpers"
platforms = ["linux", "macos", "windows"]

View File

@ -329,7 +329,7 @@ manifest path. The manifest shape is:
id = "example.worktree-bootstrap"
name = "Worktree Bootstrap"
version = "0.1.0"
min_herdr_version = "0.6.10"
min_herdr_version = "0.7.0"
description = "Prepare new worktrees"
platforms = ["linux", "macos", "windows"]

View File

@ -0,0 +1,86 @@
id = "devin"
version = "2026.06.15.1"
min_engine_version = 1
updated_at = "2026-06-15T00:00:00Z"
aliases = ["devin-cli", "devin cli"]
[[rules]]
id = "workspace_trust_prompt"
state = "blocked"
priority = 300
region = "bottom_non_empty_lines(8)"
visible_blocker = true
contains = [
"do you trust the authors of this directory?",
"with untrusted content.",
"yes, trust ",
]
[[rules]]
id = "permission_prompt"
state = "blocked"
priority = 290
region = "bottom_non_empty_lines(8)"
visible_blocker = true
contains = ["approve once", "select", "confirm", "esc cancel"]
[[rules]]
id = "running_tools_footer"
state = "working"
priority = 200
region = "bottom_non_empty_lines(8)"
visible_working = true
contains = ["running tools", "esc to interrupt"]
not = [
{ contains = ["approve once", "esc cancel"] },
]
[[rules]]
id = "guide_while_working"
state = "working"
priority = 190
region = "bottom_non_empty_lines(6)"
visible_working = true
contains = ["guide devin while it works"]
not = [
{ contains = ["approve once", "esc cancel"] },
]
[[rules]]
id = "tool_reading_timeout"
state = "working"
priority = 180
region = "bottom_non_empty_lines(8)"
visible_working = true
contains = ["reading shell ", "timeout:"]
not = [
{ contains = ["approve once", "esc cancel"] },
]
[[rules]]
id = "welcome_prompt_footer"
state = "idle"
priority = 120
region = "bottom_non_empty_lines(8)"
visible_idle = true
contains = ["ask devin to build", "features, fix bugs", "your code"]
line_regex = ['^\s*❭ Ask Devin to build']
not = [
{ contains = ["approve once", "esc cancel"] },
{ contains = ["running tools", "esc to interrupt"] },
{ contains = ["guide devin while it works"] },
]
[[rules]]
id = "live_prompt_footer"
state = "idle"
priority = 100
region = "bottom_non_empty_lines(6)"
visible_idle = true
contains = ["context:"]
line_regex = ['^\s*❭']
not = [
{ contains = ["approve once", "esc cancel"] },
{ contains = ["running tools", "esc to interrupt"] },
{ contains = ["guide devin while it works"] },
]

View File

@ -24,6 +24,10 @@ path = "codex.toml"
id = "cursor"
path = "cursor.toml"
[[agents]]
id = "devin"
path = "devin.toml"
[[agents]]
id = "droid"
path = "droid.toml"

View File

@ -119,6 +119,13 @@ export default defineConfig({
{ label: 'Configuration', slug: 'docs/configuration' },
],
},
{
label: 'Plugins',
items: [
{ label: 'Plugins', slug: 'docs/plugins' },
{ label: 'Marketplace', slug: 'docs/marketplace' },
],
},
{
label: 'Reference',
items: [

View File

@ -14,6 +14,7 @@ Automatic detection works out of the box for common coding agents. The important
| Pi | lifecycle hooks when installed; otherwise screen manifest | state and session |
| OMP | lifecycle hooks when installed | state |
| GitHub Copilot CLI | screen manifest | session |
| Devin CLI | screen manifest | session |
| Kimi Code CLI | lifecycle hooks when installed; otherwise screen manifest | state and session |
| Hermes Agent | lifecycle hooks when installed; otherwise screen manifest | state and session |
| Qoder CLI | screen manifest | session |
@ -99,7 +100,7 @@ Each supported agent has its own integration name and behavior. See [Integration
You can rename an agent target for display:
```bash
herdr agent rename 1-1 reviewer
herdr agent rename w1:p1 reviewer
herdr agent rename reviewer --clear
```
@ -110,7 +111,7 @@ Targets accept terminal IDs, unique agent names, detected or reported agent labe
Integrations can report a visual status label without changing semantic state.
```bash
herdr pane report-agent 1-1 \
herdr pane report-agent w1:p1 \
--source custom:indexer \
--agent docs-bot \
--state working \
@ -132,7 +133,7 @@ herdr agent start reviewer --cwd ~/project --split right -- pi
You can place that agent in a specific workspace or tab:
```bash
herdr agent start docs --workspace 1 --tab 1-1 -- claude
herdr agent start docs --workspace w1 --tab w1:t1 -- claude
```
Use `herdr pane ...` commands for ordinary terminals, servers, tests, shells, and low-level terminal input. For example, use `pane split` and `pane run` for `cargo test`, not `agent start`, unless that terminal is intentionally being treated as an agent target.

View File

@ -69,7 +69,7 @@ Use `default` as the session name when you need to stop the default session expl
```bash
herdr workspace list
herdr workspace create [--cwd PATH] [--label TEXT] [--focus] [--no-focus]
herdr workspace create [--cwd PATH] [--label TEXT] [--env KEY=VALUE] [--focus] [--no-focus]
herdr workspace get <workspace_id>
herdr workspace focus <workspace_id>
herdr workspace rename <workspace_id> <label>
@ -99,7 +99,7 @@ Worktrees are normal Herdr workspaces with Git checkout provenance. `worktree cr
```bash
herdr tab list [--workspace <workspace_id>]
herdr tab create [--workspace <workspace_id>] [--cwd PATH] [--label TEXT] [--focus] [--no-focus]
herdr tab create [--workspace <workspace_id>] [--cwd PATH] [--label TEXT] [--env KEY=VALUE] [--focus] [--no-focus]
herdr tab get <tab_id>
herdr tab focus <tab_id>
herdr tab rename <tab_id> <label>
@ -110,17 +110,22 @@ herdr tab close <tab_id>
```bash
herdr pane list [--workspace <workspace_id>]
herdr pane current [--pane ID|--current]
herdr pane get <pane_id>
herdr pane layout [--pane ID|--current]
herdr pane process-info [--pane ID|--current]
herdr pane neighbor --direction left|right|up|down [--pane ID|--current]
herdr pane edges [--pane ID|--current]
herdr pane focus --direction left|right|up|down [--pane ID|--current]
herdr pane resize --direction left|right|up|down [--amount FLOAT] [--pane ID|--current]
herdr pane zoom [<pane_id>|--pane ID|--current] [--toggle|--on|--off]
herdr pane rename <pane_id> <label>|--clear
herdr pane split [<pane_id>|--pane ID|--current] --direction right|down [--ratio FLOAT] [--cwd PATH] [--focus] [--no-focus]
herdr pane split [<pane_id>|--pane ID|--current] --direction right|down [--ratio FLOAT] [--cwd PATH] [--env KEY=VALUE] [--focus] [--no-focus]
herdr pane swap --direction left|right|up|down [--pane ID|--current]
herdr pane swap --source-pane ID --target-pane ID
herdr pane move <pane_id> --tab <tab_id> --split right|down [--target-pane ID] [--ratio FLOAT] [--focus|--no-focus]
herdr pane move <pane_id> --new-tab [--workspace ID] [--label TEXT] [--focus|--no-focus]
herdr pane move <pane_id> --new-workspace [--label TEXT] [--tab-label TEXT] [--focus|--no-focus]
herdr pane close <pane_id>
```
@ -178,6 +183,10 @@ herdr pane report-metadata <pane_id> \
`STATUS` is one of `idle`, `working`, `blocked`, `done`, or `unknown`. `--agent` is a guard for the authoritative agent label. `--applies-to-source` is a guard for the active lifecycle authority source. Use `--display-agent` to change the visible name.
Metadata text is normalized before storage. Herdr trims surrounding whitespace, removes control characters, caps `--custom-status` at 32 characters, and caps `--title`, `--display-agent`, and each `--state-label` value at 80 characters. Empty normalized values are ignored.
`--source` and `--applies-to-source` must be 80 characters or fewer and may contain only ASCII letters, digits, colon, dot, underscore, and hyphen. `--ttl-ms` makes metadata expire automatically and must be between `1` and `86400000` milliseconds. Omit it for metadata that should stay until replaced, cleared, or the pane closes. `--seq` lets Herdr ignore stale reports from the same `--source`; stale reports are accepted by the API but ignored by pane state.
## Agents
```bash
@ -189,7 +198,7 @@ herdr agent rename <target> <name>|--clear
herdr agent focus <target>
herdr agent wait <target> --status <idle|working|blocked|unknown> [--timeout MS]
herdr agent attach <target> [--takeover]
herdr agent start <name> [--cwd PATH] [--workspace ID] [--tab ID] [--split right|down] [--focus|--no-focus] -- <argv...>
herdr agent start <name> [--cwd PATH] [--workspace ID] [--tab ID] [--split right|down] [--env KEY=VALUE] [--focus|--no-focus] -- <argv...>
herdr agent explain <target> [--json|--verbose]
herdr agent explain --file PATH --agent LABEL [--json|--verbose]
```
@ -206,9 +215,12 @@ Use `pane send-text`, `pane send-keys`, `pane run`, and `terminal attach` for or
```bash
herdr terminal attach <terminal_id> [--takeover]
herdr terminal title set <title>
herdr terminal title clear
```
Detach from direct attach with `ctrl+b q`. Send literal `ctrl+b` with `ctrl+b ctrl+b`.
`terminal title clear` restores Herdr's default outer terminal window title.
## Waits
@ -234,6 +246,7 @@ herdr integration install omp
herdr integration install claude
herdr integration install codex
herdr integration install copilot
herdr integration install devin
herdr integration install droid
herdr integration install kimi
herdr integration install opencode
@ -246,6 +259,7 @@ herdr integration uninstall omp
herdr integration uninstall claude
herdr integration uninstall codex
herdr integration uninstall copilot
herdr integration uninstall devin
herdr integration uninstall droid
herdr integration uninstall kimi
herdr integration uninstall opencode
@ -256,6 +270,74 @@ herdr integration uninstall cursor
herdr integration status [--outdated-only]
```
## Plugins
Plugin commands install and run local executable workflow plugins. A plugin is a manifest plus out-of-process commands; Herdr owns the host surface and plugins own their implementation language.
Install, list, and remove plugins:
```bash
herdr plugin install <owner>/<repo>[/subdir...] [--ref REF] [--yes]
herdr plugin list [--plugin ID] [--json]
herdr plugin uninstall <plugin_id|owner/repo[/subdir...]>
herdr plugin enable <plugin_id>
herdr plugin disable <plugin_id>
```
`plugin install` accepts GitHub shorthand only, such as `ogulcancelik/herdr-plugin-examples/worktree-bootstrap`. It uses `git`, shows a trust preview in interactive terminals, runs supported manifest build commands, and stores GitHub installs in a Herdr-managed directory. Use `--yes` for noninteractive installs. Reinstalling a GitHub-managed plugin replaces that managed checkout. Installing over a locally linked plugin is refused. Plugin manifests must declare `min_herdr_version`; install and link fail when the plugin requires a newer Herdr binary. `plugin list` is human-readable by default; pass `--json` for the raw API response.
Local development:
```bash
herdr plugin link <path> [--disabled]
herdr plugin unlink <plugin_id>
```
`plugin link` accepts a plugin directory containing `herdr-plugin.toml` or a direct manifest path. It is still the right command while authoring or testing a plugin from a local checkout. `plugin unlink` unregisters the plugin and leaves files alone. `plugin uninstall` unregisters a plugin and also removes Herdr-managed GitHub checkout files. For GitHub installs, uninstall accepts either the plugin id or the same `owner/repo[/subdir...]` shorthand used by install. Actions, event hooks, panes, and link handlers are declared in the manifest; runtime action registration is not part of v1.
Config directory:
```bash
herdr plugin config-dir <plugin_id>
```
`plugin config-dir` prints the plugin's config directory, creating it (and seeding it from legacy plugin config locations when present) if needed. Use it in setup docs and shell scripts to point users at a stable path for `.env` files and other user-editable config, separate from the managed plugin checkout.
Actions:
```bash
herdr plugin action list [--plugin ID]
herdr plugin action invoke <action_id> [--plugin ID]
```
`plugin action invoke` starts the manifest command for an installed, enabled,
platform-compatible plugin action and prints the started command log record in
the JSON response. Use the qualified action id (`plugin.id.action`) when more
than one plugin uses the same action id. Local action ids cannot contain dots,
so qualified ids remain unambiguous even when plugin ids contain dots.
Logs:
```bash
herdr plugin log list [--plugin ID] [--limit N]
```
Managed terminal panes:
```bash
herdr plugin pane open --plugin ID --entrypoint ID [--placement overlay|split|tab|zoomed] [--workspace ID] [--target-pane PANE] [--direction right|down] [--cwd PATH] [--env KEY=VALUE] [--focus|--no-focus]
herdr plugin pane focus <pane_id>
herdr plugin pane close <pane_id>
```
`plugin pane open` requires the plugin to be linked, enabled, and compatible
with the current platform. It starts a manifest-declared `[[panes]]` command as
a Herdr-managed terminal pane. The manifest default is `overlay`, which opens a
temporary zoomed overlay over the active pane. It can also open as a split, a
new tab, or a zoomed pane. Native non-terminal plugin panes are a later surface.
`--env KEY=VALUE` can be repeated on process-launching commands. It applies to the newly launched process only. Herdr-managed variables such as `HERDR_SOCKET_PATH`, `HERDR_BIN_PATH`, `HERDR_ENV`, `HERDR_WORKSPACE_ID`, `HERDR_TAB_ID`, `HERDR_PANE_ID`, `HERDR_PLUGIN_ID`, `HERDR_PLUGIN_ROOT`, `HERDR_PLUGIN_CONFIG_DIR`, `HERDR_PLUGIN_STATE_DIR`, `HERDR_PLUGIN_ENTRYPOINT_ID`, and `HERDR_PLUGIN_CONTEXT_JSON` stay authoritative when they conflict with caller-provided env.
## Read sources
| Source | Meaning |
@ -272,5 +354,9 @@ herdr integration status [--outdated-only]
| `HERDR_CONFIG_PATH` | Override the config file path. |
| `HERDR_SESSION` | Select a named session for CLI commands. |
| `HERDR_SOCKET_PATH` | Low-level socket path override. |
| `HERDR_ENV` | Set to `1` inside Herdr-managed pane processes. |
| `HERDR_PANE_ID` | Public pane id for the running pane process. |
| `HERDR_TAB_ID` | Public tab id for the running pane process. |
| `HERDR_WORKSPACE_ID` | Public workspace id for the running pane process. |
| `HERDR_LOG` | Set log filter, for example `HERDR_LOG=herdr=debug`. |
| `HERDR_DISABLE_SOUND` | Disable sound playback even when sound notifications are enabled. |

View File

@ -42,7 +42,7 @@ Linux and macOS direct installs use the stable update channel by default. Window
channel = "stable"
```
Set `channel = "preview"` to make `herdr update` install preview builds from the current development branch. Homebrew, mise, and Nix installs ignore the preview channel and update through their package managers.
Set `channel = "preview"` to make `herdr update` install manually published preview builds from the current development branch. Homebrew, mise, and Nix installs ignore the preview channel and update through their package managers.
## Reload config
@ -224,6 +224,17 @@ description = "run lazygit"
`type = "shell"` runs detached in the background.
`type = "plugin_action"` invokes an installed plugin action id. Use the
qualified id when action ids are not globally unique:
```toml
[[keys.command]]
key = "prefix+l"
type = "plugin_action"
command = "example.layout.apply"
description = "apply layout"
```
An optional `description` can be provided. When specified, this description is displayed in the keybind help panel (opened with `prefix+?`) in place of the default `'custom command'` label.
Custom commands receive `HERDR_SOCKET_PATH`, `HERDR_BIN_PATH`, `HERDR_ACTIVE_WORKSPACE_ID`, `HERDR_ACTIVE_TAB_ID`, `HERDR_ACTIVE_PANE_ID`, and `HERDR_ACTIVE_PANE_CWD` when those values are available. Shell commands run from the focused pane's working directory when Herdr can detect it.
@ -288,7 +299,7 @@ accent = "cyan"
`confirm_close` controls whether closing a workspace asks for confirmation. `prompt_new_tab_name` controls whether new tabs ask for a label first.
Set `mouse_capture = false` if you want your terminal to handle normal clicks, such as command-clicking URLs. With mouse capture enabled, Ctrl-click opens pane links when your terminal sends that modified click to Herdr; use Shift-Ctrl-click on Linux or Shift-Cmd-click on macOS for the terminal-native bypass path.
Set `mouse_capture = false` if you want your terminal to handle normal clicks, such as command-clicking URLs. With mouse capture enabled, Ctrl-click opens pane links when your terminal sends that modified click to Herdr. This includes macOS; Cmd-click is not reported separately from plain click while Herdr captures mouse input. Use Shift-Ctrl-click on Linux or Shift-Cmd-click on macOS for the terminal-native bypass path.
Set `right_click_passthrough_modifier = "ctrl"` if you want Ctrl-right-click, hold, and drag gestures inside mouse-reporting pane apps to reach the app instead of opening Herdr's pane menu. The default is empty, which disables this passthrough. Supported modifiers are `ctrl`, `alt`, `cmd`, `super`, `meta`, and `hyper`; `shift` is rejected because many terminals reserve Shift+mouse for their own mouse bypass.
@ -353,7 +364,7 @@ request_path = "sounds/request.mp3"
`path` sets one sound for all sound notifications. `done_path` and `request_path` override only the finished and needs-input sounds.
Per-agent sound overrides accept `default`, `on`, or `off`. Droid is muted by default.
Per-agent sound overrides accept `default`, `on`, or `off`. Use detected agent labels such as `claude`, `codex`, `devin`, or `droid` as keys. Droid is muted by default.
```toml
[ui.sound.agents]
@ -430,7 +441,7 @@ For how native agent session restore differs from pane screen history and live h
## IME cursor tracking
When the focused pane hides its cursor and paints its own — common in AI-agent TUIs like Claude Code, pi, and codex — macOS native input methods stop tracking the candidate window position because the outer terminal stops reporting the cursor.
When the focused pane hides its cursor and paints its own — common in AI-agent TUIs like Claude Code, pi, codex, and Devin — macOS native input methods stop tracking the candidate window position because the outer terminal stops reporting the cursor.
Set `reveal_hidden_cursor_for_cjk_ime = true` to expose the focused pane's cursor anchor to the outer terminal regardless of the pane's `?25l` request:
@ -443,7 +454,7 @@ cjk_ime_cursor_shape = "steady_block"
When enabled, the cursor stays visible at the focused pane's reported position. If the pane reports no cursor position, the anchor falls back to the pane's top-left so a stable IME hint is always available.
`cjk_ime_agents` is an optional allow-list. When empty, the reveal applies to any focused pane. When non-empty, the reveal only applies if the focused pane's detected agent matches one of the listed names — useful to enable the reveal only for AI-agent TUIs that paint their own cursor while leaving plain shells untouched. Accepted names: `pi`, `claude`, `codex`, `gemini`, `cursor`, `agy`, `cline`, `opencode`, `copilot`, `kimi`, `kiro`, `droid`, `amp`, `grok`, `hermes`, `kilo`, `qodercli`, and `qoder`. Unknown names are ignored; if the list contains no valid names, the reveal does not apply.
`cjk_ime_agents` is an optional allow-list. When empty, the reveal applies to any focused pane. When non-empty, the reveal only applies if the focused pane's detected agent matches one of the listed names — useful to enable the reveal only for AI-agent TUIs that paint their own cursor while leaving plain shells untouched. Accepted names: `pi`, `claude`, `codex`, `gemini`, `cursor`, `devin`, `agy`, `cline`, `opencode`, `copilot`, `kimi`, `kiro`, `droid`, `amp`, `grok`, `hermes`, `kilo`, `qodercli`, and `qoder`. Unknown names are ignored; if the list contains no valid names, the reveal does not apply.
`cjk_ime_cursor_shape` controls the DECSCUSR shape rendered for the IME anchor. Accepted values: `block`, `steady_block` (default), `underline`, `steady_underline`, `bar`, `steady_bar`.

View File

@ -64,4 +64,14 @@ The guide teaches your agent Herdr's concepts, setup, configuration, and common
[Read the API guide →](/docs/socket-api/)
</Card>
<Card title="Plugins">
Author local executable workflow plugins with manifest actions and event hooks.
[Write a plugin →](/docs/plugins/)
</Card>
<Card title="Marketplace">
Share plugins from GitHub today and tag your repo to be listed when the marketplace launches.
[Publish a plugin →](/docs/marketplace/)
</Card>
</CardGrid>

View File

@ -132,7 +132,7 @@ herdr channel set stable
For direct installs, changing channels also checks that channel and installs its latest binary. If that update fails, run `herdr update` to retry from the configured channel.
Preview builds are GitHub prereleases published from the current development branch. They are useful when you want fixes before the next stable release, but they can regress. Homebrew, mise, and Nix installs do not use the preview channel.
Preview builds are manually published GitHub prereleases from the current development branch. They are useful when you want fixes before the next stable release, but they can regress. Homebrew, mise, and Nix installs do not use the preview channel.
Windows beta builds are preview-only for now. `herdr channel set stable` is rejected on Windows until stable Windows releases are available.

View File

@ -1,11 +1,11 @@
---
title: Integrations
description: Install Herdr integrations for Pi, OMP, Claude Code, Codex, GitHub Copilot CLI, Droid, Kimi Code CLI, OpenCode, Kilo Code CLI, Hermes Agent, Qoder CLI, and Cursor Agent CLI.
description: Install Herdr integrations for Pi, OMP, Claude Code, Codex, GitHub Copilot CLI, Devin CLI, Droid, Kimi Code CLI, OpenCode, Kilo Code CLI, Hermes Agent, Qoder CLI, and Cursor Agent CLI.
---
Herdr detects supported agents automatically. Official integrations can add native session identity for restore, lifecycle state reports, or both.
Use integrations when you want native agent session restore, direct lifecycle reports from Pi/OMP/Copilot/OpenCode/Kilo/Hermes-style hooks or plugins, or both. See [Agents](/docs/agents/) for the full status authority model.
Use integrations when you want native agent session restore from Claude Code/Codex/Copilot/Devin-style hooks, direct lifecycle reports from Pi/OMP/Kimi/OpenCode/Kilo/Hermes-style hooks or plugins, or both. See [Agents](/docs/agents/) for the full status authority model.
## Install integrations
@ -17,6 +17,7 @@ herdr integration install omp
herdr integration install claude
herdr integration install codex
herdr integration install copilot
herdr integration install devin
herdr integration install droid
herdr integration install kimi
herdr integration install opencode
@ -34,6 +35,7 @@ herdr integration uninstall omp
herdr integration uninstall claude
herdr integration uninstall codex
herdr integration uninstall copilot
herdr integration uninstall devin
herdr integration uninstall droid
herdr integration uninstall kimi
herdr integration uninstall opencode
@ -50,13 +52,13 @@ Herdr uses integrations in two different ways:
| Integration type | Agents | Effect |
| --- | --- | --- |
| Lifecycle authority | Pi, OMP, Kimi Code CLI, OpenCode, Kilo Code CLI, Hermes Agent | When installed and actively reporting for the pane, hook or plugin events author `idle`, `working`, and `blocked`. Herdr does not also use screen manifest fallback for that same lifecycle authority. |
| Session identity | Claude Code, Codex, GitHub Copilot CLI, Droid, Qoder CLI, Cursor Agent CLI | The integration reports native session references for restore. State still comes from Herdr's screen manifest detection. |
| Session identity | Claude Code, Codex, GitHub Copilot CLI, Devin CLI, Droid, Qoder CLI, Cursor Agent CLI | The integration reports native session references for restore. State still comes from Herdr's screen manifest detection. |
Custom socket integrations can also report state when they define state that is not visible in the native terminal UI.
Some integrations report native agent session references. Herdr uses official session references to resume Claude Code, Codex, Droid, Kimi Code CLI, Qoder CLI, Cursor Agent CLI, GitHub Copilot CLI, Pi, Hermes Agent, OpenCode, and Kilo Code CLI panes after a Herdr server restart unless `[session] resume_agents_on_restore = false` disables it.
Some integrations report native agent session references. Herdr uses official session references to resume Claude Code, Codex, Devin CLI, Droid, Kimi Code CLI, Qoder CLI, Cursor Agent CLI, GitHub Copilot CLI, Pi, Hermes Agent, OpenCode, and Kilo Code CLI panes after a Herdr server restart unless `[session] resume_agents_on_restore = false` disables it.
Native session restore requires current Herdr integrations: Pi integration version `2`, Claude Code version `5`, Codex version `5`, GitHub Copilot CLI version `2`, Droid version `2`, Kimi Code CLI version `3`, Qoder CLI version `2`, Cursor Agent CLI version `1`, OpenCode version `5`, Kilo Code CLI version `1`, or Hermes Agent version `2`. OMP integration version `2` reports agent state only. Check installed versions with `herdr integration status`.
Native session restore requires current Herdr integrations: Pi integration version `2`, Claude Code version `6`, Codex version `5`, GitHub Copilot CLI version `2`, Devin CLI version `1`, Droid version `2`, Kimi Code CLI version `3`, Qoder CLI version `2`, Cursor Agent CLI version `1`, OpenCode version `5`, Kilo Code CLI version `1`, or Hermes Agent version `2`. OMP integration version `2` reports agent state only. Check installed versions with `herdr integration status`.
## Pi
@ -130,6 +132,20 @@ Herdr uses `~/.copilot` by default, or `COPILOT_HOME` when set. The Copilot conf
After Copilot emits a session-bearing event, Herdr can use the reported session id to resume the pane with `copilot --resume=<id>`.
## Devin CLI
Install the Devin CLI hook:
```bash
herdr integration install devin
```
The hook reports native session identity from Devin session, prompt, tool-use, permission, and stop events. Devin state still comes from Herdr's screen manifest and OSC detection because Devin hooks do not emit a reliable state transition after every permission cancellation or user interrupt.
Herdr uses `~/.config/devin` by default, or `$XDG_CONFIG_HOME/devin` when `XDG_CONFIG_HOME` is set. The Devin config directory must already exist. Install writes `herdr-agent-state.sh` and updates `config.json` with Herdr hook entries. The hook refreshes the session reference while Devin runs. Uninstall removes Herdr entries from `config.json` and deletes the hook script.
Herdr resumes stored Devin sessions with `devin --resume <id>`. Native screen manifest detection remains the state authority whether or not the hook is installed.
## Kimi Code CLI
Install the Kimi Code CLI hook:
@ -231,7 +247,7 @@ Integrations can report a short visual label without changing the semantic state
For example, an agent can remain semantically `working` while showing `indexing` in the UI.
```bash
herdr pane report-agent 1-1 \
herdr pane report-agent w1:p1 \
--source custom:docs \
--agent docs-bot \
--state working \
@ -264,7 +280,7 @@ herdr agent list
Read a pane when you need to verify what Herdr can see:
```bash
herdr pane read 1-1 --source recent --lines 50
herdr pane read w1:p1 --source recent --lines 50
```
If integration state looks wrong, first confirm the agent is running inside Herdr and that the relevant hook or plugin was installed for the same user account.

View File

@ -0,0 +1,37 @@
---
title: Marketplace
description: Publish and share Herdr plugins, and get listed when the marketplace launches.
---
The Herdr plugin marketplace is a discoverable index of installable plugins. It
is not live yet. This page is how to be ready for it.
## Share a plugin today
The marketplace adds discovery on top of installation; it does not replace it.
Anyone can already install your plugin straight from GitHub:
```bash
herdr plugin install owner/repo[/subdir...]
```
Publish a normal public GitHub repository with a `herdr-plugin.toml` manifest at
its root, or in a subdirectory, and that command works now. See
[Plugins](/docs/plugins/) for the manifest and authoring reference.
## Get listed when it launches
If you want your plugin to appear in the website marketplace when discovery
launches, add the GitHub topic `herdr-plugin` to your repository now. That
topic is the signal the future index will use for discovery, so tagging a
public plugin today means it can be listed when the marketplace goes live.
## What a listing will show
A marketplace card will surface your plugin's `id`, `name`, `description`,
declared `platforms`, and a link back to the source repository. Getting that
manifest metadata right today is what makes your listing accurate later. Declare
`platforms` honestly, because the index will use it to show where a plugin runs.
Plugins stay ordinary GitHub repositories. The marketplace is a discovery and
trust layer on top of the same `herdr plugin install` path you can use now.

View File

@ -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.

View File

@ -19,7 +19,7 @@ When a session has no workspaces, Herdr opens one automatically. A workspace is
Herdr is mouse-native, so start by clicking. Click panes, tabs, workspaces, and agents to focus them. Drag split borders to resize. Right-click for context menus, including splitting panes and creating tabs. Drag-select text to copy it to your clipboard; double-click a token to copy it directly. Copying does not require Ctrl+C.
Ctrl-click opens pane links when your terminal sends the modified click to Herdr. This works for OSC 8 hyperlinks and visible `http://` or `https://` URLs. The portable terminal-native fallback is Shift-Ctrl-click on Linux or Shift-Cmd-click on macOS.
Ctrl-click opens pane links when your terminal sends the modified click to Herdr. This works for OSC 8 hyperlinks and visible `http://` or `https://` URLs. On macOS, use Ctrl-click for Herdr-handled pane links while mouse capture is enabled; Cmd-click is only available through the terminal-native bypass path, such as Shift-Cmd-click or `ui.mouse_capture = false`.
If you configure `ui.right_click_passthrough_modifier`, that modifier plus right-click sends right-click, hold, and drag gestures to mouse-reporting pane apps.

View File

@ -67,10 +67,11 @@ Native session restore requires these Herdr integration versions or newer:
| Agent | Minimum Herdr integration version | Resume command |
| --- | --- | --- |
| Pi | `2` | `pi --session <path-or-id>` |
| Claude Code | `5` | `claude --resume <id>` |
| Claude Code | `6` | `claude --resume <id>` |
| Codex | `5` | `codex resume <id>` |
| Cursor Agent CLI | `1` | `cursor-agent --resume <id>` |
| GitHub Copilot CLI | `2` | `copilot --resume=<id>` |
| Devin CLI | `1` | `devin --resume <id>` |
| Droid | `2` | `droid --resume <id>` |
| Kimi Code CLI | `3` | `kimi --session <id>` |
| Qoder CLI | `2` | `qodercli --resume <id>` |

View File

@ -47,8 +47,8 @@ herdr tab create --label logs
Split a pane and run a command:
```bash
herdr pane split 1-1 --direction right
herdr pane run 1-2 "npm test"
herdr pane split w1:p1 --direction right
herdr pane run w1:p2 "npm test"
```
Inspect and rearrange panes:
@ -59,19 +59,19 @@ herdr pane neighbor --direction right --current
herdr pane resize --direction right --amount 0.1 --current
herdr pane swap --direction right --current
herdr pane zoom --on --current
herdr pane split 1-1 --direction right --ratio 0.333
herdr pane split w1:p1 --direction right --ratio 0.333
```
Wait for an agent:
```bash
herdr wait agent-status 1-1 --status done
herdr wait agent-status w1:p1 --status done
```
Read pane output:
```bash
herdr pane read 1-2 --source recent --lines 50
herdr pane read w1:p2 --source recent --lines 50
```
## Raw methods
@ -82,39 +82,106 @@ Raw socket method names use dot notation:
| --- | --- |
| Server | `ping`, `server.stop`, `server.reload_config`, `server.agent_manifests`, `server.reload_agent_manifests` |
| Notification | `notification.show` |
| Client | `client.window_title.set`, `client.window_title.clear` |
| Workspace | `workspace.create`, `workspace.list`, `workspace.get`, `workspace.focus`, `workspace.rename`, `workspace.close` |
| Worktree | `worktree.list`, `worktree.create`, `worktree.open`, `worktree.remove` |
| Tab | `tab.create`, `tab.list`, `tab.get`, `tab.focus`, `tab.rename`, `tab.close` |
| Pane | `pane.split`, `pane.swap`, `pane.zoom`, `pane.layout`, `pane.neighbor`, `pane.edges`, `pane.focus_direction`, `pane.resize`, `pane.list`, `pane.get`, `pane.rename`, `pane.send_text`, `pane.send_keys`, `pane.send_input`, `pane.read`, `pane.report_agent`, `pane.report_agent_session`, `pane.report_metadata`, `pane.clear_agent_authority`, `pane.release_agent`, `pane.close`, `pane.wait_for_output` |
| Pane | `pane.split`, `pane.swap`, `pane.move`, `pane.zoom`, `pane.layout`, `pane.process_info`, `pane.neighbor`, `pane.edges`, `pane.focus_direction`, `pane.resize`, `pane.list`, `pane.current`, `pane.get`, `pane.rename`, `pane.send_text`, `pane.send_keys`, `pane.send_input`, `pane.read`, `pane.report_agent`, `pane.report_agent_session`, `pane.report_metadata`, `pane.clear_agent_authority`, `pane.release_agent`, `pane.close`, `pane.wait_for_output` |
| Layout | `layout.export`, `layout.apply` |
| Agent | `agent.list`, `agent.get`, `agent.read`, `agent.explain`, `agent.send`, `agent.rename`, `agent.focus`, `agent.start` |
| Events | `events.subscribe`, `events.wait` |
| Integrations | `integration.install`, `integration.uninstall` |
| Plugins | `plugin.link`, `plugin.list`, `plugin.unlink`, `plugin.enable`, `plugin.disable`, `plugin.action.list`, `plugin.action.invoke`, `plugin.log.list`, `plugin.pane.open`, `plugin.pane.focus`, `plugin.pane.close` |
Some CLI commands are conveniences around these methods. For example, `herdr agent wait` resolves an agent target and then subscribes to pane agent state events.
Pane control methods use public pane ids such as `1-1`. Omit `pane_id` to use
the server's active focused pane.
Pane control methods use public pane ids such as `w1:p1`. Methods whose
schema makes `pane_id` optional use the server's active focused pane when it is
omitted. `pane.move` always requires the source `pane_id`.
```json
{"id":"req_layout","method":"pane.layout","params":{"pane_id":"1-1"}}
{"id":"req_neighbor","method":"pane.neighbor","params":{"pane_id":"1-1","direction":"right"}}
{"id":"req_edges","method":"pane.edges","params":{"pane_id":"1-1"}}
{"id":"req_current","method":"pane.current","params":{"caller_pane_id":"w1:p1"}}
{"id":"req_layout","method":"pane.layout","params":{"pane_id":"w1:p1"}}
{"id":"req_neighbor","method":"pane.neighbor","params":{"pane_id":"w1:p1","direction":"right"}}
{"id":"req_edges","method":"pane.edges","params":{"pane_id":"w1:p1"}}
{"id":"req_focus","method":"pane.focus_direction","params":{"direction":"right"}}
{"id":"req_resize","method":"pane.resize","params":{"pane_id":"1-1","direction":"right","amount":0.1}}
{"id":"req_zoom","method":"pane.zoom","params":{"pane_id":"1-1","mode":"toggle"}}
{"id":"req_split","method":"pane.split","params":{"direction":"right","ratio":0.333}}
{"id":"req_resize","method":"pane.resize","params":{"pane_id":"w1:p1","direction":"right","amount":0.1}}
{"id":"req_zoom","method":"pane.zoom","params":{"pane_id":"w1:p1","mode":"toggle"}}
{"id":"req_split","method":"pane.split","params":{"direction":"right","ratio":0.333,"env":{"HERDR_ROLE":"tests"}}}
{"id":"req_process","method":"pane.process_info","params":{"pane_id":"w1:p1"}}
```
`pane.current` returns a single `PaneInfo`. When `caller_pane_id` is present,
Herdr returns that pane. When it is omitted, Herdr returns the active focused
pane.
`pane.layout` returns the tab layout snapshot with `workspace_id`, `tab_id`,
`zoomed`, outer `area`, `focused_pane_id`, pane rects, and split rects/ratios.
`pane.neighbor` and `pane.edges` include that same layout snapshot so clients
can make the next decision without private layout state.
`pane.process_info` returns the pane's shell pid, foreground process group id
when available, and foreground processes with pid, name, argv/cmdline, and cwd
when the platform exposes them.
`layout.export` returns a portable tab layout tree. Omit `tab_id` and `pane_id`
to export the active tab, pass `tab_id` to export that tab, or pass `pane_id` to
export the tab containing that pane.
```json
{"id":"req_export","method":"layout.export","params":{"tab_id":"w1:t1"}}
```
The response includes `workspace_id`, `tab_id`, `zoomed`, `focused_pane_id`, and
`root`. `root` is a BSP tree of `pane` and `split` nodes. Pane nodes can include
`pane_id`, `label`, `cwd`, and argv `command`. Split nodes use
`direction` (`right` or `down`), `ratio`, `first`, and `second`.
`layout.apply` creates a fresh tab from a declarative tree. If `tab_id` is
provided, Herdr creates the replacement tab first and then closes the old tab.
This restores structure, labels, cwd, env, and optional argv commands; it does
not preserve live PTYs, scrollback, or running processes.
```json
{
"id": "req_apply",
"method": "layout.apply",
"params": {
"workspace_id": "wabc",
"tab_label": "dev",
"focus": true,
"root": {
"type": "split",
"direction": "right",
"ratio": 0.65,
"first": {
"type": "pane",
"label": "editor",
"cwd": "/repo"
},
"second": {
"type": "pane",
"label": "tests",
"cwd": "/repo",
"command": ["sh", "-c", "just test"],
"env": { "HERDR_ROLE": "tests" }
}
}
}
}
```
Process-launching methods accept an `env` object. Herdr applies those key/value
pairs to the newly launched process only. Herdr also injects `HERDR_SOCKET_PATH`,
`HERDR_ENV=1`, `HERDR_WORKSPACE_ID`, `HERDR_TAB_ID`, and `HERDR_PANE_ID` into
managed pane processes. Herdr-managed variables are authoritative when they
conflict with caller-provided env.
`pane.swap` supports directional and explicit forms:
```json
{"id":"req_swap_dir","method":"pane.swap","params":{"pane_id":"1-1","direction":"right"}}
{"id":"req_swap_explicit","method":"pane.swap","params":{"source_pane_id":"1-1","target_pane_id":"1-2"}}
{"id":"req_swap_dir","method":"pane.swap","params":{"pane_id":"w1:p1","direction":"right"}}
{"id":"req_swap_explicit","method":"pane.swap","params":{"source_pane_id":"w1:p1","target_pane_id":"w1:p2"}}
```
Swap is same-tab only. It preserves split shape, split ratios, pane ids, and
@ -124,12 +191,36 @@ running processes. The response is `type: "pane_swap"` with `changed`, optional
`cross_tab`. When a tab is zoomed, swap keeps zoom active and mutates the hidden
full-tab layout.
`pane.move` moves a running pane to a different tab, a new tab, or a new
workspace:
```json
{"id":"req_move_tab","method":"pane.move","params":{"pane_id":"w1:p2","destination":{"type":"tab","tab_id":"w1:t2","target_pane_id":"w1:p3","split":"right","ratio":0.5},"focus":true}}
{"id":"req_move_new_tab","method":"pane.move","params":{"pane_id":"w1:p2","destination":{"type":"new_tab","workspace_id":"w1","label":"logs"},"focus":true}}
{"id":"req_move_new_workspace","method":"pane.move","params":{"pane_id":"w1:p2","destination":{"type":"new_workspace","label":"logs","tab_label":"main"},"focus":true}}
```
Existing-tab moves require `split: "right" | "down"`. `target_pane_id` is
optional and defaults to the target tab's focused pane. Same-tab layout changes
remain `pane.swap`; moving to the source tab returns `changed: false` with
`reason: "same_tab"`. Moves involving a zoomed source or target tab return
`changed: false` with `reason: "zoomed_tab"`.
The response is `type: "pane_move"` with `changed`, optional `reason`,
`previous_pane_id`, `previous_workspace_id`, `previous_tab_id`, the moved
`pane`, optional `source_layout`, `target_layout`, optional created workspace or
tab records, optional closed workspace or tab ids, and `focused_pane_id`.
Cross-workspace moves keep the internal pane and terminal alive but assign a new
public pane id in the destination workspace. Subscribers can listen for
`pane.moved`; Herdr does not emit fake pane close/create events for the moved
terminal process.
`pane.zoom` toggles, enables, or disables zoom for the target pane's tab:
```json
{"id":"req_zoom_toggle","method":"pane.zoom","params":{"pane_id":"1-1"}}
{"id":"req_zoom_on","method":"pane.zoom","params":{"pane_id":"1-1","mode":"on"}}
{"id":"req_zoom_off","method":"pane.zoom","params":{"pane_id":"1-1","mode":"off"}}
{"id":"req_zoom_toggle","method":"pane.zoom","params":{"pane_id":"w1:p1"}}
{"id":"req_zoom_on","method":"pane.zoom","params":{"pane_id":"w1:p1","mode":"on"}}
{"id":"req_zoom_off","method":"pane.zoom","params":{"pane_id":"w1:p1","mode":"off"}}
```
Omitting `pane_id` targets the server's active focused pane. The response is
@ -160,18 +251,29 @@ The response reports whether anything was shown:
Possible reasons are `shown`, `disabled`, `rate_limited`, `no_foreground_client`, and `busy`. `disabled` means `ui.toast.delivery = "off"`. `busy` means an existing in-app toast was not replaced. Terminal and system delivery are best-effort through the current foreground attached Herdr client.
Set or clear the foreground client's outer terminal window title:
```json
{"id":"req_title","method":"client.window_title.set","params":{"title":"herdr api"}}
{"id":"req_title_clear","method":"client.window_title.clear","params":{}}
```
`client.window_title.clear` restores Herdr's default title. The response is
`type: "client_window_title"` with `changed` and reason `set`, `cleared`, or
`no_foreground_client`.
Worktree methods manage Git checkouts as Herdr workspaces. `worktree.create` creates a checkout and returns the new `workspace`, `tab`, `root_pane`, and `worktree` records. `worktree.open` opens an existing checkout or returns the already-open workspace. `worktree.remove` runs `git worktree remove` against a linked child workspace and never deletes the branch.
Create a worktree from a source workspace:
```json
{"id":"req_1","method":"worktree.create","params":{"workspace_id":"1","branch":"worktree/api","focus":false}}
{"id":"req_1","method":"worktree.create","params":{"workspace_id":"w1","branch":"worktree/api","focus":false}}
```
Open an existing checkout:
```json
{"id":"req_2","method":"worktree.open","params":{"workspace_id":"1","branch":"worktree/api","focus":true}}
{"id":"req_2","method":"worktree.open","params":{"workspace_id":"w1","branch":"worktree/api","focus":true}}
```
Remove a linked checkout:
@ -182,9 +284,158 @@ Remove a linked checkout:
Use at most one of `workspace_id` or `cwd` for `worktree.list`, `worktree.create`, and `worktree.open`; omit both to use the active workspace. Use exactly one of `path` or `branch` for `worktree.open`. Raw socket `cwd` and `path` values must be absolute; the CLI expands relative `--cwd` and `--path` values before sending requests. Workspace responses include optional `worktree` provenance when a workspace belongs to a Herdr worktree group. Worktree commands can emit `workspace.updated` when an existing workspace gains or changes worktree provenance.
Worktree commands also emit lifecycle events. `worktree.create` emits `workspace.created`, `tab.created`, `pane.created`, and `worktree.created`. `worktree.open` emits `worktree.opened`, and it also emits workspace/tab/pane creation events when it opens a new Herdr workspace. `worktree.remove` emits `worktree.removed`; if the linked workspace is still open, it also emits `workspace.closed`.
## Plugin APIs
The plugin API is an early host surface for executable workflow tools. A plugin
is a package with a `herdr-plugin.toml` manifest. The manifest declares
shareable actions, event hooks, terminal pane entrypoints, and link handlers.
Actions and panes are manifest-only; runtime action registration and runtime
argv pane creation are not part of v1.
Installed and linked plugins persist across restarts. Herdr writes a
`plugins.json` registry file alongside `session.json` on `plugin.link`,
`plugin.unlink`, `plugin.enable`, and `plugin.disable`. The
`herdr plugin install` CLI also writes the same registry when Herdr is not
running, then startup loads it automatically. On startup, Herdr re-reads each
manifest from its original path; if the file is missing or unparseable the entry
is kept with a `warnings` field so `plugin.list` surfaces it.
Event hook `on` values are validated against the known Herdr event names at link time. An unrecognised name is not an error — the link still succeeds — but the returned plugin info includes a warning (e.g. `"unknown event 'worktree.craeted'"`). Check the `warnings` field in the `plugin.link` and `plugin.list` responses.
Link a local plugin manifest:
```json
{"id":"req_plugin_link","method":"plugin.link","params":{"path":"/path/to/plugin","enabled":true}}
```
`plugin.link` also accepts optional `source` metadata. The CLI uses this when it installs from GitHub so `plugin.list` can show origin, requested ref, resolved commit, and managed checkout path:
```json
{"id":"req_plugin_link","method":"plugin.link","params":{"path":"/managed/plugin/herdr-plugin.toml","enabled":true,"source":{"kind":"github","owner":"ogulcancelik","repo":"herdr-plugin-examples","subdir":"worktree-bootstrap","requested_ref":"main","resolved_commit":"abc123","managed_path":"/data/plugins/github/<managed-checkout>","installed_unix_ms":1780000000000}}}
```
The path can be a plugin directory containing `herdr-plugin.toml` or a direct
manifest path. The manifest shape is:
```toml
id = "example.worktree-bootstrap"
name = "Worktree Bootstrap"
version = "0.1.0"
min_herdr_version = "0.7.0"
description = "Prepare new worktrees"
platforms = ["linux", "macos", "windows"]
[[build]]
command = ["bun", "install"]
[[actions]]
id = "bootstrap"
title = "Bootstrap worktree"
contexts = ["workspace"]
command = ["bun", "run", "bootstrap.ts"]
[[events]]
on = "worktree.created"
command = ["bun", "run", "bootstrap.ts"]
[[panes]]
id = "board"
title = "Worktree board"
placement = "overlay"
command = ["bun", "run", "board.ts"]
[[link_handlers]]
id = "github-issue"
title = "Open GitHub issue"
pattern = "^https://github\\.com/[^/]+/[^/]+/(issues|pull)/[0-9]+$"
action = "bootstrap"
```
`min_herdr_version` is required. The server refuses to link a plugin when the
field is missing, invalid, or newer than the running Herdr binary.
Declare `platforms` at the top level with the OS identifiers (`linux`, `macos`,
`windows`) your plugin supports. Omitting `platforms` is allowed for local
development — `plugin.link` succeeds but the response includes a warning.
Individual build commands, actions, event hooks, panes, and link handlers can
declare their own `platforms` to override the plugin-level list; if omitted they
inherit from the plugin. Invoking an action or opening a pane whose effective
platforms do not include the current OS returns a `platform_unsupported` error.
List, enable, disable, or unlink linked plugins:
```json
{"id":"req_plugin_list","method":"plugin.list","params":{}}
{"id":"req_plugin_disable","method":"plugin.disable","params":{"plugin_id":"example.worktree-bootstrap"}}
{"id":"req_plugin_enable","method":"plugin.enable","params":{"plugin_id":"example.worktree-bootstrap"}}
{"id":"req_plugin_unlink","method":"plugin.unlink","params":{"plugin_id":"example.worktree-bootstrap"}}
```
Actions are resolved from the linked manifest. `plugin.action.list` returns all actions across installed plugins; pass `plugin_id` to filter.
```json
{"id":"req_plugin_actions","method":"plugin.action.list","params":{}}
{"id":"req_plugin_actions_filtered","method":"plugin.action.list","params":{"plugin_id":"example.worktree-bootstrap"}}
```
`plugin.action.list` returns each action's effective `platforms` after applying
plugin-level inheritance.
Invoke an action by its qualified id or bare action id:
```json
{"id":"req_plugin_invoke","method":"plugin.action.invoke","params":{"action_id":"example.worktree-bootstrap.bootstrap","context":{"invocation_source":"keybinding"}}}
```
`plugin.action.invoke` resolves the manifest action, starts the manifest
command, and returns the Herdr-built invocation context plus the started command
log record. Missing context fields are filled from the active workspace, tab,
focused pane, worktree provenance, and request id. Invoking an action from a
disabled plugin returns a `plugin_disabled` error.
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 available
`HERDR_WORKSPACE_ID`, `HERDR_TAB_ID`, and `HERDR_PANE_ID` values. 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`.
List recent action and event command logs:
```json
{"id":"req_plugin_logs","method":"plugin.log.list","params":{"plugin_id":"example.worktree-bootstrap","limit":20}}
```
Event hooks run for enabled installed plugins when Herdr emits a matching event
name such as `worktree.created`.
There is no Herdr-managed plugin storage API in v1. `HERDR_PLUGIN_CONFIG_DIR`
and `HERDR_PLUGIN_STATE_DIR` are path discovery only; plugins own their files,
schemas, migrations, and cleanup.
Open a managed terminal UI:
```json
{"id":"req_plugin_pane","method":"plugin.pane.open","params":{"plugin_id":"example.board","entrypoint":"board","placement":"zoomed","target_pane_id":"w1:p1","env":{"HERDR_ROLE":"board"},"focus":true}}
```
`plugin.pane.open` requires an installed, enabled, platform-compatible plugin,
then launches the requested manifest `[[panes]]` entrypoint as an argv-backed
terminal pane. Manifest pane `placement` defaults to `overlay`; request
`placement` overrides the manifest with `overlay`, `split`, `tab`, or `zoomed`.
Overlay panes target the active pane. Split and zoomed panes target an existing
pane; tab panes can target a workspace. The pane
behaves like a normal Herdr pane, but `plugin.pane.focus` and
`plugin.pane.close` only operate on panes opened through the plugin API. Focus
returns `plugin_pane_focused`; close returns `plugin_pane_closed`.
## Socket transport
Herdr uses newline-delimited JSON over a Unix domain socket.
Herdr uses newline-delimited JSON over a local socket. On Unix, that socket is a
Unix domain socket. On Windows, it is a named pipe.
Send one request per line:
@ -220,6 +471,10 @@ Resolution order:
Use `HERDR_SOCKET_PATH` only for low-level overrides.
For plugins, prefer invoking `HERDR_BIN_PATH` and the CLI wrappers when you need
portable Windows behavior. Raw socket clients are responsible for using the
platform-native local socket form.
## Agent state reporting
Integrations report agent state with `pane.report_agent`.
@ -229,7 +484,7 @@ Integrations report agent state with `pane.report_agent`.
"id": "req_1",
"method": "pane.report_agent",
"params": {
"pane_id": "1-1",
"pane_id": "w1:p1",
"source": "custom:docs",
"agent": "docs-bot",
"state": "working",
@ -241,7 +496,7 @@ Integrations report agent state with `pane.report_agent`.
`state` is semantic. It affects waits, notifications, and rollups.
`custom_status` is visual. It can show a short label like `indexing` without changing semantic behavior.
`custom_status` is visual. It can show a short activity label like `indexing` without changing semantic behavior.
Session-only official integrations report native session references with `pane.report_agent_session`. State-reporting integrations can still include native session references in `pane.report_agent`. State-independent session reports do not affect waits, notifications, or rollups.
@ -250,7 +505,7 @@ Session-only official integrations report native session references with `pane.r
"id": "req_2",
"method": "pane.report_agent_session",
"params": {
"pane_id": "1-1",
"pane_id": "w1:p1",
"source": "herdr:codex",
"agent": "codex",
"agent_session_id": "..."
@ -282,7 +537,7 @@ Use `pane.report_metadata` when a user hook wants to customize presentation with
"id": "req_2",
"method": "pane.report_metadata",
"params": {
"pane_id": "1-1",
"pane_id": "w1:p1",
"source": "user:claude-title",
"agent": "claude",
"title": "Refactor auth middleware",
@ -298,7 +553,15 @@ Use `pane.report_metadata` when a user hook wants to customize presentation with
}
```
Metadata reports are display-only. Valid metadata can override the pane title, displayed agent name, compact custom status, and visible state labels. `working`, `blocked`, `idle`, waits, notifications, and rollups still come from semantic state. Native session restore comes from stored official session references. `agent` is an optional guard for the authoritative agent label; `applies_to_source` is an optional guard for the active lifecycle authority source. Use `display_agent` to change the visible name. `state_labels` keys must be `idle`, `working`, `blocked`, `done`, or `unknown`. Use clear fields such as `clear_custom_status: true` with the same `source` to remove one presentation override.
Metadata reports are display-only. Valid metadata can override the pane title, displayed agent name, compact activity label, and visible state labels. `working`, `blocked`, `idle`, waits, notifications, and rollups still come from semantic state. Native session restore comes from stored official session references. `agent` is an optional guard for the authoritative agent label; `applies_to_source` is an optional guard for the active lifecycle authority source. Use `display_agent` to change the visible name. `state_labels` keys must be `idle`, `working`, `blocked`, `done`, or `unknown`. Use clear fields such as `clear_custom_status: true` with the same `source` to remove one presentation override.
Presentation text is normalized before storage. Herdr trims surrounding whitespace, removes control characters, caps `custom_status` at 32 characters, and caps `title`, `display_agent`, and each state label at 80 characters. Empty normalized values are ignored.
`source` and `applies_to_source` are source identifiers. They must be 80 characters or fewer and may contain only ASCII letters, digits, colon, dot, underscore, and hyphen.
Use `ttl_ms` for short-lived metadata. It must be between `1` and `86400000` milliseconds. Omit `ttl_ms` for metadata that should stay until replaced, cleared, or the pane closes. When the TTL expires, Herdr removes that source's metadata and emits a presentation change if the visible pane presentation changed.
Use `seq` when a hook may send updates out of order. For the same `source`, reports with a sequence number less than or equal to the last accepted sequence are accepted by the API but ignored by the pane state.
## Event subscriptions
@ -310,7 +573,7 @@ Subscribe to events when you need a long-lived stream:
"method": "events.subscribe",
"params": {
"subscriptions": [
{ "type": "pane.agent_status_changed", "pane_id": "1-1", "agent_status": "blocked" }
{ "type": "pane.agent_status_changed", "pane_id": "w1:p1", "agent_status": "blocked" }
]
}
}
@ -318,19 +581,24 @@ Subscribe to events when you need a long-lived stream:
The first response acknowledges the subscription. Later lines are pushed events.
Workspace event subscriptions include `workspace.created`, `workspace.updated`, `workspace.renamed`, `workspace.closed`, and `workspace.focused`.
Workspace event subscriptions include `workspace.created`, `workspace.updated`, `workspace.renamed`, `workspace.closed`, and `workspace.focused`. Workspace events describe Herdr UI/runtime lifecycle. `workspace.created` includes optional `workspace.worktree` provenance when the workspace belongs to a worktree group. `workspace.closed` includes a final `workspace` snapshot when Herdr can still identify it before removal.
Pane event subscriptions include `pane.created`, `pane.closed`, `pane.focused`,
`pane.moved`, `pane.exited`, `pane.agent_detected`,
`pane.output_matched`, and `pane.agent_status_changed`.
Use `events.wait` when you want one matching event and then a response.
Worktree event subscriptions include `worktree.created`, `worktree.opened`, and `worktree.removed`. Worktree events describe Git checkout lifecycle. `worktree.created` includes the opened `workspace` and created `worktree`. `worktree.opened` includes the target `workspace`, opened `worktree`, and `already_open`. `worktree.removed` includes the `workspace_id`, removed `worktree`, and `forced`.
Use `events.subscribe` for lifecycle events. Dedicated wait helpers are documented separately when a one-shot wait is supported.
## Reading panes
Use `pane.read` through the CLI unless you are writing a protocol client.
```bash
herdr pane read 1-1 --source visible --lines 80
herdr pane read 1-1 --source recent --lines 120
herdr pane read 1-1 --source recent-unwrapped --lines 120
herdr pane read 1-1 --source detection
herdr pane read w1:p1 --source visible --lines 80
herdr pane read w1:p1 --source recent --lines 120
herdr pane read w1:p1 --source recent-unwrapped --lines 120
herdr pane read w1:p1 --source detection
```
`recent-unwrapped` is useful for logs because it ignores soft wrapping.
@ -341,8 +609,8 @@ herdr pane read 1-1 --source detection
Use waits to coordinate agents and scripts.
```bash
herdr wait agent-status 1-1 --status done
herdr wait agent-status 1-1 --status blocked
herdr wait agent-status w1:p1 --status done
herdr wait agent-status w1:p1 --status blocked
```
Agent waits observe semantic state, not arbitrary command completion.
@ -357,10 +625,10 @@ Successful responses look like this:
"result": {
"type": "pane_info",
"pane": {
"pane_id": "1-1",
"pane_id": "w1:p1",
"terminal_id": "term_abc123",
"workspace_id": "1",
"tab_id": "1-1",
"workspace_id": "w1",
"tab_id": "w1:t1",
"focused": true,
"agent_status": "working",
"revision": 42
@ -401,7 +669,7 @@ Fields such as `last_check_unix`, `last_result`, `active_version`, `cached_remot
{
"id": "req_2",
"method": "agent.explain",
"params": { "target": "1-1" }
"params": { "target": "w1:p1" }
}
```

View File

@ -33,11 +33,14 @@ For internal beta testing, `HERDR_MANIFEST_URL` can point the installer at a cus
| Agent self-report integrations | beta |
| Agent process-tree detection | beta |
| Git/worktree detection from known cwd | beta |
| Plugins | preview |
| Pane screen history | beta |
| Nested launch override | beta |
Windows agent process detection scans descendants of the pane shell and recognizes direct agents plus common command wrappers. It is useful for Codex, Claude, and similar agents, but it is not the same as Unix foreground process-group detection.
Plugins support `windows` as a manifest platform in preview. GitHub install, local link, build commands, actions, events, and plugin panes are best effort on Windows. Commands are argv commands and must be Windows-compatible; Node package shims such as `npm`, `bun`, and `node` are expected to work when they are on `PATH`, while Unix-only examples using `sh` or Bash need Windows-specific alternatives. Platform filters skip unsupported build commands and return `platform_unsupported` for unsupported actions or panes.
## Partial support
| Capability | Status |