Skip to content

[Feature] Approval system: customizable smart prompt context (quick win) + pluggable hook handler (long-term) #16475

Description

@Emidomenge

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havecomp/agentCore agent runtime: loop, agent_init, prompt builder, context-compression, responses endpointtype/featureNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions