-
Notifications
You must be signed in to change notification settings - Fork 0
Configuration
Directory (preferred):
~/.hermes/custom-dangerous-patterns/
All *.yaml files in the directory are loaded and merged alphabetically.
Most CLI write commands (enable, disable, add without --target)
write delta entries to 99-custom.yaml — user-created files are never
modified.
Two exceptions:
-
removedeletes entries directly from source YAML files -
add --target <filename>writes to the specified file
Single file (fallback):
~/.hermes/custom-dangerous-patterns.yaml
Combined mode: When both the directory and the sibling .yaml file
exist, both are loaded and merged (directory files take precedence via
dedup).
Override with env var:
export HERMES_CUSTOM_PATTERNS_PATH=/path/to/config.yaml
# Or point to a directory:
export HERMES_CUSTOM_PATTERNS_PATH=/path/to/config-directory/The hermes custom-dangerous-patterns CLI allows managing patterns without editing YAML directly:
-
list— List all patterns with filtering by type, group, search, status -
test <cmd>— Test a command against all pattern types without running it -
init— Bootstrap a config directory (--with-examplesfor demo patterns) -
enable / disable— Toggle patterns by index, description, or group (auto-interactive when no target or group) -
add— Add a pattern interactively or via CLI flags (supports--globfor glob-to-regex,--targetfor direct file writes) -
remove— Remove a pattern (truly deletes from source YAML; use--forceto skip confirmation) -
validate— Check config syntax and regex validity (supports--quietfor CI) -
info— Dashboard: pattern counts, integrity status, group breakdown -
logs— Extract plugin log entries from Hermes logs
See CLI-Reference for full command details and glob syntax reference.
These commands trigger the approval prompt:
patterns:
- pattern: '\bvultr\b'
description: 'Vultr CLI command'
enabled: true
group: cloud
protected: false
examples:
- 'vultr account info'
- 'vultr instance list'| Field | Required | Description |
|---|---|---|
pattern |
Yes* | Python regex (matched with re.IGNORECASE | re.DOTALL). Can be omitted if glob is provided — the regex is auto-generated from the glob on config load. |
description |
Yes | Human-readable label shown in the approval prompt |
examples |
No | Documentation-only list of example commands |
enabled |
No | Boolean (default true). Set false to temporarily disable |
group |
No | Optional string tag for categorization (e.g., cloud, database) |
protected |
No | Boolean (default false). If true, integrity-checked across sessions |
glob |
No | Original glob pattern. If pattern is absent, the glob is auto-converted to regex on config load. |
*
patternorglobrequired. At least one must be present. If both are provided,patternis used as-is. If onlyglobis present, the regex is auto-generated during config validation.
Exempt specific commands from approval, even if they match a block pattern:
allow_patterns:
- pattern: '\bvultr\s+(account\s+info|instance\s+list)\b'
description: 'Read-only Vultr commands'
enabled: true
group: cloud| Field | Required | Description |
|---|---|---|
pattern |
Yes* | Python regex (same flags as block patterns). Can be omitted if glob is provided — auto-generated from glob. |
description |
No | Documentation-only label |
enabled |
No | Boolean (default true). Set false to temporarily disable |
group |
No | Optional string tag for categorization |
protected |
No | Boolean (default false). If true, integrity-checked across sessions |
glob |
No | Original glob pattern. If pattern is absent, auto-converted to regex on load. |
*
patternorglobrequired. At least one must be present. If both are provided,patternis used as-is.
Commands matching deny patterns are blocked immediately without an approval prompt. They are checked before allow and block patterns — deny wraps the original guard function and intercepts first. Useful for commands that should never be run without manual config changes.
deny_patterns:
- pattern: '\bgit\s+push\s+--force\b'
description: 'Force git push'
enabled: true
group: git
examples:
- 'git push --force origin main'| Field | Required | Description |
|---|---|---|
pattern |
Yes* | Python regex (same flags as block patterns). Can be omitted if glob is provided — auto-generated from glob. |
description |
Yes | Human-readable label shown in the block message |
examples |
No | Documentation-only list of example commands |
enabled |
No | Boolean (default true). Set false to temporarily disable |
group |
No | Optional string tag for categorization |
protected |
No | Boolean (default false). If true, integrity-checked across sessions |
glob |
No | Original glob pattern. If pattern is absent, auto-converted to regex on load. |
*
patternorglobrequired. At least one must be present. If both are provided,patternis used as-is.
Known limitation: Deny patterns intercept before --yolo/mode=off checks inside the original guard function, so --yolo does not bypass deny patterns. This will be addressed in a future Hermes core integration (v0.5.0).
All pattern types (block, allow, deny) support optional enabled, group, protected, and glob fields.
-
enabled(bool, defaulttrue) — Setfalseto temporarily disable a pattern without removing it -
group(string) — Optional tag for categorization (e.g.,cloud,database,testing) -
protected(bool, defaultfalse) — Iftrue, the pattern regex is integrity-checked across sessions -
glob(string) — Original glob pattern, saved automatically when the pattern was created via--glob. Ifpatternis not present, the glob is converted to regex on config load.
See each pattern type's field table above for full details. See CLI-Reference#Glob-Syntax for glob-to-regex conversion rules.
Instead of a single file, you can use a directory. The plugin loads all *.yaml files in alphabetical order and merges them:
- Lists (
patterns,allow_patterns,deny_patterns) are extended (appended) - Scalars override previous values
This is useful for splitting configs by tool or team:
~/.hermes/custom-dangerous-patterns/
├── 10-cloud.yaml # cloud CLI patterns
├── 20-database.yaml # database patterns
└── 30-deployment.yaml # deploy tool patterns
Use hermes custom-dangerous-patterns init to create a config directory
with starter files, or set the directory path via $HERMES_CUSTOM_PATTERNS_PATH.
When the config path is a directory, CLI write commands behave differently:
-
enable/disableandadd(without--target) write only the changed entries (delta) to99-custom.yaml, which sorts last in the merge order (highest precedence). User-created files (10-cloud.yaml,20-database.yaml) are never touched. -
add --target <filename>writes directly to the specified file (skips the delta system). The file must have a.yamlextension and no path separators. -
removedeletes entries directly from source YAML files using ruamel.yaml round-trip editing. Lines are removed — no disabled remnant is left behind. Protected patterns cannot be removed via CLI. - To reset CLI-managed patterns, delete
99-custom.yamland restart Hermes.
The plugin tracks configuration integrity across sessions:
- A SHA-256 hash of the full config YAML is stored in
~/.hermes/.custom-patterns-hash. If the config changes between sessions, aWARNINGis logged with old and new pattern counts. -
Protected patterns (
protected: true) have their individual regex hashed and tracked. If a protected pattern is modified or removed, aCRITICALwarning is logged at startup. - Allow shadowing detection warns if an allow pattern could bypass a built-in dangerous pattern without a corresponding custom block pattern.
These checks are detective, not preventive — they log changes but do not prevent them.
Patterns use \b to match whole words only. This prevents false positives:
| Pattern | Matches | Doesn't match |
|---|---|---|
\bvultr\b |
vultr instance list |
echo vultr_test, my-vultr-server
|
\baws\s+ec2\b |
aws ec2 describe-instances |
aws-ec2-tool, paws ec2
|
\bterraform destroy\b |
terraform destroy -auto-approve |
echo "terraform destroy" in a script |
Without \b, \bvultr would match any string containing "vultr" — including hostnames, variable names, or unrelated commands.
Tip: Use single-quoted YAML strings for patterns — backslashes pass through literally ('\bvultr\b'), avoiding the double-escaping needed with double quotes ("\\bvultr\\b").
Note: The runtime evaluation order differs because the deny-pattern wrapper runs before the original
check_all_command_guards()function that contains the yolo/mode=off check. Deny patterns intercept--yoloandmode=offby design.
Each check is tagged with its source:
-
[Plugin]— this plugin's custom checks -
[Hermes]— Hermes Agent's built-in checks
1. [Plugin] Deny patterns (custom) → BLOCKED immediately, no prompt
(wraps original check_all_command_guards)
2. [Hermes] Hardline check → blocked unconditionally
3. [Hermes] Sudo stdin guard → blocked unconditionally
4. [Hermes] Yolo / mode=off → bypasses steps 5-7
5. [Plugin] Allow patterns (custom) → command runs, no prompt (allow wins over block)
6. detect_dangerous_command(): — same approval prompt for both —
a. [Plugin] Block patterns (custom) → [o]nce/[s]ession/[a]lways/[d]eny
b. [Hermes] Built-in patterns → [o]nce/[s]ession/[a]lways/[d]eny
7. [Hermes] Tirith security scan → approval prompt if findings
Key rules:
- Deny wins over allow. Deny patterns are checked first (step 1). If a command matches a deny pattern, it is blocked before allow patterns are even evaluated.
- Allow wins over block. If a command matches both an allow pattern (step 5) and a block pattern (step 6a), allow wins and no prompt is shown.
-
Deny is immediate-block; block is approval-prompt. Block patterns go through the
detect_dangerous_command()approval flow. Deny patterns skip it entirely. -
Deny bypasses yolo. Deny patterns are evaluated outside the original guard function, so
--yolodoes not bypass them.
# ~/.hermes/custom-dangerous-patterns.yaml
#
# TIP: Use single-quoted strings for patterns — backslashes pass through
# literally: '\bvultr\b' not "\\bvultr\\b"
patterns:
# ── Cloud CLI tools (destructive) ────────────────────────────────
- pattern: '\bvultr\s+(instance\s+create|instance\s+delete|snapshot\s+create|snapshot\s+delete)\b'
description: 'Vultr destructive instance/snapshot command'
examples:
- 'vultr instance delete --instance-id cb670a12-e4f5-6d78-ab90-1234567890ab'
- 'vultr snapshot delete --snapshot-id 5a3b2c1d'
- pattern: '\bterraform\s+(destroy|apply)\b'
description: 'Terraform destroy/apply (infrastructure mutation)'
examples:
- 'terraform destroy -auto-approve'
- 'terraform apply -auto-approve'
- pattern: '\baws\s+(ec2|s3|rds|iam|lambda|cloudformation)\b'
description: 'AWS CLI mutating service command'
examples:
- 'aws ec2 terminate-instances --instance-ids i-12345'
- 'aws s3 rb s://my-bucket --force'
- 'aws rds delete-db-instance --db-instance-identifier mydb'
- pattern: '\bgcloud\s+(compute\s+instances\s+delete|projects\s+delete)\b'
description: 'GCP destructive command'
examples:
- 'gcloud compute instances delete my-vm --zone=us-central1-a'
- pattern: '\boci\s+(compute\s+instance\s+terminate|database\s+db\s+system\s+delete|network\s+vcn\s+delete)\b'
description: 'Oracle Cloud destructive command'
examples:
- 'oci compute instance terminate --instance-id ocid1.instance.oc1..aaaaaaaa'
- 'oci database db-system delete --db-system-id ocid1.dbsystem.oc1..aaaaaaaa'
- pattern: '\bdoctl\s+(compute\s+droplet\s+delete|kubernetes\s+cluster\s+delete|databases\s+delete)\b'
description: 'DigitalOcean destructive command'
examples:
- 'doctl compute droplet delete 12345678'
- 'doctl kubernetes cluster delete my-cluster'
- pattern: '\bkubectl\s+delete\s+namespace\b'
description: 'Kubernetes namespace deletion'
examples:
- 'kubectl delete namespace staging'
# ── Deployment tools ─────────────────────────────────────────────
- pattern: '\bcap\s+\w+\s+deploy\b'
description: 'Capistrano production deploy'
examples:
- 'cap production deploy'
- pattern: '\bfab\s+\w*\s*deploy\b'
description: 'Fabric deploy'
examples:
- 'fab deploy production'
# ── Database operations ──────────────────────────────────────────
- pattern: '\bDROP\s+(TABLE|DATABASE)\b'
description: 'SQL DROP statement'
examples:
- 'DROP TABLE users'
- 'DROP DATABASE production'
- pattern: '\bmongodump\b.*--drop\b'
description: 'MongoDB dump with --drop (overwrites existing data)'
examples:
- 'mongodump --drop --db production'
# ── Allow patterns ────────────────────────────────────────────────
# Commands matching these are EXEMPT from approval, even if they
# also match a blocked pattern. Evaluated BEFORE block patterns.
# Allow wins over block.
allow_patterns:
# ── Read-only cloud commands (safe) ─────────────────────────────
- pattern: '\bvultr\s+(account\s+info|instance\s+list|dns\s+list|plan\s+list)\b'
description: 'Read-only Vultr commands'
- pattern: '\baws\s+(ec2\s+describe|s3\s+ls|s3\s+cp.*--dry-run|iam\s+list)\b'
description: 'AWS read-only commands'
- pattern: '\bterraform\s+(plan|state\s+list|output)\b'
description: 'Terraform read-only commands'
- pattern: '\boci\s+(compute\s+instance\s+list|network\s+vcn\s+list|database\s+db\s+system\s+list)\b'
description: 'Oracle Cloud read-only commands'
- pattern: '\bdoctl\s+(compute\s+droplet\s+list|kubernetes\s+cluster\s+list|databases\s+list)\b'
description: 'DigitalOcean read-only commands'
# ── Help and utility (safe) ─────────────────────────────────────
- pattern: '\b(vultr|gcloud|aws|terraform|kubectl|oci|doctl)\s+(-h|--help|help)\b'
description: 'Help flags are safe'
- pattern: '\b(vultr|gcloud|aws|terraform|oci|doctl)\s+completion\b'
description: 'Shell completion scripts are safe'| Scenario | Behavior |
|---|---|
| Config file missing | Plugin loads silently, no patterns injected |
| Config file invalid YAML | Log WARNING, plugin loads with empty pattern list |
| Invalid regex in pattern | Log WARNING for that pattern, skip it, load valid ones |
| Block pattern matches but allow also matches | Allow wins — no prompt (allow wins over block) |
| Deny pattern matches (and allow also matches) | Deny wins — blocked immediately (deny checked first) |
| Glob with no pattern | Auto-converted to regex on config load |
| Glob and pattern disagree | Warning emitted by validate command |
| Config changed since last session | WARNING logged with old/new pattern counts |
| Protected pattern missing/modified | CRITICAL warning logged |
| Allow pattern shadows built-in pattern | WARNING logged with details |
--yolo mode |
Block patterns (custom + built-in) bypassed. Deny patterns still block — checked outside the original guard function. |
approvals.mode: off |
Block patterns bypassed. Deny patterns still block — checked outside the original guard function. |
approvals.mode: smart |
Custom patterns assessed by auxiliary LLM |
Cron session + cron_mode: deny
|
Custom patterns blocked in cron |
| Container backend (docker, etc.) | All approval checks skipped (sandboxed) |
command_allowlist "always" choice |
Persisted to config.yaml — survives restarts |