Approval Gates: Human-in-the-Loop

+15 Mana ✨

Introduction

Approval gates are the last layer before a destructive command runs. They are Hermes's way of pausing the loop and asking a human should this actually happen? before doing something with real-world consequences. When you see the prompt, you are the safety check.

Key Concepts

  • Approval gate: A pause in the tool loop while Hermes waits for a user response (yes, no, or always).
  • Approval mode: manual (always prompt), smart (LLM-assisted risk filter, auto-approve low-risk, deny dangerous), or off (no prompts, used by --yolo).
  • Dangerous pattern: A command shape (recursive delete, formatting, piping web content to a shell, ...) that Hermes recognizes as risky and intercepts.
  • Hardline blocklist: A set of commands so catastrophic that Hermes refuses regardless of mode or --yolo.

Real World Context

When you ask Hermes to clean up old node_modules and it tries rm -rf node_modules, you see a prompt: Run this command? (once / session / always / deny). That is the approval gate. You can approve once, for the rest of the session, permanently (added to your allowlist), or deny it. The prompt exists because rm -rf matches a dangerous pattern and even if you trust the agent, you should look at the exact path before letting it run.

Deep Dive

The three modes:

  • manual (default). Every dangerous pattern triggers a prompt. You decide. This is the right setting for any surface where the agent might do something destructive and a human can review.
  • smart. Hermes uses an auxiliary LLM call to assess each dangerous-pattern match. Low-risk variants are auto-approved (rm node_modules/foo.json in a project context), and clearly dangerous ones are auto-denied. Useful for cutting friction in personal use without going full --yolo.
  • off (equivalent to --yolo). No prompts. Commands run as-is. The hardline blocklist still applies. Use only on disposable environments or when you genuinely accept the risk.

What triggers a prompt under manual (a partial list):

  • Recursive deletes: rm -r, rm -R, rm -rf.
  • Permission changes: chmod 777, chmod o+w.
  • Recursive ownership changes: chown -R.
  • Filesystem formatting: mkfs.*.
  • Disk operations: dd if=/dev/zero.
  • Destructive SQL: DROP TABLE, DELETE FROM without WHERE, TRUNCATE.
  • Piping web content to a shell: curl ... | sh, wget ... | sh.
  • System file overwrites: > /etc/....
  • Process termination: kill -9 -1, pkill -9.
  • Self-termination: pkill hermes.

The hardline blocklist refuses outright (no --yolo override):

  • rm -rf / and variants.
  • Fork bombs.
  • Filesystem formatting of the root device while mounted.
  • Disk zeroing of /dev/sd*.
  • Piping untrusted URLs to a shell at the filesystem root.

Approval flow in different surfaces:

  • CLI: Inline prompt with four options (once, session, always, deny). Default is deny on timeout.
  • Gateway (Telegram, Discord, etc.): A message asking for yes or no. Configurable timeout (default 60 seconds). No response defaults to deny.

Container backends skip the dangerous-command check because the container itself is the boundary: anything dangerous can only affect the container.

Common Pitfalls

  1. Approving everything reflexively: When the prompts get frequent, the temptation is to hit always. Resist. Read the command, decide each time, or switch to a tighter toolset so the agent stops asking.
  2. Running --yolo in shared environments: Disabling approvals is fine for a disposable VM. It is not fine for a machine with anything you care about.

Best Practices

  1. Read the command, not the description: Hermes shows the literal command in the prompt. Read that, not the agent's friendly summary.
  2. Pick smart for personal use, manual for production: smart cuts friction; manual gives review.

Summary

  • Approval gates pause the tool loop and ask a human before running dangerous commands.
  • Three modes: manual (default), smart (LLM-assisted), off (yolo).
  • The hardline blocklist refuses some commands no matter what.
  • Container backends skip the check because the container is the boundary.

Code Examples

yaml
# Configure approval mode in ~/.hermes/config.yaml
approvals:
  mode: smart       # manual | smart | off
  timeout: 60       # seconds before deny (default 60)

# Alternatively, bypass approvals at runtime:
#   hermes --yolo
# Or toggle from inside an active session:
#   /yolo
✓ Completed