Skip to content

fix(tui): register shell hooks in TUI path for parity with CLI and gateway - #48770

Open
handpape wants to merge 1 commit into
NousResearch:mainfrom
handpape:fix/tui-shell-hook-registration
Open

fix(tui): register shell hooks in TUI path for parity with CLI and gateway#48770
handpape wants to merge 1 commit into
NousResearch:mainfrom
handpape:fix/tui-shell-hook-registration

Conversation

@handpape

Copy link
Copy Markdown

Problem

Shell hooks configured in the hooks: block of config.yaml (e.g. post_llm_call) are silently ignored when running via the TUI. They work correctly in the CLI and gateway paths.

Root cause

The TUI's agent factory (_make_agent in tui_gateway/server.py) never calls register_from_config(). The other two entry points do:

Entry point Calls register_from_config Location
CLI cli.py:953
Gateway gateway/run.py:5124
TUI

Without this call, shell hook callbacks are never wired into the plugin manager, so invoke_hook("post_llm_call", ...) in agent/turn_finalizer.py finds zero callbacks and the hook script never runs.

Fix

Add register_from_config(load_config(), accept_hooks=False) to _make_agent() in tui_gateway/server.py, matching the exact pattern used by the CLI and gateway. The call is:

  • Idempotent — guarded by the _registered set in shell_hooks.py, so repeated calls on multiple agent creations are no-ops.
  • Failure-safe — wrapped in try/except so a broken hook never crashes agent init.
  • Consistent — uses the same accept_hooks=False argument, letting _resolve_effective_accept pick up hooks_auto_accept: true / HERMES_ACCEPT_HOOKS env var.

Verification

# Before fix: TUI process
>>> from hermes_cli.plugins import get_plugin_manager
>>> get_plugin_manager().has_hook("post_llm_call")
False

# After fix: TUI process
>>> get_plugin_manager().has_hook("post_llm_call")
True
>>> get_plugin_manager()._hooks.get("post_llm_call")
[shell_hook[post_llm_call:~/.hermes/agent-hooks/notify-complete.sh]]

hermes hooks doctor and hermes hooks test post_llm_call both pass. The hook script fires correctly on TUI agent responses after restart.

…teway

The TUI (_make_agent in tui_gateway/server.py) never called
register_from_config(), so declarative shell hooks (hooks: block in
config.yaml) were silently ignored when running via the TUI.  This
caused hooks like post_llm_call to never fire, even though they work
correctly in the CLI (cli.py:953) and gateway (gateway/run.py:5124)
paths.

This adds the same register_from_config(load_config(), accept_hooks=False)
call to _make_agent(), matching the pattern used by the other two entry
points.  The call is idempotent (guarded by _registered set) and
failure-safe (wrapped in try/except), so it is safe to run on every
agent creation.
@alt-glitch alt-glitch added type/bug Something isn't working comp/tui Terminal UI (ui-tui/ + tui_gateway/) comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists labels Jun 19, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

Clean fix registering shell hooks in the TUI execution path for parity with CLI and gateway. Small change (10 additions, 1 file) that improves consistency. No concerns.


Reviewed by Hermes Agent

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for identifying a real TUI-process parity gap. Current main still builds TUI agents in tui_gateway/server.py:4488-4650 without shell-hook registration, while successful turns dispatch post_llm_call in agent/turn_finalizer.py:393-403.

Problems

  • Please add a regression test in tests/test_tui_gateway_server.py near the existing _make_agent() tests at :7517. The PR changes a process-startup integration path and currently has no coverage asserting register_from_config(load_config(), accept_hooks=False).
  • The new bare except Exception: pass drops diagnostics. The matching gateway path logs failures at gateway/run.py:6971-6975; retain that failure-safe behavior but add a debug log with exc_info=True.

Suggested changes

  • Mock agent.shell_hooks.register_from_config and hermes_cli.config.load_config, call _make_agent(), and assert the exact registration arguments.
  • Use the gateway's debug-log pattern for registration failures.

Automated hermes-sweeper review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants