fix(cli): /yolo in chat must enable session bypass, not just set env var#33931
Merged
kshitijk4poor merged 1 commit intoMay 28, 2026
Merged
Conversation
The CLI's in-chat `/yolo` toggle mutated `os.environ["HERMES_YOLO_MODE"]`
but had no effect because `tools/approval.py:_YOLO_MODE_FROZEN` captures
that env var once at module-import time (a deliberate security floor that
keeps prompt-injected skills from flipping the bypass mid-run). By the
time the user reaches `/yolo` in a running CLI session, `tools.approval`
has already been imported, so the env flip after that is a silent no-op.
Result: `/yolo` advertised "⚠ YOLO" in the status bar while every
dangerous command still hit the approval prompt or got denied. Only
`hermes --yolo` (set before tool imports), `HERMES_YOLO_MODE=1 hermes ...`,
and `hermes config set approvals.mode off` actually bypassed.
This patches the CLI to match what the gateway and TUI `/yolo` handlers
already do, plus mirrors the TUI's session-rename YOLO transfer:
* `_toggle_yolo()` now calls `enable_session_yolo(self.session_id)` /
`disable_session_yolo(self.session_id)` instead of touching the env
var. Matches `gateway/run.py:_handle_yolo_command` and the
`tui_gateway/server.py` key=="yolo" branch.
* Around each `run_conversation()` call, `run_agent()` now binds
`set_current_session_key(self.session_id)` so
`tools.approval.is_current_session_yolo_enabled()` resolves against
the same key the toggle writes under, and resets it in `finally` so
reused threads don't see stale identity. Matches the
`tui_gateway/server.py` and `gateway/platforms/api_server.py` binding
pattern.
* New `_transfer_session_yolo()` helper carries YOLO bypass state
across `self.session_id` reassignments — `/branch` forking into a
new session id and the auto-compression sync that rotates into a
fresh continuation session id. Without this, the same UX failure
mode the rest of this fix addresses (silent `/yolo` no-op) would
reappear after a single `/branch` or auto-compression event.
Mirrors `tui_gateway/server.py` ~line 1297-1305.
* New `_is_session_yolo_active()` helper replaces the two
`bool(os.getenv("HERMES_YOLO_MODE"))` reads in the status-bar
builders, so the badge reflects the actual bypass state. Uses
`getattr(self, "session_id", None)` so status-bar test fixtures
that bypass `__init__` via `HermesCLI.__new__(HermesCLI)` don't
trip `AttributeError` (the builders swallow exceptions silently
and lose every field after the failure). Still honors
`_YOLO_MODE_FROZEN` so `hermes --yolo` keeps lighting it up.
The `_YOLO_MODE_FROZEN` security freeze is preserved — env-var-based
opt-in still only works when set before process start, which is the
documented contract for `--yolo` / `HERMES_YOLO_MODE`.
Closes NousResearch#33925
e372c72 to
6574663
Compare
2 tasks
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #33925.
The CLI's in-chat
/yolotoggledos.environ["HERMES_YOLO_MODE"]but never bypassed approvals — that env var is captured once at module-import time intotools/approval.py:_YOLO_MODE_FROZEN(a deliberate security floor that stops prompt-injected skills from flipping the bypass mid-run), so any post-import flip is a silent no-op. The CLI handler also didn't callenable_session_yolo()the way the gateway and TUI handlers do, so the per-session bypass path couldn't fire either.Net effect: the status bar showed
⚠ YOLOwhile every dangerous command still hit the approval prompt or got denied. Onlyhermes --yolo(set before tool imports),HERMES_YOLO_MODE=1 hermes ..., andhermes config set approvals.mode offactually bypassed.Changes
cli.py:_toggle_yolo()— now callsenable_session_yolo(self.session_id)/disable_session_yolo(self.session_id)instead of mutating the env var. Matchesgateway/run.py:_handle_yolo_commandandtui_gateway/server.pykey=="yolo".cli.py:run_agent()(insideprocess_input) — bindsset_current_session_key(self.session_id)aroundrun_conversation()sois_current_session_yolo_enabled()resolves against the same key the toggle writes under. Resets infinallyso reused threads don't see stale identity. Mirrorstui_gateway/server.py:3496-3812andgateway/platforms/api_server.py:3658-3672.cli.py:_is_session_yolo_active()— new helper that replaces the twobool(os.getenv("HERMES_YOLO_MODE"))reads in the status-bar builders (cli.py:3750,cli.py:3811). Reads the live session-yolo state and still honors_YOLO_MODE_FROZENsohermes --yolocontinues to light up the badge.tests/cli/test_cli_yolo_toggle.py— 8 new regression tests covering: ON/OFF toggle, no env-var mutation, missing-session_idfallback to"default", two-session isolation, status-bar helper,_YOLO_MODE_FROZENinteraction, and an end-to-end check thatcheck_all_command_guardsactually auto-approves after the toggle.The
_YOLO_MODE_FROZENsecurity freeze itself is preserved — env-var-based opt-in still only works when set before process start, which is the documented contract for--yolo/HERMES_YOLO_MODE.Test Plan
Manual repro verified before/after on
origin/main:hermes→/yolo→ status bar shows ⚠ YOLO →rm -rf /tmp/foo→ still prompts.hermes→/yolo→ status bar shows ⚠ YOLO →rm -rf /tmp/foo→ auto-approved.Related
approvals.modedropdown shows stale["ask", "yolo", "deny"]instead of the values the normalizer accepts (["manual", "smart", "off"]). Same family of bug (UI surface that doesn't actually toggle approvals). Out of scope here, but the user who reported CLI /yolo (in-chat) does not bypass dangerous command approvals — env var freeze + missing enable_session_yolo call #33925 also hit that path.HERMES_YOLO_MODE=falseas YOLO on. Cleaned up the same status-bar reads we touch here.computer_use; different scope, doesn't touch the CLI/yolopath.