首页
/ Ponytail for Hermes:插件启用、斜杠命令与内置技能全解

Ponytail for Hermes:插件启用、斜杠命令与内置技能全解

2026-09-05 15:36:40作者:滕妙奇

本文基于仓库中的 Hermes 安装后指南 after-install.md,完整讲清 Ponytail 在 Hermes Agent 中的启用步骤、共享网关下的访问控制要点,以及全部六个斜杠命令与内置技能的行为语义。读完你会掌握 Hermes 插件的安装后配置流程、默认模式解析优先级(环境变量 → 配置文件 → full),并能结合 plugin.yamlinit.py 的注册逻辑理解规则注入和网关命令改写的底层实现。

1. 背景:Hermes 为什么有独立的"安装后"环节

Ponytail 的定位是让 AI agent 像"最懒的资深工程师"一样思考——写代码前先走完七级梯子(YAGNI → 代码库复用 → 标准库 → 平台原生特性 → 已安装依赖 → 一行 → 最小可用实现),把不必要的抽象、脚手架和依赖直接砍掉。

在 Claude Code、Codex 等单机 agent 中,安装即生效;但 Hermes 是面向多用户、多通道的 agent 网关,插件安装(hermes plugins install)与启用是两步分离的操作,且斜杠命令会被转发到共享网关上。正因为这两个差异,仓库才为 Hermes 单独提供了一份 after-install.md 安装后指南。仓库根目录的 plugin.yaml 就是 Hermes 插件清单,其中声明了插件名 ponytail、版本(与 package.json4.9.0 对齐)、两个钩子(pre_llm_callpre_gateway_dispatch)、六个命令和六个技能:

name: ponytail
version: 4.9.0
provides_hooks:
  - pre_llm_call
  - pre_gateway_dispatch
provides_commands:
  - ponytail
  - ponytail-review
  - ponytail-audit
  - ponytail-debt
  - ponytail-gain
  - ponytail-help
provides_skills:
  # 与 provides_commands 同名的六个技能

2. 启用插件:安装后的必要一步

如果你的安装命令带了 --enable(如 README 中的完整形式),插件已处于启用状态,可跳过本节。否则执行:

hermes plugins enable ponytail

启用后需要重启 Hermes 或网关(restart)才能生效——钩子与命令注册发生在插件加载阶段,运行中的进程不会自动拾取新插件。

README 中给出的带 --enable 的一站式安装方式是:

hermes plugins install DietrichGebert/ponytail --enable

3. 共享网关下的安全配置:把 /ponytail 限制给可信用户

after-install.md 中有一条常被忽略但很关键的运维建议:

在共享网关中,用 Hermes 的斜杠命令访问控制(slash-command access controls)将 /ponytail 限制给可信用户;运行时模式是进程局部的(process-local)。

这句话包含两层含义,源码可以印证:

  1. 权限层:网关会把 /ponytail-* 命令改写为普通 agent 提示词再派发给后端。改写前会先调用网关的 _check_slash_access(source, command) 检查发起者是否有权限;被拒绝时改写函数直接返回 None,命令不进入 agent 执行流。见 init.py 中的 rewrite_gateway_command_slash_access_denied
  2. 状态层:运行时模式(当前是 lite/full/ultra/off)保存在插件模块的一个模块级变量 _current_mode 中,即"进程局部"。不同进程、不同会话之间不会共享这个值;进程重启后回到默认解析链。因此某个用户在 A 进程里 /ponytail ultra 不会改变 B 进程的行为——这既是隔离保障,也意味着"改模式"不是一个跨用户的全局操作。

4. 六个命令与六个技能一览

安装并启用后,Hermes 中获得六条斜杠命令(与 after-install.md 的命令列表一致):

命令 作用 对应技能文件
/ponytail [lite|full|ultra|off] 设置强度档位;不带参数时报告当前档位 模式命令,无对应 SKILL.md
/ponytail-review [target] 只针对 diff 做过度工程审查,逐条给出"可删除清单" skills/ponytail-review/SKILL.md
/ponytail-audit [target] 全仓库范围的过度工程审计,按可删收益排序 skills/ponytail-audit/SKILL.md
/ponytail-debt 把代码里的 ponytail: 简写标记收割成债务台账 skills/ponytail-debt/SKILL.md
/ponytail-gain 展示实测收益记分牌(更少代码、更低成本、更高速度) skills/ponytail-gain/SKILL.md
/ponytail-help 上述命令速查卡 skills/ponytail-help/SKILL.md

六个打包技能同时注册在 ponytail: 命名空间下:ponytail:ponytailponytail:ponytail-reviewponytail:ponytail-auditponytail:ponytail-debtponytail:ponytail-gainponytail:ponytail-help

各技能的实际行为(以下均引自各自 SKILL.md 的实现定义):

  • ponytail(主技能):注入"懒惰资深工程师"人格与七级梯子。三档强度语义:lite = 照做但用一行指出更懒的替代方案,由用户拍板;full(默认)= 强制走梯子,标准库与原生优先,最短 diff 与最短解释;ultra = YAGNI 极端派,删除先于新增,交付一行解的同时质疑其余需求。典型例子(加缓存):lite 会说"已加缓存;functools.lru_cache 一行也能覆盖";full 直接 @lru_cache(maxsize=1000);ultra 则回答"profiler 没说话就不加缓存"。同时明确"不懒惰"的边界:信任边界校验、防数据丢失的错误处理、安全与可访问性永远不能砍。
  • ponytail-review:只审 diff,每条发现一行,格式 L<行号>: <tag> <砍什么>. <用什么替代>.,标签共五种:delete:stdlib:native:yagni:shrink:;结尾必须给出 net: -<N> lines possible.,没有可删的则回答 Lean already. Ship.。它只列清单,不代改代码,且正确性/安全/性能问题明确不在其范围内。
  • ponytail-audit:ponytail-review 的仓库级版本,扫描整棵树而非 diff,按"能砍多少"排序输出,结尾为 net: -<N> lines, -<M> deps possible.
  • ponytail-debt:按 grep -rnE '(#|//) ?ponytail:' . 收割仓库中所有刻意留下的 ponytail: 简写注释(约定格式为 ponytail: <天花板>, <升级路径>),按文件分组生成台账行,并对没有写明升级触发条件的标记打上 no-trigger 风险标签;只读不写。
  • ponytail-gain:一次性展示已发布的 benchmark 中位数记分牌(5 个日常任务 × 3 个模型的离线测量),并有一条"诚实边界":绝不给当前仓库编造"你已省下 X 行"的数字,未写出来的代码没有可相减的基线;仓库级真实数字只有 /ponytail-debt 的计数台账。
  • ponytail-help:一次性速查卡,展示三档强度、六个技能、退出方式(说 "stop ponytail"/"normal mode" 或 /ponytail off),以及默认模式配置方式。它不改变模式、不写任何持久化文件。

5. 源码纵深:register(ctx) 如何把命令、钩子、技能接进 Hermes

init.py 根部的 register 函数是整个插件的装配点,共做三件事:

① 注册技能。 遍历 skills/ 下每个含 SKILL.md 的子目录并调用 ctx.register_skill(child.name, skill_md),于是六个技能都以 ponytail:<name> 形式可用:

for child in sorted(SKILLS_DIR.iterdir() if SKILLS_DIR.exists() else []):
    skill_md = child / "SKILL.md"
    if child.is_dir() and skill_md.exists():
        ctx.register_skill(child.name, skill_md)

② 注册两个钩子。

  • pre_llm_call:在每轮 LLM 调用前执行,读取当前模式(运行时模式 _current_mode 未设置时走默认解析链),调用 build_injected_context(mode) 生成规则文本注入上下文;off 时返回空上下文,等价于安静地不注入。
  • pre_gateway_dispatch:绑定 rewrite_gateway_command,负责把网关收到的 /ponytail-* 消息改写为指向对应技能的提示词。

③ 注册命令。 /ponytail 绑定 _handle_mode_command(带参设档、无参查档、非法参数回显 Usage: /ponytail [lite|full|ultra|off]);其余五个命令通过 _make_skill_command_handler 生成——点击/输入命令后,插件向 agent 队列注入一条形如 Load and follow the Hermes plugin skill ponytail:ponytail-review. Review the current diff ... 的提示词,把命令转化为技能调用。

5.1 默认模式解析链:运行时模式、环境变量、配置文件

源码中定义了两组模式集合,注意区分:

RUNTIME_MODES = {"off", "lite", "full", "ultra"}      # /ponytail 命令可设的
CONFIG_MODES  = RUNTIME_MODES | {"review"}            # 默认解析链可取的

_default_mode() 的优先级为:环境变量 PONYTAIL_DEFAULT_MODE → 配置文件 defaultMode → 兜底 full。配置文件位置遵循 XDG 约定:XDG_CONFIG_HOME 下为 $XDG_CONFIG_HOME/ponytail/config.json,Windows 为 %APPDATA%\ponytail\config.json,其余 Unix 为 ~/.config/ponytail/config.json。例如:

{ "defaultMode": "lite" }

配置为 "off" 可关闭会话自动注入,需要时再手动 /ponytail 打开。review 只能经配置/解析链出现,不是 /ponytail 命令的合法参数(传 maximum 之类的值会收到 Usage 提示)。

5.2 注入的上下文不是原文照搬

build_injected_context 有三个分支:

  1. off → 空字符串,什么都不注入;
  2. review → 读取 skills/ponytail-review/SKILL.md 的正文(去掉 YAML frontmatter),前面加上 PONYTAIL MODE ACTIVE — level: review 头;文件缺失时退回一句降级提示;
  3. 其余档位 → 读取主技能 skills/ponytail/SKILL.md,由 _filter_skill_body_for_mode模式过滤:删除正文中属于其他档位的表格行(如 | **Lite** | ...)和示例行(如 - full: ...),只保留与当前档位匹配的部分,即"注入的提示词量级随档位伸缩"。SKILL.md 也读不到时才使用内置的 _fallback_instructions 精简规则兜底。

这套行为的直接可观测效果:/ponytail 无参数时输出形如 Ponytail mode: ultra. Use /ponytail lite|full|ultra|off./ponytail ultra 输出 Ponytail mode set to ultra.,随后每轮 LLM 调用都带上 PONYTAIL MODE ACTIVE — level: ultra 开头的规则上下文。

5.3 网关命令改写:下划线兼容与访问控制

rewrite_gateway_command 处理网关消息时的完整逻辑:

  • 只处理以 / 开头的文本,取出首段命令名并把下划线统一为连字符(因此 /ponytail_audit repo/ponytail-audit repo 等价);
  • 命令不在六个技能命令白名单内(如 /status、普通聊天文本)则返回 None 不做任何事;
  • 通过 _slash_access_denied 调用网关的 _check_slash_access(source, command):返回非 None 即视为拒绝,改写放弃,命令不落地;
  • 通过检查后返回 {"action": "rewrite", "text": <skill prompt>},其中提示词模板为 Load and follow the Hermes plugin skill ponytail:<command>. <描述><用户参数>

6. 测试证据:这些行为如何被验证

tests/hermes-plugin.test.jsnode:test 驱动 Python 加载插件模块,对上一节每条结论都留有断言:

  • 清单一致性plugin.yaml 的版本、作者、命令、技能必须与 package.jsonskills/ 目录实际内容对齐,且声明 pre_llm_call / pre_gateway_dispatch 两个钩子;
  • 命名空间注册:调用 register(ctx) 后,六个技能全部以 ponytail: 前缀注册且路径以 /SKILL.md 结尾;
  • 模式注入build_injected_context('ultra') 的输出必须含 PONYTAIL MODE ACTIVE — level: ultra 且不泄漏其他档位的表格行;off 输出为空;
  • 默认解析链:在临时 XDG_CONFIG_HOME 写入 {"defaultMode": "lite"} 并设 PONYTAIL_DEFAULT_MODE=ultra 时,环境变量胜出(level: ultra);无参 /ponytail 输出状态、非法参数输出 Usage:、再次查询保持 ultra
  • 网关改写/ponytail-review x/ponytail_audit repo/ponytail-debt/ponytail-help 全部被保留,/status 与普通文本返回 null_check_slash_access 返回 'denied' 时改写结果为 null——这正是第 3 节"把 /ponytail 限制给可信用户"的代码级依据。

7. 安装后自检清单

after-install.md 的完整流程收尾:

  1. 确认启用:hermes plugins enable ponytail(未随 --enable 安装时),随后重启 Hermes 或网关;
  2. 共享网关场景:先在 Hermes 侧配置斜杠命令访问控制,把 /ponytail 等命令限定给可信用户;
  3. 会话内验证:输入 /ponytail(不带参数)应看到 Ponytail mode: full. 之类的状态行(full 是默认档);
  4. 试一条技能命令:/ponytail-help 应回显速查卡;/ponytail-review 会按 L<行号>: <tag> ... 格式对当前 diff 给出删除清单;
  5. 需要固定默认档位时,用环境变量 PONYTAIL_DEFAULT_MODE 或配置文件 ~/.config/ponytail/config.jsondefaultMode 字段(环境变量优先级更高),无需任何强制配置项。

至此,Hermes 侧的 Ponytail 安装即告完成:六个命令、六个技能、两个钩子全部就绪,而"最懒的资深工程师"默认以 full 档在每个 LLM 轮次前就位。

登录后查看全文
热门项目推荐
相关项目推荐