diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-20 00:54:05 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-20 00:55:36 +0300 |
| commit | d30ab1b54f6b6be95a0cb47ddc38da1d5e088700 (patch) | |
| tree | eb2002b408c856d9fcd7a573afe73b917f22cd97 /docs/next | |
| parent | 3f80947678a9723434aa7fddfe23750b5393e24c (diff) | |
feat: add plugin-driven agent views and startup hooks
Diffstat (limited to 'docs/next')
| -rw-r--r-- | docs/next/CHANGELOG.md | 2 | ||||
| -rw-r--r-- | docs/next/api/herdr-api.schema.json | 366 | ||||
| -rw-r--r-- | docs/next/website/src/content/docs/plugins.mdx | 34 | ||||
| -rw-r--r-- | docs/next/website/src/content/docs/socket-api.mdx | 80 |
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. |
