Skip to content

resolveShellApprovalGate

resolveShellApprovalGate(config, command): ShellApprovalGateDecision

Defined in: _worktrees/docs-release/gaunt-sloth/packages/core/src/config/shell-policy.ts:1577

EXT-52 — the ONE shell approval-gate policy every agent backend resolves (GthLangChainAgent = lean/default). It decides whether the opt-in run_shell_command tool is gated behind the per-command approval interrupt, and which status notice (if any) the backend should surface. A backend contributes only HOW it installs the interrupt; the policy and its user-facing copy live here so no two can drift (and so a later rename of this config surface has one place to change).

CFG-27 — the tool is gated whenever it is enabled, at every rung including bypass. CFG-26 used to leave it UNGATED under bypass outside interactive code, which the ladder cannot afford: §2.5 makes the declared deny list the one check bypass keeps, and a deny entry can only fire if the call reaches GthAgentRunner.decideToolApproval — an ungated call never does. Gating unconditionally also keeps the rung switchable mid-session (/approvals <rung>), since a tool wired without the interrupt cannot be re-gated without rebuilding the agent.

What each rung then does is decided in decideToolApproval, not here: • bypass — deny list, then approve without prompting or rating. • manual/write — deny list, allow-list, else escalate to the human. • assisted/auto — deny list, allow-list, then the rater.

This decides the SHELL’s gating only, and it is not the whole gated set. With the shell tool disabled — or on a non-dev-tools command (chat/api/…) — nothing about the shell is gated and nothing is announced, but at manual and write resolveGatedToolNames still gates every bound tool the rung does not auto-grant, so an MCP call in a plain chat session is escalated there. Read gateShell as “does the shell need the interrupt”, never as “is the interrupt needed at all”.

Shell enablement itself is resolved through getEffectiveDevToolsConfig + isShellToolEnabled, so the gate stays in lockstep with where GthDevToolkit actually emits the tool; the posture comes from resolveApprovals, so this and the runner can never disagree about which rung is in force.

Pick<GthConfig, "commands" | "builtInTools" | "approvals" | "askWriteMode"> | undefined

GthCommand | undefined

ShellApprovalGateDecision