@narumitw/pi-herdr

Herdr agent-state integration and operating skill for Pi.

Packages

Package details

extensionskill

Install @narumitw/pi-herdr from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@narumitw/pi-herdr
Package
@narumitw/pi-herdr
Version
0.4.0
Published
Nov 6, 2026
Downloads
964/mo · 544/wk
Author
narumitw
License
MIT
Types
extension, skill
Size
255.5 KB
Dependencies
1 dependency · 2 peers
Pi manifest JSON
{
  "skills": [
    "./skills"
  ],
  "extensions": [
    "./dist/index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

🐑 pi-herdr — Herdr Integration for Pi

npm Pi extension License: MIT

Connect Pi's interactive lifecycle to Herdr and load operating guidance from the installed Herdr and Herdr Core CLIs.

✨ Features

  • Reports Pi session identity and working, blocked, and idle lifecycle states to the current Herdr pane.
  • Publishes bounded model, provider, thinking, session, and context_usage tokens for Herdr sidebar rows.
  • Shows recognized sibling agents from the current Herdr workspace in a passive widget above Pi's editor, with a saved visibility toggle in /herdr.
  • Refreshes the widget on Herdr pane, workspace-name, and agent-status updates without polling the CLI.
  • Coalesces rapid state changes and retries short-lived local socket failures without interrupting Pi.
  • Derives blocked state from Pi's public ui_prompt_start and ui_prompt_end lifecycle events.
  • Bundles thin herdr and hc bootstrap skills for explicit inspection and control requests.
  • Loads version-matched operating guidance from herdr --skill or hc --skill.
  • Keeps extension and skill installation in one Pi package.

📦 Install

Install persistently from npm:

pi install npm:@narumitw/pi-herdr

Try from npm without installing permanently:

pi -e npm:@narumitw/pi-herdr

Build and load a local checkout from the repository root:

npm --workspace @narumitw/pi-herdr run build
pi --no-extensions -e ./packages/pi-herdr

An unbuilt local checkout has no generated entrypoint and cannot be loaded by package directory.

Pi extensions and skills run with your user permissions. Install only trusted packages, and review the source and bundled instructions before loading this package.

🚀 Quick start

Start Pi inside a Herdr-managed pane after installing the package. The extension activates automatically when HERDR_ENV=1, HERDR_SOCKET_PATH, and HERDR_PANE_ID are present. When the current Herdr workspace contains another recognized agent, Pi shows its state in a widget above the editor. Ask Pi to use Herdr, or invoke /skill:herdr, when you want it to inspect or control the current Herdr session. Before the first control command, the bootstrap loads herdr --skill once and reuses those instructions while they remain in the current context. For Herdr Core terminals, invoke /skill:hc instead; it loads hc --skill without requiring a Herdr-managed pane.

If the standalone integration and skill are already installed, remove them after installing this package to avoid duplicate state reports and skill-name collisions:

rm ~/.pi/agent/extensions/herdr-agent-state.ts
rm -rf ~/.agents/skills/herdr

Run /reload or restart Pi after changing the installed resources.

🧠 Skills

The bundled skills load CLI-owned guidance once and reuse it while it remains in the current context:

  • herdr, invoked with /skill:herdr, loads herdr --skill for legacy Herdr panes and requires HERDR_ENV=1.
  • hc, invoked with /skill:hc, loads hc --skill for Herdr Core persistent terminals and agents; it requires neither HERDR_ENV=1 nor HC_TERMINAL_ID.

Both skills apply only after an explicit request for their CLI, not merely because a task could use background work or delegation. The CLIs are separate; neither skill substitutes the other CLI when its command fails.

The herdr skill treats panes created for background work as temporary and attempts to close them after collecting the required output. Ask Pi explicitly to keep a pane open after the task when you want to inspect or use it later. Automatic cleanup runs only when the installed Herdr guidance provides a conditional close that atomically confirms the recorded pane ownership and acceptable agent or shell state; otherwise Pi leaves the pane open and reports the limitation.

💬 Commands

/herdr opens a menu to toggle the agent widget and view status or help, inspired by /tool. It accepts no arguments and is available inside Herdr in TUI and RPC modes; print and JSON modes reject it. RPC can save the preference but does not display the widget. Changes apply immediately and closing the menu does not undo saved changes.

⚙️ Settings

Toggle Agent widget in /herdr, or edit <getAgentDir()>/pi-herdr.json (normally ~/.pi/agent/pi-herdr.json):

{
  "widget": false
}

widget accepts only true or false and defaults to true when absent. Only user settings are supported; project files are not read. Manual edits apply after /reload or the next session start. Missing files are not created until an explicit save. Invalid files trigger a warning, use defaults, and block saves until repaired. Saves preserve unknown fields and use atomic temporary-file-plus-rename publication, with reads and writes ordered within one Pi process, not across processes. Failed saves restore the previous effective value and leave the existing file untouched. Turning the widget off closes its subscription and pending requests without disabling lifecycle or metadata reporting.

🔄 Lifecycle reporting

The extension reports only interactive TUI sessions because Herdr displays agents attached to terminal panes. A session report contains the Herdr pane ID, the integration source, Pi's agent kind, a monotonic sequence, the session start reason, and an absolute Pi session path when available. It falls back to Pi's session ID when no absolute session path is available. Agent reports contain the same ownership fields plus the current lifecycle state and optional blocked label. Blocking extension prompts use their Pi-provided title as the label and fall back to the prompt kind.

Local socket delivery is best-effort. Connection failures, malformed responses, and timeouts are retried once with bounded timeouts; explicit API rejections are not retried. Only a complete success response with the matching request ID acknowledges a report. Herdr can acknowledge but ignore an old sequence, so acknowledgement does not guarantee a state change. Reporting failures never stop Pi. Session shutdown aborts and drains in-flight reporting and prevents stale session work from publishing later state. Replacement aborts pending metadata cleanup. Native quit cleanup remains Herdr-owned: the extension does not release native Pi identity or clear reporting authority and restore references. Herdr ignores official-source release requests, while authority clearing also removes session restore data; neither operation is used during shutdown.

🏷️ Pane metadata

The extension publishes only the model, provider, thinking, session, and context_usage token keys through pane.report_metadata under the herdr:pi source. model and provider come from Pi's selected model, thinking comes from Pi's effective Thinking level, and session comes only from Pi's explicit session display name. context_usage is Pi's current context percentage rounded to the nearest whole percent. Every report is a full five-key patch, and an unavailable value is sent as JSON null so old data is cleared instead of retained. Values are stripped of terminal controls, trimmed, and limited to 80 Unicode characters before crossing the socket. The extension never publishes prompts, conversation text, tool arguments, credentials, raw session paths, or inferred session titles as metadata tokens. It also never sets Herdr's pane title, display_agent, state_labels, agent lifecycle state, or session restore fields through metadata.

Metadata is evaluated after session_start, session_info_changed, model_select, thinking_level_select, agent_settled, and successful session_compact events. Unchanged event snapshots are suppressed, rapid changes are coalesced, and the latest unchanged snapshot is refreshed no more often than every 30 minutes. Each token has a one-hour TTL, so data from a crashed Pi process expires without steady socket traffic. Orderly shutdown sends one best-effort five-key clear patch, while abrupt shutdown and failed clears fall back to the TTL. Metadata uses the lifecycle reporter's monotonic sequence allocator and bounded best-effort sender, so older delayed reports cannot replace newer accepted values and socket failures never interrupt Pi.

Herdr custom pane tokens use a $name row entry. For example, this Herdr configuration displays Pi's model context without replacing pane labels or agent identity:

[ui.sidebar.agents]
rows = [
  ["state_icon", "agent"],
  ["$provider", "$model", "$thinking"],
  ["$session", "$context_usage"],
]

🐑 Agent widget

The widget lists only recognized agents in the current Herdr workspace and excludes the pane running the current Pi session. Each row presents state, agent, pane, and workspace in that order, using theme hierarchy instead of repeating field labels. State icons follow Herdr's distinct static symbols: × blocked, ◐ working, ✓ done, ○ idle, and · unknown. Pi theme roles map blocked to error, working to warning, done to accent, idle to success, and unknown to dim without hard-coded terminal colors. Agent identity prefers the name assigned by herdr agent rename, then Herdr display metadata, and finally the detected agent kind. Pane identity uses its label or metadata title with a short pane ID, while workspace identity uses its label with a short workspace ID. Terminal titles are not used as agent identity. The widget orders agents by blocked, done, working, idle, and unknown, shows at most five rows, and reports any remaining count. A state label published through Herdr metadata can replace the raw state name. Herdr's public pane responses do not expose the blocked prompt message, so the widget cannot show that reason. The widget is read-only and does not focus panes, read terminal output, send prompts, or mark a background done state as seen. The extension discovers the current workspace, pane list, and agent names, opens pane-scoped status subscriptions plus pane-update and workspace-name subscriptions, and then reloads those identities. Events trigger serialized, coalesced reads rather than replacing current state with event payloads. If an event arrives during a read, the extension reads again before publishing that result. Agent names, workspace labels, and cleared presentation fields update from these authoritative reads. Changes to the current pane, workspace, or recognized-agent set rebuild the pane-scoped subscriptions without consuming the bounded failure retry. Unexpected disconnection or events_lost clears the widget before one bounded reconnect attempt, and a second failure leaves it hidden until the next Pi session or /reload. Session replacement and shutdown abort the subscription, pending reads, reconnect delay, and stale widget publication.

🔒 Security and privacy

The extension connects only to the Unix socket or Windows named pipe provided by HERDR_SOCKET_PATH. Lifecycle reporting sends the current Herdr pane ID, Pi session path or ID, lifecycle state, session start reason, and blocked label to that endpoint. Metadata reporting sends the current Herdr pane ID plus only the selected model ID, provider ID, effective Thinking level, explicit Pi session name, and rounded context-usage percentage. For the widget, it reads the canonical current pane, current workspace metadata, current workspace pane list, and session agent list, then subscribes to pane creation, updates, closure, movement, exit, agent detection, agent-status changes, and workspace renames. The session agent list can contain agent metadata from other workspaces, but the extension retains names only for panes in the current workspace list. Widget fields can include workspace, tab, pane, terminal, agent, display, name, title, label, state-label, and lifecycle identifiers supplied by Herdr. The subscription can deliver matching pane events from other workspaces in the same Herdr session, and the extension ignores them after resolving the current workspace. The extension filters presentation to the current workspace, strips terminal controls at the display boundary, and never reads sibling terminal output for the widget. The package does not authenticate the endpoint, so trust the environment that launches Pi and controls these variables.

The bundled skills load operating guidance from the local CLI only after an explicit request for Herdr or Herdr Core. The returned CLI-owned instructions can direct Pi to inspect terminals, create panes or persistent terminals, start agents, send input, and run local or remote commands. Those commands execute with the same user permissions as Pi and can affect live terminal sessions. Both bootstraps stop when their CLI is unavailable or its --skill command fails; the herdr bootstrap also stops when HERDR_ENV is not 1. Command recipes, approval handling, and other operating safety rules come from the selected CLI's installed version instead of being duplicated by this package.

🚧 Limitations

  • Lifecycle reporting, metadata reporting, and the agent widget are disabled in RPC, JSON, and print modes.
  • The widget has no settings for placement, workspace scope, or row count.
  • The widget cannot show blocked prompt text because Herdr does not expose it through public pane responses.
  • The widget requires compatible pane-update and workspace-name subscriptions; unsupported subscriptions hide the widget without disabling lifecycle or metadata reporting.
  • A pane-label change appears on its next update event or authoritative refresh; an agent rename emits a pane-update event.
  • Integration requires a running compatible Herdr session and valid injected environment variables.
  • Each skill requires its matching CLI with --skill support; hc does not enable the legacy Herdr lifecycle reports or widget.
  • Socket failures are intentionally silent after the bounded retry.
  • Skill cleanup tracking exists only in the active model context, so compaction, session replacement, /reload, or shutdown can leave temporary panes open.
  • The package does not install, start, update, or configure Herdr or Herdr Core itself.

🗂️ Package layout

packages/pi-herdr/
├── src/                               # Authoritative implementation and helpers
│   ├── index.ts                       # Thin repository entrypoint
│   └── herdr-agent-state.ts           # Herdr lifecycle integration
├── dist/                              # Generated TypeScript runtime loaded by Pi
├── scripts/                           # Deterministic runtime builder
├── skills/                            # Published herdr and hc bootstraps for CLI-owned guidance
└── test/                              # Behavior and lifecycle coverage

🔎 Keywords

Pi, Herdr, Herdr Core, hc, terminal multiplexer, persistent terminals, coding agents, agent orchestration, lifecycle state.

📄 License

MIT. See LICENSE.