hermes - ✅(Solved) Fix [Feature] Approval system: customizable smart prompt context (quick win) + pluggable hook handler (long-term) [1 pull requests, 2 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#16475Fetched 2026-04-28 06:53:06
View on GitHub
Comments
2
Participants
1
Timeline
8
Reactions
0
Participants
Timeline (top)
labeled ×3commented ×2cross-referenced ×1renamed ×1

The current approval system supports three fixed modes (manual, smart, off). This feature request is for a fourth extensibility point: a custom approval hook — a user-defined script or command that Hermes calls to make the approve/deny decision, similar to how Claude Code's PreToolUse hooks work.

Root Cause

The current approval system supports three fixed modes (manual, smart, off). This feature request is for a fourth extensibility point: a custom approval hook — a user-defined script or command that Hermes calls to make the approve/deny decision, similar to how Claude Code's PreToolUse hooks work.

Fix Action

Fixed

PR fix notes

PR #16483: feat(approvals): add approvals.context for customizable smart-approval prompts

Description (problem / solution / changelog)

Summary

Implements the quick win suggested in #16475: an optional approvals.context config key that lets users customize the smart-approval prompt with agent-specific guidance.

Problem

The current smart approval mode uses a hardcoded, generic prompt in _smart_approve(). Specialized agents (e.g. a Home Assistant admin bot) routinely run commands that match dangerous patterns but are completely safe in context — curl to local IPs, python -c env introspection, etc. This causes constant false positives and approval fatigue.

Solution

Add an approvals.context string field that gets appended to the auxiliary LLM's assessment prompt when mode: smart is active.

Example config

approvals:
  mode: smart
  context: |
    This agent manages a Home Assistant instance. The following are always safe in this context:
    - curl requests to homeassistant.local or local LAN addresses (192.168.x.x)
    - python -c commands that read environment variables
    - SSH commands to [email protected]

Changes

  • tools/approval.py — add _get_approval_context() helper; inject context into _smart_approve() prompt when present
  • hermes_cli/config.py — add "context": None to default approvals block; bump _config_version to 19
  • tests/tools/test_approval.py — add tests for context reading, empty/whitespace handling, and prompt injection
  • website/docs/user-guide/security.md — document approvals.context
  • website/docs/user-guide/configuration.md — document approvals.context

Why not the full pluggable hook?

The full custom hook handler from the original issue is a larger architectural change (new approval mode, subprocess execution, JSON protocol, gateway notification hooks). This PR ships the immediate value — customizable smart prompts — with a ~10-line code change, while leaving the door open for the hook system later.

Closes #16475 (quick win)

Changed files

  • hermes_cli/config.py (modified, +4/-1)
  • tests/tools/test_approval.py (modified, +61/-1)
  • tools/approval.py (modified, +19/-1)
  • website/docs/user-guide/configuration.md (modified, +18/-0)
  • website/docs/user-guide/security.md (modified, +16/-0)

Code Example

{ "decision": "deny", "reason": "Curl over plain HTTP to an internal host is not allowed in this context." }

---

approvals:
  mode: custom
  hook: "/opt/data/scripts/approval_hook.py"
  timeout: 30
  on_deny_notify_gateway: true    # post denial reason to the active platform channel
  on_approve_notify_gateway: false  # optionally post approval confirmation too (default: false)

---

{
  "tool": "terminal",
  "command": "python3 -c \"import os; print(os.environ['HA_TOKEN'])\"",
  "reason": "script execution via -c flag",
  "session_id": "abc123",
  "platform": "discord",
  "user_id": "364815244633178123"
}

---

{ "decision": "approve" }
{ "decision": "approve", "reason": "Safe read-only env introspection, no exfiltration risk." }
{ "decision": "deny", "reason": "Printing the HA token to the terminal is not safe in this context." }
{ "decision": "escalate", "reason": "Uncertain — routing to human." }
RAW_BUFFERClick to expand / collapse

Summary

The current approval system supports three fixed modes (manual, smart, off). This feature request is for a fourth extensibility point: a custom approval hook — a user-defined script or command that Hermes calls to make the approve/deny decision, similar to how Claude Code's PreToolUse hooks work.

How Claude Code does it

In Claude Code, you can configure a shell command as a PreToolUse hook in settings.json. Before any tool runs, Claude Code calls that command with tool details on stdin and reads a JSON decision from stdout:

{ "decision": "deny", "reason": "Curl over plain HTTP to an internal host is not allowed in this context." }

The hook can be anything — a Python script, a local LLM call, a webhook to an external service. This makes the approval system fully extensible without forking the agent.

Requested behavior for Hermes

Add a custom approval mode (or a hook field alongside smart) that lets users define a command to call:

approvals:
  mode: custom
  hook: "/opt/data/scripts/approval_hook.py"
  timeout: 30
  on_deny_notify_gateway: true    # post denial reason to the active platform channel
  on_approve_notify_gateway: false  # optionally post approval confirmation too (default: false)

When a dangerous command is detected, Hermes calls the hook with a JSON payload on stdin:

{
  "tool": "terminal",
  "command": "python3 -c \"import os; print(os.environ['HA_TOKEN'])\"",
  "reason": "script execution via -c flag",
  "session_id": "abc123",
  "platform": "discord",
  "user_id": "364815244633178123"
}

The hook returns a decision on stdout:

{ "decision": "approve" }
{ "decision": "approve", "reason": "Safe read-only env introspection, no exfiltration risk." }
{ "decision": "deny", "reason": "Printing the HA token to the terminal is not safe in this context." }
{ "decision": "escalate", "reason": "Uncertain — routing to human." }
  • approve → execute; if on_approve_notify_gateway: true and a reason is present, post it to the active platform channel (useful for audit trails)
  • deny → block; if on_deny_notify_gateway: true, post the reason to the active platform channel with optional human override prompt
  • escalate → fall back to the existing manual gateway prompt

Why this matters / use case

Running a Home Assistant admin agent on Discord. The built-in smart mode works well for obvious cases, but:

  1. The smart LLM's judgement is a closed box — no visibility, no tuning
  2. Different agents have very different risk profiles. An HA agent legitimately runs curl to local IPs and python -c env introspections constantly. A finance bot should never touch network calls. A fixed global policy can't capture this.
  3. With a pluggable hook, you can use a fast/cheap LLM with a custom system prompt tailored to the agent's context, make it context-aware, and have it post a clear approval or denial message to the Discord channel for full visibility into what the agent is doing and why

A simple hook script using any LLM API could be a 50-line Python file that gives far better context-aware decisions than a generic smart mode — and doubles as an audit log.

Prior art

  • Claude Code PreToolUse hooks: shell command called with tool details on stdin, returns JSON decision
  • Standard Unix philosophy: the agent provides the interface, the user provides the logic

extent analysis

TL;DR

To implement a custom approval hook in Hermes, add a custom approval mode that allows users to define a command to call with a JSON payload on stdin and returns a decision on stdout.

Guidance

  • Introduce a new custom approval mode in the Hermes configuration, allowing users to specify a command to call for approval decisions.
  • Define the JSON payload structure for the hook, including tool details and session information, to be passed on stdin.
  • Specify the expected JSON decision format on stdout, including approve, deny, and escalate options with optional reasons.
  • Implement logic to handle the hook's decision, including execution, blocking, or escalation, and notification to the active platform channel as configured.

Example

approvals:
  mode: custom
  hook: "/opt/data/scripts/approval_hook.py"
  timeout: 30
  on_deny_notify_gateway: true

Notes

The implementation should consider the security implications of executing user-defined commands and ensure proper input validation and error handling.

Recommendation

Apply workaround by implementing the custom approval hook as described, allowing for flexible and context-aware approval decisions. This approach provides a more tailored solution than the existing smart mode and enables better visibility into agent actions.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix [Feature] Approval system: customizable smart prompt context (quick win) + pluggable hook handler (long-term) [1 pull requests, 2 comments, 1 participants]