Skip to content

feat: surface command context in approval prompts - #22363

Open
sqp-adicr wants to merge 2 commits into
NousResearch:mainfrom
sqp-adicr:feat/approval-command-context
Open

feat: surface command context in approval prompts#22363
sqp-adicr wants to merge 2 commits into
NousResearch:mainfrom
sqp-adicr:feat/approval-command-context

Conversation

@sqp-adicr

Copy link
Copy Markdown

Summary

This PR surfaces optional command context after dangerous-command approval requests.

The existing approval Reason explains why Hermes flagged a command as requiring approval, e.g. delete in root path. This change adds optional user-facing context that explains:

  • Purpose — why the agent wants to run the command
  • Effect — what will change if the command runs
  • Risk — what the user should consider before approving

When this context is available, the gateway sends it as a follow-up message after the existing approval request:

Command approval context:

Purpose: ...

Effect: ...

Risk: ...

Motivation

Dangerous-command approvals are a security-critical UX path, especially in messaging gateways where users may approve commands from a mobile chat UI. The raw command and detector reason are useful, but they do not always explain what approving the command means for the current task.

This keeps the existing approval prompt and approval flow intact while adding structured decision context when the model provides it.

Changes

  • Add optional terminal tool schema fields:
    • approval_purpose
    • approval_effect
    • approval_risk
  • Thread approval context through terminal_tool into check_all_command_guards(...).
  • Normalize model-supplied approval context before attaching it to gateway approval data.
  • Send a follow-up gateway message with purpose/effect/risk when context is available.
  • Preserve the existing approval prompt and Reason field.
  • Add tests for schema exposure, context normalization, and gateway approval data.

Notes

This PR does not auto-generate explanations with another model. It only surfaces context supplied by the tool call, avoiding extra latency, cost, and privacy considerations in the approval path.

Test Plan

  • python3 -m py_compile gateway/run.py tools/approval.py tools/terminal_tool.py tests/tools/test_command_guards.py
  • python3 -m pytest tests/tools/test_command_guards.py -q -o 'addopts='

Local result:

23 passed

Add optional purpose/effect/risk context fields to terminal tool calls and thread them through command approval requests. Gateway approval prompts keep the existing request message intact and send a follow-up context message when explanation data is available.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery comp/tools Tool registry, model_tools, toolsets tool/terminal Terminal execution and process management labels May 9, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for improving the information available at a security-sensitive approval decision point. The idea remains relevant on current main, but this patch needs a safety-focused salvage.

Problems

  • gateway/run.py:14258-14281 sends model-supplied purpose/effect/risk directly to the adapter. Current main explicitly redacts approval output at gateway/run.py:18503-18509; these new fields need the same forced-redaction boundary before delivery.
  • tools/terminal_tool.py:322-327 replaces the consolidated-guard wrapper without current main's has_host_access propagation. Current main passes that value at tools/terminal_tool.py:2282-2285 to ensure host-mounted Docker commands cannot take the isolated-container approval bypass.

Suggested changes

  • Preserve has_host_access when adding context and adapt the implementation to current main's notifier scheduling path.
  • Redact context at each approval egress and add delivery-level coverage, including the API/TUI payload paths.

Automated hermes-sweeper review.

Comment thread gateway/run.py
asyncio.run_coroutine_threadsafe(
_status_adapter.send(
_status_chat_id,
followup_msg,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sends model-controlled context directly to the chat adapter. Approval output is a secret-egress boundary on current main (gateway/run.py:18503-18509 redacts the command with forced redaction); redact each context field before constructing this follow-up and cover the delivery path with a credential-shaped fixture.

Comment thread tools/terminal_tool.py
return _check_all_guards_impl(command, env_type,
approval_callback=_get_approval_callback())
approval_callback=_get_approval_callback(),
approval_context=approval_context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please preserve current main's has_host_access propagation here. Current terminal_tool passes it into the consolidated guard for host-mounted Docker backends; removing it would reintroduce approval bypass for commands reaching bind-mounted host paths.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit labels Jul 13, 2026

@GottZ GottZ left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during triage.

Summary

Two PRs address the missing purpose/effect/risk context in dangerous-command approvals. #22363 adds structured context as a separate follow-up with redaction across gateway egress paths, while #75795 rebuilds the feature for the current approval architecture as one sanitized, redacted, fail-closed approval message.

Related pull requests

  • #22363 related — (+280/-8) — superseded implementation: The diff threads purpose/effect/risk through the terminal guard pipeline and adds forced redaction for chat, API, and TUI egress, but delivers gateway context as a separate follow-up message. Despite the keep_open review on #22363, #75795 covers the same user-visible need on the current single-message path and avoids the follow-up ordering and association problem.
  • #75795 related — (+983/-83) — keep open with a salvage path: The diff co-locates sanitized, credential-redacted model context with the actionable approval prompt and adds fail-closed delivery handling, directly addressing the reported lack of decision context. The keep_open review identifies a blocking sanitizer bypass because LF/CR are removed before line-based forged-command filtering, plus duplicate CLI rendering because both enhanced_desc and explanation contain the context.

Duplicates

#22363 and #75795 substantially overlap at the feature and guard-pipeline level, although #75795 is a current-architecture redesign rather than a line-for-line duplicate; for consolidation, #22363 can be treated as superseded by #75795.

Suggested consolidation

Keep #75795 open with a salvage path: normalize CRLF first, preserve LF while stripping other controls, filter every forged-command line, add embedded-line and CRLF regression coverage, and render purpose/effect/risk only once in the CLI fallback. Then close #22363 as duplicate of #75795 for issue-tracking purposes; this differs from the keep_open review on #22363 because the complete #75795 diff preserves its core context/schema work while replacing the separate follow-up with the current single-message approval design. Do not advance #75795 until its contributor-blocking sanitizer and duplicate-rendering findings are resolved.

Cross-PR triage: Reviewed 2 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 82 kB of PR diffs, 6 kB of issue/PR text, 3 kB of discussion (5 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

@sqp-adicr

sqp-adicr commented Aug 2, 2026 via email

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data tool/terminal Terminal execution and process management type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants