@muzi3/herdr
Herdr for pi: three independent extensions (agent + blocked state reporting, /pi-hot-restart, and the herdr_layout / herdr_pane / herdr_agent pane control tools forked from @ogulcancelik/pi-herdr) plus the herdr-guide skill.
Package details
Install @muzi3/herdr from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@muzi3/herdr- Package
@muzi3/herdr- Version
0.2.2- Published
- Sep 16, 2026
- Downloads
- 116/mo · 3/wk
- Author
- muzi3
- License
- Apache-2.0 AND MIT
- Types
- extension, skill
- Size
- 96.1 KB
- Dependencies
- 0 dependencies · 0 peers
Pi manifest JSON
{
"skills": [
"./skills"
],
"extensions": [
"./extensions/herdr-agent-state/index.ts",
"./extensions/pane-agent-tools/index.ts",
"./extensions/pi-hot-restart/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@muzi3/herdr
Herdr 相关的官方 guide skill、pane/agent 控制工具与本地补充扩展打包为一个 pi package。
| 资源 | 类型 | 说明 |
|---|---|---|
herdr_layout / herdr_pane / herdr_agent |
扩展(fork) | pane/agent 控制工具:工作区 · tab · pane 拓扑,pane 的命令下发/读取/等输出/收发按键,以及 coding agent 的启动、prompt、等待与读取 |
herdr-guide |
user-invoked 向导 | 引导用户理解、安装、配置与排查 Herdr(herdr.dev/agent-guide.md) |
herdr-agent-state |
扩展 | 通过 Herdr 的 pane socket 上报 agent 状态(working / blocked / idle)及会话引用,供 Herdr 面板展示;并把 pi 的阻塞式交互弹窗(ui_prompt_start / ui_prompt_end,含 ask_user_question)转发为 herdr 的 herdr:blocked 事件,使 pane 变为 blocked(label 带问题摘要);桌面通知交给 herdr 自己发 |
pi-hot-restart |
扩展 | 提供 /pi-hot-restart 命令:批量重启当前 herdr 里的所有 pi 窗口(跳过 working),并恢复到原 session |
三个扩展互相独立:每个扩展独占 extensions/ 下的一个目录、以 index.ts 为入口,互不 import,package.json 的 pi.extensions 逐条列出入口。一个扩展注册失败不会连带拖垮另外两个,日后给某个扩展加内部模块也不会影响另外两个。
扩展结构
extensions/
├── herdr-agent-state/index.ts agent 状态 + blocked 状态上报
├── pane-agent-tools/index.ts herdr_layout / herdr_pane / herdr_agent
└── pi-hot-restart/index.ts /pi-hot-restart
| 入口 | 内容 | 加载门槛 |
|---|---|---|
herdr-agent-state/index.ts |
agent 状态 + blocked 状态上报(herdr 官方集成正文 + 本包并入的 blocked 段落) | HERDR_ENV=1 且 HERDR_SOCKET_PATH / HERDR_PANE_ID 非空 |
pi-hot-restart/index.ts |
/pi-hot-restart 命令(本包自研补充) |
无,走 PATH 调 herdr CLI |
pane-agent-tools/index.ts |
herdr_layout / herdr_pane / herdr_agent(本地 fork) |
HERDR_ENV=1 且 HERDR_PANE_ID 非空 |
门槛由各扩展自己判断(没有统一 gate),所以在 herdr 之外 /pi-hot-restart 仍可用(它只控制本机进程,不需要 pane socket),依赖 pane 的两个扩展则静默跳过。
每个扩展目录的入口都叫 index.ts,与 pi 自己的目录式扩展约定一致:扩展目录内可以再放内部模块,pi.extensions 只指向入口,不会误加载旁支文件。
herdr-agent-state/index.ts 的目录名与 herdr 集成注入的文件同名,对齐上游时可以直接对比。内容分两段:官方集成正文(一直到文件末尾之前)与之后的「本包新增」段落。本包对官方正文只有一处改动:官方 export default 开头插入一行 registerBlockedReporting(pi); —— 该 default export 就是本扩展的唯一入口,blocked 上报只能挂在那里。重新同步上游时(HERDR_INTEGRATION_VERSION 从 8 往上升)重取注入文件替换官方正文并补回那一行;diff 应只有三处新增、零删除,漏帖那一行会被 tests/herdr-agent-state.test.ts 拦下。
来源与许可
两者内容均来自 Herdr 官方,上游仓库为 herdrdev/herdr:
herdr-guide引导 skill —— 官方herdr.dev/agent-guide.md,教 agent 引导用户理解/配置/排障 Herdrherdr-agent-state扩展 —— Herdr 官方pi集成的 bundled 扩展,本包保留其正文,只做一处改动(在官方export default开头插入一行 blocked 上报),其余新增都在文件末尾的段落里。herdr integration install pi会把官方版本写入~/.pi/agent/extensions/herdr-agent-state.ts(若设置PI_CODING_AGENT_DIR则写入$PI_CODING_AGENT_DIR/extensions/)
Herdr 以 Apache-2.0 许可发布,本包保留其许可声明,详见 LICENSE。
⚠️ 本包这份与集成写入的那份目录名相同、位置不同(本包
extensions/herdr-agent-state/index.ts,集成写~/.pi/agent/extensions/herdr-agent-state.ts)。若已执行过herdr integration install pi,agent 目录里的副本会被 pi 自动加载,与本包同时上报状态(herdr 的blockedCount会短暂变成 2,然后一起归零)。本包已自带该功能,用本包时不必安装集成;已安装的话请删掉~/.pi/agent/extensions/herdr-agent-state.ts。无论装不装集成,agent 目录里那份都由集成管理,重装或更新集成会覆盖它;自定义 hooks 请写成旁边的独立文件而非编辑它(本包这份是 vendored 副本,由本包自己维护)。
extensions/pane-agent-tools/index.ts(herdr_layout / herdr_pane / herdr_agent)是本地 fork,来源与许可与上面不同:
- 上游:
@ogulcancelik/pi-herdr0.4.0(仓库,MIT,Copyright (c) 2026 Can Celik),许可全文见本包LICENSE.MIT - 因此本包整体按
Apache-2.0 AND MIT双许可表述:LICENSE(Apache-2.0)覆盖 Herdr 官方内容与pi-hot-restart.ts,LICENSE.MIT覆盖 fork 进来的pane-agent-tools.ts
相对上游的改动
上游 0.4.0 把 pane run / pane send-text / pane send-keys 交给 execHerdrJson,而它额外要求 herdr CLI 输出 JSON envelope。但 herdr 0.9.0 上这三条命令成功时退出码为 0 且 stdout 为空,于是每一次写操作都误报 Expected JSON output from herdr ... —— 即使命令早已成功下发到目标 pane。实测 14 天内 156 个 pi session 日志,误报次数为 send-keys 964、send-text 923、run 438。
这三处改用 execHerdr:它只校验退出码,并把 stderr/stdout 上的结构化 herdr 错误经 parseHerdrError 抛出,因此真实失败照旧报错,只去掉了那个不成立的「stdout 必须非空」约束。pane close / pane wait-output / agent send-keys 确实返回 envelope,保持 execHerdrJson(close 的边界由回归测试锁定)。
上游尚未修复,相关讨论:issue #22、issue #40、PR #27(仅覆盖 run,未合并)。本包已不依赖 @ogulcancelik/pi-herdr:同时安装两者会重复注册同名工具,需先卸载上游包。
安装
pi install npm:@muzi3/herdr
用法
- 用户询问 Herdr 是什么、怎么安装/配置/使用,或排查 agent 未识别、快捷键失效等问题时,触发
herdr-guide引导(/herdr-guide) - 触发词:
herdr/herdr 安装/herdr 配置/终端工作区/agent 状态检测等
pane / agent 控制工具
三个工具直接驱动 herdr CLI,需在 herdr 集成环境(HERDR_ENV=1 + HERDR_PANE_ID)中加载:
herdr_layout—— 工作区 / tab / pane 的创建、列举与拓扑查询(current/workspace_list/pane_split/pane_layout等)herdr_pane—— 普通进程的 pane 控制:run下发命令、read读回输出、wait_output等匹配输出、send_text/send_keys收发按键、close关闭(拒绝关闭 pi 自身所在 pane)herdr_agent—— 已识别 coding agent 的 pane:start/prompt/wait/read/send_keys/rename等
批量重启 pi 窗口
在任意 pi 窗口执行 /pi-hot-restart,会:
- 列出当前 herdr 里所有
pi窗口; - 跳过
agent_status === "working"的窗口(含当前发起命令的窗口本身); - 弹出确认框,展示将重启的窗口清单与数量;
- 对每个目标窗口:向 pi 前台进程组发 SIGTERM 优雅退出(session 落盘),等待退出后用
pi --session <path|id>在原 pane 恢复。
等用户输入时上报 blocked
herdr 的 pi 集成只认 herdr:blocked 事件,且 herdr 0.9.0 对 pi 仍没有终端 blocked 识别规则(内置规则只有一条 working_literal,匹配 Working...),所以 ask_user_question / confirm 弹窗期间 pane 会一直停在 working。本扩展的 blocked 上报段落订阅 pi core 的 ui_prompt_start / ui_prompt_end(select/confirm/input/editor/custom 统一包装,只在外层触发):
- 等待期发
herdr:blocked { active: true, label },结束后发{ active: false };label 形如等待回答:<问题 header>(custom无 title,取rpiv:ask-user:prompt的问题内容)、等待确认:<title>。 - 契约同 pi-subagents 的 herdr-status bridge:herdr 的
blockedCount是计数式的,切 label 前先发active:false再发active:true;本扩展严格配对,只占一个计数。
桌面通知交给 herdr 自己发(~/.config/herdr/config.toml 设 [ui.toast] delivery = "terminal"):通知经终端转交给 Ghostty 显示,点击横幅会把 Ghostty 窗口调到前面。注意它只能到窗口粒度 —— herdr 的 pane 是 herdr TUI 内部的概念,点通知不会切到对应 pane;正文也固定为 <工作区名> · <工作区编号> · <tab 名>,不含 pane id 与问题原文。早期版本试过自建横幅(osascript / terminal-notifier),内容能带 pane 与问题原文,但要么不支持点击动作、要么在本机通知权限不稳;点击跳转要能捕获回调的通知器(如 alerter)才可能做到,为避免与 herdr 自己的通知重复弹两份,自建横幅已整体移除。
扩展环境变量
扩展需在 Herdr 集成环境中运行,依赖以下环境变量:
| 变量 | 说明 |
|---|---|
HERDR_ENV |
为 1 时启用扩展 |
HERDR_SOCKET_PATH |
Herdr pane socket 路径 |
HERDR_PANE_ID |
当前 pane id(同时作为扩展的运行门槛) |
未设置时 herdr-agent-state 与 pane-agent-tools 两个扩展静默跳过(门槛见「扩展结构」),/pi-hot-restart 仍可用:它通过 PATH 调用 herdr CLI(agent list / pane process-info / pane run),不依赖上述变量。
测试
node --test tests/ # 等价于 npm test
tests/ 下三个文件、共 28 个用例,node:test + node:assert/strict,无需引入 bun(Node 原生剥离 TS 类型):
tests/pane-agent-tools.test.ts —— 由上游 index.test.ts(bun:test)改写。除移植的 9 个用例外,额外覆盖本 fork 的 3 行改动:
pane run/send_text/send_keys在 stdout 为空时成功,且恰好调用一次 herdr- stdout 为 banner/ANSI 等非 JSON 内容时不当作协议数据解析
- 结构化 herdr 错误(stderr envelope)与裸非零退出仍然报错,不会被「只校验退出码」吞掉
pane close仍走 JSON envelope 路径
这组用例对上游写法运行会有 4 个失败、对当前实现 16 个全通过,可用于确认回归网没有失效。
tests/herdr-agent-state.test.ts —— 起一个真实 unix socket 充当 pane socket,验证 agent 状态(working / idle)与 blocked 上报(含 label 取值、弹窗结束后的回落)真的落到连接上。用真 socket 而非桩:上报的成败判据本身就在连接上(sendRequestAttempt 只有连上并收到对端数据才算送达),桩掉 net 等于把被测逻辑一起桩掉。这一组只调 default export(扩展唯一入口),所以官方正文里那行 registerBlockedReporting(pi); 被漏帖时会直接失败。
tests/extensions.test.ts —— 把「三个扩展各自独立」锁成断言:pi.extensions 与 extensions/ 下的扩展目录一一对应(不漏声明、也不留死路径)、每个扩展目录都有 index.ts 入口且顶层没有散落的扩展文件、扩展之间没有跨目录 import,并且单独加载每个扩展时只会注册自己的资源(herdr-agent-state 只挂状态监听,pi-hot-restart 只有 /pi-hot-restart,pane-agent-tools 只有三个工具)。
参考
- 官方文档:https://herdr.dev/docs/
- 引导 guide 原文:https://herdr.dev/agent-guide.md
- 集成文档(Pi 章节):https://herdr.dev/docs/integrations/
- 上游仓库:https://github.com/herdrdev/herdr
- pi-herdr 上游仓库:https://github.com/ogulcancelik/pi-extensions/tree/main/packages/pi-herdr