debugging-hermes-tui-commands

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Debugging Hermes TUI Slash Commands

调试Hermes TUI斜杠命令

Overview

概述

Hermes slash commands span three layers — Python command registry, tui_gateway JSON-RPC bridge, and the Ink/TypeScript frontend. When a command misbehaves (missing from autocomplete, works in CLI but not TUI, config persists but UI doesn't update), the bug is almost always one layer being out of sync with another.
Use this skill when you encounter issues with slash commands in the Hermes TUI, particularly when commands aren't showing in autocomplete, aren't working properly in the TUI, or need to be added/updated.
Hermes斜杠命令涵盖三层——Python命令注册表、tui_gateway JSON-RPC桥接层和Ink/TypeScript前端。当命令出现异常(自动补全中缺失、在CLI中可用但在TUI中不可用、配置已持久化但UI未更新)时,问题几乎总是源于某一层与其他层不同步。
当你在Hermes TUI中遇到斜杠命令相关问题时,尤其是命令未显示在自动补全中、在TUI中无法正常工作,或者需要添加/更新命令时,可以使用本技能。

When to Use

使用场景

  • A slash command exists in one part of the codebase but doesn't work fully
  • A command needs to be added to both backend and frontend
  • Command autocomplete isn't working for specific commands
  • Command behavior is inconsistent between CLI and TUI
  • A command persists config but doesn't apply live in the TUI
  • 斜杠命令在代码库的某一部分存在,但无法完全正常工作
  • 需要同时在后端和前端添加命令
  • 特定命令的自动补全功能失效
  • CLI与TUI中的命令行为不一致
  • 命令已持久化配置,但未在TUI中实时生效

Architecture Overview

架构概述

Python backend (hermes_cli/commands.py)     <- canonical COMMAND_REGISTRY
TUI gateway (tui_gateway/server.py)         <- slash.exec / command.dispatch
TUI frontend (ui-tui/src/app/slash/)        <- local handlers + fallthrough
Command definitions must be registered consistently across Python and TypeScript to work properly. The Python
COMMAND_REGISTRY
is the source of truth for: CLI dispatch, gateway help, Telegram BotCommand menu, Slack subcommand map, and autocomplete data shipped to Ink.
Python backend (hermes_cli/commands.py)     <- canonical COMMAND_REGISTRY
TUI gateway (tui_gateway/server.py)         <- slash.exec / command.dispatch
TUI frontend (ui-tui/src/app/slash/)        <- local handlers + fallthrough
命令定义必须在Python和TypeScript中一致注册才能正常工作。Python的
COMMAND_REGISTRY
是以下内容的事实来源:CLI调度、网关帮助、Telegram BotCommand菜单、Slack子命令映射,以及发送给Ink的自动补全数据。

Investigation Steps

排查步骤

  1. Check if the command exists in the TUI frontend:
    bash
    search_files --pattern "/commandname" --file_glob "*.ts" --path ui-tui/
    search_files --pattern "/commandname" --file_glob "*.tsx" --path ui-tui/
  2. Examine the TUI command definition:
    bash
    read_file ui-tui/src/app/slash/commands/core.ts
    # If not there:
    search_files --pattern "commandname" --path ui-tui/src/app/slash/commands --target files
  3. Check if the command exists in the Python backend:
    bash
    search_files --pattern "CommandDef" --file_glob "*.py" --path hermes_cli/
    search_files --pattern "commandname" --path hermes_cli/commands.py --context 3
  4. Examine the gateway implementation:
    bash
    search_files --pattern "complete.slash|slash.exec" --path tui_gateway/
  1. 检查命令是否存在于TUI前端:
    bash
    search_files --pattern "/commandname" --file_glob "*.ts" --path ui-tui/
    search_files --pattern "/commandname" --file_glob "*.tsx" --path ui-tui/
  2. 查看TUI命令定义:
    bash
    read_file ui-tui/src/app/slash/commands/core.ts
    # 如果不存在:
    search_files --pattern "commandname" --path ui-tui/src/app/slash/commands --target files
  3. 检查命令是否存在于Python后端:
    bash
    search_files --pattern "CommandDef" --file_glob "*.py" --path hermes_cli/
    search_files --pattern "commandname" --path hermes_cli/commands.py --context 3
  4. 查看网关实现:
    bash
    search_files --pattern "complete.slash|slash.exec" --path tui_gateway/

Fix: Missing Command Autocomplete

修复:缺失命令自动补全

If a command exists in the TUI but doesn't show in autocomplete:
  1. Add a
    CommandDef
    entry to
    COMMAND_REGISTRY
    in
    hermes_cli/commands.py
    :
    python
    CommandDef("commandname", "Description of the command", "Session",
               cli_only=True, aliases=("alias",),
               args_hint="[arg1|arg2|arg3]",
               subcommands=("arg1", "arg2", "arg3")),
  2. Pick
    cli_only
    vs gateway availability carefully:
    • cli_only=True
      — only in the interactive CLI/TUI
    • gateway_only=True
      — only in messaging platforms
    • neither — available everywhere
    • gateway_config_gate="display.foo"
      — config-gated availability in the gateway
  3. Ensure
    subcommands
    matches the expected tab-completion options shown by the TUI.
  4. If the command runs server-side, add a handler in
    HermesCLI.process_command()
    in
    cli.py
    :
    python
    elif canonical == "commandname":
        self._handle_commandname(cmd_original)
  5. For gateway-available commands, add a handler in
    gateway/run.py
    :
    python
    if canonical == "commandname":
        return await self._handle_commandname(event)
如果命令存在于TUI中但未显示在自动补全中:
  1. hermes_cli/commands.py
    COMMAND_REGISTRY
    中添加
    CommandDef
    条目:
    python
    CommandDef("commandname", "Description of the command", "Session",
               cli_only=True, aliases=("alias",),
               args_hint="[arg1|arg2|arg3]",
               subcommands=("arg1", "arg2", "arg3")),
  2. 谨慎选择
    cli_only
    与网关可用性:
    • cli_only=True
      — 仅在交互式CLI/TUI中可用
    • gateway_only=True
      — 仅在消息平台中可用
    • 两者都不设置 — 所有场景都可用
    • gateway_config_gate="display.foo"
      — 在网关中受配置控制的可用性
  3. 确保
    subcommands
    与TUI显示的预期制表符补全选项一致。
  4. 如果命令在服务器端运行,在
    cli.py
    HermesCLI.process_command()
    中添加处理程序:
    python
    elif canonical == "commandname":
        self._handle_commandname(cmd_original)
  5. 对于网关可用的命令,在
    gateway/run.py
    中添加处理程序:
    python
    if canonical == "commandname":
        return await self._handle_commandname(event)

Common Issues

常见问题

  1. Command shows in TUI but not in autocomplete. The command is defined in the TUI codebase but missing from
    COMMAND_REGISTRY
    in
    hermes_cli/commands.py
    . Autocomplete data ships from Python.
  2. Command shows in autocomplete but doesn't work. Check the command handler in
    tui_gateway/server.py
    and the frontend handler in
    ui-tui/src/app/createSlashHandler.ts
    . If the command is local-only in Ink, it must be handled in
    app.tsx
    built-in branch; otherwise it falls through to
    slash.exec
    and must have a Python handler.
  3. Command behavior differs between CLI and TUI. The command might have different implementations. Check both
    cli.py::process_command
    and the TUI's local handler. Local TUI handlers take precedence over gateway dispatch.
  4. Command persists config but doesn't apply live. For TUI-local commands, updating
    config.set
    is not enough. Also patch the relevant nanostore state immediately (usually
    patchUiState(...)
    ) and pass any new state through rendering components. Example:
    /details collapsed
    must update live detail visibility, not just save
    details_mode
    ; in-session global
    /details <mode>
    may need a separate command-override flag so live commands can override built-in section defaults while startup/config sync preserves default-expanded thinking/tools behavior.
  5. Gateway dispatch silently ignores the command. The gateway only dispatches commands it knows about. Check
    GATEWAY_KNOWN_COMMANDS
    (derived from
    COMMAND_REGISTRY
    automatically) includes the canonical name. If the command is
    cli_only
    with a
    gateway_config_gate
    , verify the gated config value is truthy.
  1. 命令显示在TUI中但未出现在自动补全中。 命令在TUI代码库中定义,但
    hermes_cli/commands.py
    COMMAND_REGISTRY
    中缺失。自动补全数据由Python端提供。
  2. 命令显示在自动补全中但无法工作。 检查
    tui_gateway/server.py
    中的命令处理程序和
    ui-tui/src/app/createSlashHandler.ts
    中的前端处理程序。如果命令是Ink本地命令,必须在
    app.tsx
    的内置分支中处理;否则会 fallback 到
    slash.exec
    ,且必须有Python处理程序。
  3. CLI与TUI中的命令行为不一致。 命令可能有不同的实现。检查
    cli.py::process_command
    和TUI的本地处理程序。TUI本地处理程序优先级高于网关调度。
  4. 命令已持久化配置但未实时生效。 对于TUI本地命令,仅更新
    config.set
    是不够的。还需立即修补相关的nanostore状态(通常是
    patchUiState(...)
    ),并将任何新状态传递给渲染组件。示例:
    /details collapsed
    必须实时更新详情可见性,而不仅仅是保存
    details_mode
    ;会话全局的
    /details <mode>
    可能需要单独的命令覆盖标志,以便实时命令可以覆盖内置的默认展开思考/工具行为,同时启动/配置同步保留默认行为。
  5. 网关调度静默忽略命令。 网关仅调度其已知的命令。检查
    GATEWAY_KNOWN_COMMANDS
    (自动从
    COMMAND_REGISTRY
    派生)是否包含规范名称。如果命令是带有
    gateway_config_gate
    cli_only
    命令,请验证受控制的配置值为真。

Debugging Tactics

调试策略

When surface-level inspection doesn't reveal the bug:
  • Python side hangs or misbehaves: use the
    python-debugpy
    skill to break inside
    _SlashWorker.exec
    or the command handler.
    remote-pdb
    set at the handler entry is the fastest path.
  • Ink side not reacting: use the
    node-inspect-debugger
    skill to break in
    app.tsx
    's slash dispatch or the local command branch.
    sb('dist/app.js', <line>)
    after
    npm run build
    .
  • Registry mismatch / unclear which side is wrong: compare the canonical
    COMMAND_REGISTRY
    entry against the TUI's local command list side-by-side.
当表面检查无法发现问题时:
  • Python端挂起或行为异常: 使用
    python-debugpy
    技能在
    _SlashWorker.exec
    或命令处理程序内部断点调试。在处理程序入口设置
    remote-pdb
    是最快的方式。
  • Ink端无响应: 使用
    node-inspect-debugger
    技能在
    app.tsx
    的斜杠调度或本地命令分支中断点调试。执行
    npm run build
    后使用
    sb('dist/app.js', <line>)
  • 注册表不匹配/不清楚哪一侧出错: 将规范的
    COMMAND_REGISTRY
    条目与TUI的本地命令列表逐一对比。

Pitfalls

注意事项

  • Don't forget to set the appropriate category for the command in
    CommandDef
    (e.g., "Session", "Configuration", "Tools & Skills", "Info", "Exit")
  • Make sure any aliases are properly registered in the
    aliases
    tuple — no other file changes are needed, everything downstream (Telegram menu, Slack mapping, autocomplete, help) derives from it
  • For commands with subcommands, ensure the
    subcommands
    tuple in
    CommandDef
    matches what's in the TUI code
  • cli_only=True
    commands won't work in gateway/messaging platforms — unless you add a
    gateway_config_gate
    and the gate is truthy
  • After adding live UI state, search every consumer of the old prop/helper and thread the new state through all render paths, not just the active streaming path. TUI detail rendering has at least two important paths: live
    StreamingAssistant
    /
    ToolTrail
    and transcript/pending
    MessageLine
    rows. A
    /clean
    pass should explicitly check both.
  • Rebuild the TUI (
    npm --prefix ui-tui run build
    ) before testing — tsx watch mode may lag on first launch
  • 不要忘记在
    CommandDef
    中为命令设置适当的类别(例如“Session”、“Configuration”、“Tools & Skills”、“Info”、“Exit”)
  • 确保所有别名都正确注册在
    aliases
    元组中——无需修改其他文件,所有下游内容(Telegram菜单、Slack映射、自动补全、帮助)都从中派生
  • 对于带有子命令的命令,确保
    CommandDef
    中的
    subcommands
    元组与TUI代码中的内容一致
  • cli_only=True
    的命令在网关/消息平台中无法工作——除非添加
    gateway_config_gate
    且该控制值为真
  • 添加实时UI状态后,搜索旧属性/助手的所有使用者,并将新状态传递到所有渲染路径,而不仅仅是活动流路径。TUI详情渲染至少有两个重要路径:实时
    StreamingAssistant
    /
    ToolTrail
    和 transcript/pending
    MessageLine
    行。
    /clean
    操作应明确检查这两个路径。
  • 测试前重新构建TUI(
    npm --prefix ui-tui run build
    )——tsx监听模式在首次启动时可能会延迟

Verification

验证

After fixing:
  1. Rebuild the TUI:
    bash
    cd /home/bb/hermes-agent && npm --prefix ui-tui run build
  2. Run the TUI and test the command:
    bash
    hermes --tui
  3. Type
    /
    and verify the command appears in autocomplete suggestions with the expected description and args hint.
  4. Execute the command and confirm:
    • Expected behavior fires
    • Any persisted config updates correctly (
      read_file ~/.hermes/config.yaml
      )
    • Live UI state reflects the change immediately (not just after restart)
  5. If the command is also gateway-available, test it from at least one messaging platform (or run the gateway tests:
    scripts/run_tests.sh tests/gateway/
    ).
修复后:
  1. 重新构建TUI:
    bash
    cd /home/bb/hermes-agent && npm --prefix ui-tui run build
  2. 运行TUI并测试命令:
    bash
    hermes --tui
  3. 输入
    /
    并验证命令出现在自动补全建议中,且带有预期的描述和参数提示。
  4. 执行命令并确认:
    • 触发预期行为
    • 所有持久化配置正确更新(
      read_file ~/.hermes/config.yaml
    • 实时UI状态立即反映更改(无需重启)
  5. 如果命令也支持网关,从至少一个消息平台测试它(或运行网关测试:
    scripts/run_tests.sh tests/gateway/
    )。