aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-20 00:54:05 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-20 00:55:36 +0300
commitd30ab1b54f6b6be95a0cb47ddc38da1d5e088700 (patch)
treeeb2002b408c856d9fcd7a573afe73b917f22cd97 /docs
parent3f80947678a9723434aa7fddfe23750b5393e24c (diff)
feat: add plugin-driven agent views and startup hooks
Diffstat (limited to 'docs')
-rw-r--r--docs/next/CHANGELOG.md2
-rw-r--r--docs/next/api/herdr-api.schema.json366
-rw-r--r--docs/next/website/src/content/docs/plugins.mdx34
-rw-r--r--docs/next/website/src/content/docs/socket-api.mdx80
4 files changed, 475 insertions, 7 deletions
diff --git a/docs/next/CHANGELOG.md b/docs/next/CHANGELOG.md
index f9805cda..64bd38f8 100644
--- a/docs/next/CHANGELOG.md
+++ b/docs/next/CHANGELOG.md
@@ -4,6 +4,8 @@
### Added
- Added a live-agent CLI facade with named `start`, atomic `prompt`, logical `send-keys`, and server-owned `wait` workflows. Agent startup targets an existing pane without changing topology, validates the requested interactive agent kind and strict agent name, and accepts native arguments after `--`.
+- Added transient declarative Agent view queries through `agent.view.set/clear`; filtered and sorted views now define sidebar, mobile, mouse, and agent-keybind navigation order.
+- Added one-shot plugin `[[startup]]` hooks for restoring plugin-owned state after server startup and live handoff.
- Added `ui.sidebar_start_collapsed` to launch Herdr with the sidebar collapsed. (#1463)
- Added macOS support for the `HERDR_AGENT=<agent>` foreground-process hint, allowing agents hidden behind host-visible wrappers such as `nono` to use the named agent's screen manifest. (#679)
diff --git a/docs/next/api/herdr-api.schema.json b/docs/next/api/herdr-api.schema.json
index b066574f..dab07fb2 100644
--- a/docs/next/api/herdr-api.schema.json
+++ b/docs/next/api/herdr-api.schema.json
@@ -1354,6 +1354,283 @@
],
"type": "object"
},
+ "AgentViewBuiltinField": {
+ "enum": [
+ "status",
+ "workspace_id",
+ "tab_id",
+ "pane_id",
+ "agent",
+ "seen",
+ "state_change_seq"
+ ],
+ "type": "string"
+ },
+ "AgentViewBuiltinSortField": {
+ "enum": [
+ "workspace_order",
+ "tab_order",
+ "pane_order",
+ "attention",
+ "status",
+ "agent",
+ "seen",
+ "state_change_seq"
+ ],
+ "type": "string"
+ },
+ "AgentViewClearParams": {
+ "properties": {
+ "source": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ },
+ "AgentViewContext": {
+ "enum": [
+ "current_workspace_id",
+ "current_tab_id"
+ ],
+ "type": "string"
+ },
+ "AgentViewField": {
+ "anyOf": [
+ {
+ "$ref": "#/schemas/request/$defs/AgentViewBuiltinField"
+ },
+ {
+ "properties": {
+ "token": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "token"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ "AgentViewFilter": {
+ "oneOf": [
+ {
+ "properties": {
+ "filters": {
+ "items": {
+ "$ref": "#/schemas/request/$defs/AgentViewFilter"
+ },
+ "type": "array"
+ },
+ "op": {
+ "const": "all",
+ "type": "string"
+ }
+ },
+ "required": [
+ "op",
+ "filters"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "filters": {
+ "items": {
+ "$ref": "#/schemas/request/$defs/AgentViewFilter"
+ },
+ "type": "array"
+ },
+ "op": {
+ "const": "any",
+ "type": "string"
+ }
+ },
+ "required": [
+ "op",
+ "filters"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "filter": {
+ "$ref": "#/schemas/request/$defs/AgentViewFilter"
+ },
+ "op": {
+ "const": "not",
+ "type": "string"
+ }
+ },
+ "required": [
+ "op",
+ "filter"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "field": {
+ "$ref": "#/schemas/request/$defs/AgentViewField"
+ },
+ "op": {
+ "const": "eq",
+ "type": "string"
+ },
+ "value": {
+ "$ref": "#/schemas/request/$defs/AgentViewValue"
+ }
+ },
+ "required": [
+ "op",
+ "field",
+ "value"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "field": {
+ "$ref": "#/schemas/request/$defs/AgentViewField"
+ },
+ "op": {
+ "const": "in",
+ "type": "string"
+ },
+ "values": {
+ "items": {
+ "$ref": "#/schemas/request/$defs/AgentViewValue"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "op",
+ "field",
+ "values"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "field": {
+ "$ref": "#/schemas/request/$defs/AgentViewField"
+ },
+ "op": {
+ "const": "exists",
+ "type": "string"
+ }
+ },
+ "required": [
+ "op",
+ "field"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ "AgentViewSetParams": {
+ "properties": {
+ "filter": {
+ "anyOf": [
+ {
+ "$ref": "#/schemas/request/$defs/AgentViewFilter"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "label": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "sort": {
+ "items": {
+ "$ref": "#/schemas/request/$defs/AgentViewSort"
+ },
+ "type": "array"
+ },
+ "source": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "source"
+ ],
+ "type": "object"
+ },
+ "AgentViewSort": {
+ "properties": {
+ "field": {
+ "$ref": "#/schemas/request/$defs/AgentViewSortField"
+ },
+ "order": {
+ "$ref": "#/schemas/request/$defs/AgentViewSortOrder",
+ "default": "asc"
+ }
+ },
+ "required": [
+ "field"
+ ],
+ "type": "object"
+ },
+ "AgentViewSortField": {
+ "anyOf": [
+ {
+ "$ref": "#/schemas/request/$defs/AgentViewBuiltinSortField"
+ },
+ {
+ "properties": {
+ "token": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "token"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ "AgentViewSortOrder": {
+ "enum": [
+ "asc",
+ "desc"
+ ],
+ "type": "string"
+ },
+ "AgentViewValue": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "format": "uint64",
+ "minimum": 0,
+ "type": "integer"
+ },
+ {
+ "properties": {
+ "context": {
+ "$ref": "#/schemas/request/$defs/AgentViewContext"
+ }
+ },
+ "required": [
+ "context"
+ ],
+ "type": "object"
+ }
+ ]
+ },
"AgentWaitParams": {
"properties": {
"target": {
@@ -4601,6 +4878,38 @@
{
"properties": {
"method": {
+ "const": "agent.view.set",
+ "type": "string"
+ },
+ "params": {
+ "$ref": "#/schemas/request/$defs/AgentViewSetParams"
+ }
+ },
+ "required": [
+ "method",
+ "params"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "method": {
+ "const": "agent.view.clear",
+ "type": "string"
+ },
+ "params": {
+ "$ref": "#/schemas/request/$defs/AgentViewClearParams"
+ }
+ },
+ "required": [
+ "method",
+ "params"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "method": {
"const": "agent.focus",
"type": "string"
},
@@ -6632,6 +6941,12 @@
"kind": "local"
}
},
+ "startup": {
+ "items": {
+ "$ref": "#/schemas/success_response/$defs/PluginManifestStartup"
+ },
+ "type": "array"
+ },
"version": {
"type": "string"
},
@@ -7975,6 +8290,29 @@
],
"type": "object"
},
+ "PluginManifestStartup": {
+ "properties": {
+ "command": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "platforms": {
+ "items": {
+ "$ref": "#/schemas/success_response/$defs/PluginPlatform"
+ },
+ "type": [
+ "array",
+ "null"
+ ]
+ }
+ },
+ "required": [
+ "command"
+ ],
+ "type": "object"
+ },
"PluginPaneInfo": {
"properties": {
"entrypoint": {
@@ -8451,6 +8789,34 @@
},
{
"properties": {
+ "active": {
+ "type": "boolean"
+ },
+ "label": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "source": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "type": {
+ "const": "agent_view",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "active"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
"pane": {
"$ref": "#/schemas/success_response/$defs/PaneInfo"
},
diff --git a/docs/next/website/src/content/docs/plugins.mdx b/docs/next/website/src/content/docs/plugins.mdx
index 500ae5a3..c86dc69a 100644
--- a/docs/next/website/src/content/docs/plugins.mdx
+++ b/docs/next/website/src/content/docs/plugins.mdx
@@ -73,6 +73,9 @@ command = ["npm", "ci"]
command = ["npm", "run", "build"]
platforms = ["linux", "macos"]
+[[startup]]
+command = ["node", "dist/restore.js"]
+
[[actions]]
id = "apply"
title = "Apply layout"
@@ -109,9 +112,10 @@ 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.
+can run. Build commands, startup hooks, 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
@@ -222,6 +226,24 @@ 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.
+## Startup hooks
+
+`[[startup]]` commands run once for each enabled plugin after Herdr restores the
+session and its API socket is ready. They run again when a new server takes over
+during live handoff, but not when a client attaches, config reloads, or a plugin
+is linked or enabled. Herdr starts them asynchronously and records their
+completion in the normal plugin command log. A startup failure does not stop the
+server.
+
+Startup hooks are one-shot initialization commands, not supervised daemons. A
+hook should restore plugin-owned state, call any required Herdr APIs, and exit.
+For example, a plugin can save a declarative Agent view under
+`HERDR_PLUGIN_STATE_DIR`, then read and reapply that view from its startup hook.
+
+Startup hooks receive the normal runtime plugin environment and
+`HERDR_PLUGIN_EVENT=startup`. The install preview lists every startup command so
+users can review code that will run automatically.
+
## Commands and environment
Runtime commands run with the plugin directory as their working directory. Herdr
@@ -229,8 +251,10 @@ 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`.
+receive `HERDR_PLUGIN_ACTION_ID`; startup and event hooks receive
+`HERDR_PLUGIN_EVENT` (`startup` for startup hooks), event hooks additionally
+receive `HERDR_PLUGIN_EVENT_JSON`, and 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
diff --git a/docs/next/website/src/content/docs/socket-api.mdx b/docs/next/website/src/content/docs/socket-api.mdx
index 66072d3c..68045ecb 100644
--- a/docs/next/website/src/content/docs/socket-api.mdx
+++ b/docs/next/website/src/content/docs/socket-api.mdx
@@ -106,7 +106,7 @@ Raw socket method names use dot notation:
| 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.graphics.info`, `pane.graphics.set`, `pane.graphics.clear`, `pane.graphics.stream`, `pane.report_agent`, `pane.report_agent_session`, `pane.report_metadata`, `pane.clear_agent_authority`, `pane.release_agent`, `pane.close`, `pane.wait_for_output` |
| Popup | `popup.close` |
| Layout | `layout.export`, `layout.apply`, `layout.set_split_ratio` |
-| Agent | `agent.list`, `agent.get`, `agent.read`, `agent.explain`, `agent.send_keys`, `agent.prompt`, `agent.wait`, `agent.rename`, `agent.focus`, `agent.start` |
+| Agent | `agent.list`, `agent.get`, `agent.read`, `agent.explain`, `agent.send_keys`, `agent.prompt`, `agent.wait`, `agent.rename`, `agent.focus`, `agent.start`, `agent.view.set`, `agent.view.clear` |
| 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` |
@@ -366,11 +366,87 @@ Use at most one of `workspace_id` or `cwd` for `worktree.list`, `worktree.create
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`.
+## Agent view queries
+
+`agent.view.set` installs one transient declarative projection for the built-in
+Agents view. The projection is reevaluated whenever agent facts or current UI
+context change. It controls the expanded and collapsed sidebar, mobile Agents
+list, mouse targets, indexed focus, and next/previous Agent navigation. It does
+not change `agent.list`, notifications, detection, or global attention counts.
+
+Show agents in the currently presented Space or agents needing attention
+elsewhere, then order by attention and most recent state transition:
+
+```json
+{
+ "id": "view_set",
+ "method": "agent.view.set",
+ "params": {
+ "source": "plugin:example.agent-views",
+ "label": "focus",
+ "filter": {
+ "op": "any",
+ "filters": [
+ {
+ "op": "eq",
+ "field": "workspace_id",
+ "value": {"context": "current_workspace_id"}
+ },
+ {
+ "op": "in",
+ "field": "status",
+ "values": ["blocked", "done"]
+ }
+ ]
+ },
+ "sort": [
+ {"field": "attention", "order": "desc"},
+ {"field": "state_change_seq", "order": "desc"}
+ ]
+ }
+}
+```
+
+Filter nodes use `op` values `all`, `any`, `not`, `eq`, `in`, or `exists`.
+Built-in filter fields are `status`, `workspace_id`, `tab_id`, `pane_id`,
+`agent`, `seen`, and `state_change_seq`. Use `{"token":"name"}` as a field to
+filter plugin-reported pane metadata. Values are strings, booleans, unsigned
+numbers, or a context object. Context values are `current_workspace_id` and
+`current_tab_id`, and may only be compared to the matching ID field. Effective
+status values are `idle`, `working`, `blocked`, `done`, and `unknown`; `done`
+means idle and not yet seen.
+
+Sort fields are `workspace_order`, `tab_order`, `pane_order`, `attention`,
+`status`, `agent`, `seen`, `state_change_seq`, or `{"token":"name"}`. Sorts are
+stable, evaluated in order, and accept `asc` or `desc`. Missing values stay
+after present values. When `sort` is omitted, the existing
+`ui.agent_panel_sort` policy remains active. A custom sort temporarily replaces
+that policy without rewriting config.
+
+`source` identifies the owner. Plugins use `plugin:<HERDR_PLUGIN_ID>`; Herdr
+rejects plugin-owned sets when that plugin is missing or disabled. Other callers
+may use their own non-`plugin:` source. A successful set atomically replaces the
+previous view. The view lasts until it is cleared, replaced, its owning plugin
+is disabled, unlinked, or uninstalled, or the server exits. Plugins that want
+durable behavior should save the query under `HERDR_PLUGIN_STATE_DIR` and
+reapply it from a `[[startup]]` hook.
+
+Clear unconditionally, or only when the named source still owns the view:
+
+```json
+{"id":"view_clear","method":"agent.view.clear","params":{}}
+{"id":"view_clear_owned","method":"agent.view.clear","params":{"source":"plugin:example.agent-views"}}
+```
+
+A source mismatch leaves the active view unchanged. Set and clear responses use
+`type: "agent_view"` and report `active`, `source`, and optional `label`.
+
## 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.
+startup hooks, shareable actions, event hooks, terminal pane entrypoints, and
+link handlers. Startup hooks run once after restore when the API is ready.
Actions and panes are manifest-only; runtime action registration and runtime
argv pane creation are not part of v1.