
Turn Hermes Approval History into a Safe Allowlist
Repeated approval prompts can create fatigue, but disabling approvals with --yolo or approvals.mode: off removes the review boundary for every command. Hermes offers a narrower alternative: mine commands you actually approved, review the resulting patterns, and merge only selected proposals into command_allowlist.
The goal is not to convert history automatically. It is to use history as evidence for a small, auditable policy.
Understand what Hermes mines
Run the read-only proposal command first:
hermes approvals suggestHermes scans the active profile's ~/.hermes/state.db for commands that were classified as dangerous and actually executed after approval. It aggregates repeated approvals into command patterns or dangerous-class keys, ranks them by frequency, and prints a numbered proposal. By default, it examines the last 90 days and requires at least two approvals before a pattern qualifies.
The proposal generator has important safety filters:
- It does not write anything unless
--applyis supplied explicitly. - It skips proposals already covered by the current
command_allowlist. - It never proposes destructive classes such as recursive deletion,
sudo, disk or device writes, credential and system-configuration edits, pipe-to-shell execution, SQL DROP or TRUNCATE, process kills, or any hardline class. - Frequency does not override those exclusions. Repeatedly approving a recursive delete still cannot produce an
rmproposal.
These safeguards reduce obvious hazards, but a proposed pattern is still not a recommendation. It is a summary of prior decisions.
Narrow the review window
Use a shorter time window and a higher repetition threshold when old or one-off work should not shape permanent policy:
hermes approvals suggest --days 30 --min-count 3 --limit 20
hermes approvals suggest --json--json is useful for an external audit or script, while the normal output is easier for a human to review. The command also supports --db PATH for an explicitly selected session database, but the safest default is to run it under the Hermes profile whose policy you intend to change.
Treat each proposal as a capability grant. Ask:
- Is the action routine across future sessions, or was it safe only in one repository, container, remote, or incident?
- How much does the wildcard cover? A pattern such as
git push *spans more repositories, branches, and remotes than one previously approved command. - Does the proposal represent an exact command family or a broader dangerous-class key for compound commands?
- Could a narrower session-only approval solve the problem without creating a permanent rule?
- What complementary deny rule should remain non-negotiable?
If the scope is hard to explain in one sentence, do not apply it.
Apply only reviewed selections
Apply proposals by their current numbered indexes:
hermes approvals suggest --apply 1,3The selected patterns are merged into the top-level command_allowlist in config.yaml. Review the result immediately:
hermes config edit
hermes config checkAfter applying a reviewed proposal, open the resulting command_allowlist and read the exact stored pattern before continuing. Do not widen it for convenience, paste a pattern merely because the count is high, or turn a one-session need into a permanent rule. The allowlist silently approves every matching dangerous command in future sessions, so keep it short enough that every entry still has an owner, a bounded purpose, and a reason.
The interactive CLI also offers once, session, always, and deny at an approval prompt. Prefer once for exceptional work, session for a bounded maintenance window, and a permanent history-derived rule only for a stable recurring operation. Choosing always writes directly to the permanent allowlist, so it deserves the same review.
Preserve a deny floor
A permanent allowance should not remove explicit red lines. User-defined deny rules live under approvals.deny and are matched case-insensitively as whole-command fnmatch globs against normalized command variants. They are evaluated unconditionally before --yolo, /yolo, and approvals.mode: off on host-reaching backends.
Do not try to make a broad allowance safe by carving exceptions out with one narrow deny glob. Whole-command patterns are positional: a rule written for an option immediately after the executable may miss the same option later in the command, an alternate force form, or another normalized variant. If an operation such as force-pushing must remain review-gated, keep any broader command family that could include it out of command_allowlist and approve safe instances individually. Deny rules and the code-shipped hardline blocklist remain useful defense in depth, but they are not a substitute for a narrow allowance.
Verify without creating new risk
Read back the configuration and validate it before starting a future session. Because the permanent patterns are documented as being loaded for future sessions, test only in a deliberately non-production context or wait for the next normal occurrence of the workflow. Do not trigger a risky command solely to prove that a prompt disappeared.
Keep approvals.mode: smart unless you have a separate, trusted sandboxing reason to change it. Smart mode can auto-approve low-risk cases for one command while still denying dangerous actions or escalating uncertain cases. The allowlist should reduce known repetitive prompts, not replace the broader review system.
Pitfalls
- Approval history records what was allowed, not why it was safe. Repository, host, timing, and operator intent can be lost during aggregation.
- Proposal indexes can change when the history window, threshold, existing allowlist, or database changes. Review and apply from the same fresh proposal run.
- A class-key proposal for a compound command can be broader than one exact command string. Read its label and scope carefully.
- Manually adding broad entries such as a bare executable name can authorize far more than a generated scoped pattern.
- Isolated container backends skip the host dangerous-command guard stack because the container is treated as the boundary. Do not assume host allowlist and deny behavior describes every backend.
approvals.mode: offis not an allowlist optimization; it disables approval checks wholesale.
Verification checklist
- Verify the initial
hermes approvals suggestrun is a dry run and changed no configuration. - Verify every selected proposal has a documented recurring use and an acceptably narrow wildcard or class scope.
- Verify
--applyreferences indexes from the proposal you just reviewed. - Verify
hermes config checksucceeds andcommand_allowlistcontains only the intended additions. - Verify critical
approvals.denyrules remain quoted and present. - Verify smart or manual approval mode remains enabled unless a separate sandbox policy explicitly justifies otherwise.
- Verify testing occurs in a non-production context and does not manufacture a dangerous side effect.
