Skip to content

feat(plugins): add OpenClaw-style hook lifecycle execution with compatibility aliases#9070

Closed
bugmaker2 wants to merge 2 commits into
NousResearch:mainfrom
bugmaker2:feat/issue-52-plugin-hooks-design
Closed

feat(plugins): add OpenClaw-style hook lifecycle execution with compatibility aliases#9070
bugmaker2 wants to merge 2 commits into
NousResearch:mainfrom
bugmaker2:feat/issue-52-plugin-hooks-design

Conversation

@bugmaker2

@bugmaker2 bugmaker2 commented Apr 13, 2026

Copy link
Copy Markdown

What does this PR do?

This PR upgrades Hermes plugin hook orchestration to support canonical lifecycle hook names and explicit execution semantics (modifying, claiming, and observe patterns), while preserving backward compatibility for existing plugins.

It solves two core problems:

  1. Hook behavior was previously implicit and mostly fire-and-forget, making advanced extension scenarios (blocking/modifying tool calls, reply interception, render-time status customization) harder to implement safely.
  2. Legacy hook names were widely used by existing plugins, so introducing clearer naming needed a compatibility bridge.

This approach keeps old plugins working via alias mapping, while introducing a more structured hook runner model aligned with OpenClaw-style lifecycle phases.

Related Issue

#8642
#8643
#4169

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • Added canonical plugin hook names with compatibility aliases in hermes_cli/plugins.py:
    • pre_tool_call -> before_tool_call
    • post_tool_call -> after_tool_call
    • pre_llm_call -> before_agent_start
  • Added hook registration metadata with priority support (HookRegistration) in hermes_cli/plugins.py.
  • Added three execution paths in hermes_cli/plugins.py:
    • invoke_hook_modifying(...) for sequential state mutation
    • invoke_hook_claiming(...) for first-handled short-circuit
    • invoke_hook_observe(...) for fire-and-forget observers
  • Wired before_tool_call / after_tool_call into tool dispatch in model_tools.py:
    • supports argument mutation and optional blocking before dispatch
    • emits tool duration metadata after execution
  • Wired before_agent_start, before_agent_reply, and on_context_window_update into agent lifecycle in run_agent.py.
  • Wired on_status_bar_render into status text generation in cli.py so plugins can override rendered footer text.
  • Updated hook reference docs in website/docs/user-guide/features/hooks.md.
  • Added/updated tests:
    • tests/hermes_cli/test_plugins.py
    • tests/test_model_tools.py
    • tests/cli/test_cli_status_bar.py

Compatibility Notes

This PR is intentionally backward compatible:

  • Existing plugins using legacy names (pre_tool_call, post_tool_call, pre_llm_call) continue to work unchanged via alias mapping.
  • Legacy invoke_hook(...) remains available.
  • New canonical names and execution paths are additive, enabling gradual plugin migration without breakage.

How to Test

  1. Run targeted tests:
    • uv run python -m pytest tests/hermes_cli/test_plugins.py tests/test_model_tools.py tests/cli/test_cli_status_bar.py -q
  2. Verify compatibility:
    • register a plugin hook with legacy names (e.g. pre_tool_call) and confirm it still executes.
  3. Verify new behavior:
    • use before_tool_call to mutate/block args,
    • use before_agent_reply to short-circuit reply,
    • use on_status_bar_render to rewrite status bar text.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15.x

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

Targeted test run:

  • 62 passed for:
    • tests/hermes_cli/test_plugins.py
    • tests/test_model_tools.py
    • tests/cli/test_cli_status_bar.py

Introduce canonical plugin hook names with alias compatibility and add modifying/claiming/observe execution paths. Wire new hook phases into tool dispatch, agent lifecycle, and status bar rendering with tests and docs updates.

Made-with: Cursor
@bugmaker2 bugmaker2 changed the title feat(plugins): add OpenClaw-style hook lifecycle execution feat(plugins): add OpenClaw-style hook lifecycle execution with compatibility aliases Apr 13, 2026
@teknium1

Copy link
Copy Markdown
Contributor

The tool-call blocking portion of this PR was merged via #9377 (salvaged from #5385/#4610). The hook renaming, execution patterns (modifying/claiming/observe), model/provider override, and system prompt mutation were not included — the renaming adds backward-compat overhead without clear benefit, and the model/provider override bypasses the resolution chain in ways that would break caching and provider-specific code paths. Individual hooks (on_context_window_update, on_status_bar_render, before_agent_reply) can be added incrementally when concrete consumer plugins exist. Thanks for the comprehensive work!

@teknium1 teknium1 closed this Apr 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants