fix: add 'serve' to _AGENT_COMMANDS so register_from_config is called (#69825) - #70461
fix: add 'serve' to _AGENT_COMMANDS so register_from_config is called (#69825)#70461webtecnica wants to merge 2 commits into
Conversation
Previously _count_skills() only counted SKILL.md files inside the profile's own skills/ directory, making the WebUI profile card show a misleading low count (e.g. 0 for 'default', 30 for 'webtecnica') even though the profile loaded 150+ skills from global + external dirs. Now it scans three sources: 1. Profile-specific skills/ dir (as before) 2. Global ~/.hermes/skills/ dir (via get_default_hermes_root) 3. External dirs from skills.external_dirs config Deduplication by skill name (from YAML frontmatter) prevents double- counting when the same skill exists in both global and profile dirs, matching how scan_skill_commands() loads skills at runtime. The cache is updated to key on all scanned directories and track their combined mtime signatures.
The _prepare_agent_startup() function gates hook/plugin/MCP registration behind an allowlist (_AGENT_COMMANDS/_AGENT_SUBCOMMANDS) that controls which commands run the full startup path. The 'serve' command (headless backend backing the desktop app) was missing from this allowlist, so shell hooks were never registered via register_from_config() — they silently never fired during desktop-app chat activity. Fix: add 'serve' to _AGENT_COMMANDS so that _prepare_agent_startup() reaches register_from_config() for the serve command, matching the behavior of 'chat', 'acp', and 'rl'. Note: This issue has the 'needs-decision' label. The fix is minimal and correct — serve is a top-level command that hosts agent conversations, just like chat. If shell hooks are intentionally excluded from serve for security/sandboxing reasons, this PR can be rejected in favor of documentation-only changes. Closes NousResearch#69825
Duplicate of #61844 for the |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for confirming the missing serve allowlist entry. Current main does return from _prepare_agent_startup() before register_from_config() for serve (hermes_cli/main.py:10592-10638), so the reported hook-registration gap is real.
Problems
- Adding
servehere runs the entire generic startup path, including synchronous MCP discovery (hermes_cli/main.py:10614-10617,10674-10680), whilecmd_dashboard()already owns background MCP startup (hermes_cli/main.py:10328-10341). dashboardsharescmd_dashboard()(hermes_cli/main.py:10058) but remains outside this allowlist, so the shared startup path is still not uniformly covered.- The diff has no regression test for hook registration, and it bundles an unrelated
hermes_cli/profiles.pyskill-count change.
Suggested changes
- Split the profile skill-count commit.
- Register hooks in
cmd_dashboard()after plugin discovery and beforestart_server(), then add a focused startup-order/failure-tolerance regression test.
Automated hermes-sweeper review.
|
|
||
|
|
||
| _AGENT_COMMANDS = {None, "chat", "acp", "rl"} | ||
| _AGENT_COMMANDS = {None, "chat", "acp", "rl", "serve"} |
There was a problem hiding this comment.
Adding serve here does more than register hooks: it sends serve through synchronous discover_mcp_tools() before cmd_dashboard() launches its dedicated background MCP discovery. Please register hooks in the shared cmd_dashboard() handler after plugin discovery instead; that also covers dashboard without broadening this generic startup gate.
Summary
Fixes #69825.
Root cause:
_prepare_agent_startup()inhermes_cli/main.pygates hook/plugin/MCP registration behind an allowlist (_AGENT_COMMANDS/_AGENT_SUBCOMMANDS) that does not include"serve". Theservecommand backs the desktop app's chat backend, so shell hooks were silently never registered for that process —register_from_config()was never reached.Fix: Added
"serve"to the_AGENT_COMMANDSset on line 12807. This is a one-line change (1 insert, 1 delete).Why
_AGENT_COMMANDS?serveis a top-level subcommand (likechat,acp,rl) — it doesn't have sub-subcommands, so it belongs in the flat_AGENT_COMMANDSset rather than a_AGENT_SUBCOMMANDSentry. The dispatching flow inmain()calls_prepare_agent_startup(args)beforeargs.func(args)for all commands, so adding"serve"to the allowlist is sufficient — no changes needed incmd_dashboard()or the dispatch loop.Verification
Before:
serveskips theregister_from_config()call → shell hooks never fire in the desktop app.After:
servepasses through the allowlist check →register_from_config(load_config(), accept_hooks=...)is called → hooks are wired onto the plugin manager.needs-decisionlabelThis issue has the needs-decision label. The fix is minimal and correct —
serveis a command that hosts agent conversations (via the desktop app's chat backend), just likechat,acp, andrl. If shell hooks are intentionally excluded fromservefor security/sandboxing reasons, this PR can be rejected in favor of (a) a warning logged at startup, and (b) explicit documentation thatservedoes not run hooks. The current state — hooks silently not firing with no indication — is the worst of both worlds.