Skip to content

resolveShellApprovalGate

resolveShellApprovalGate(config, command): ShellApprovalGateDecision

Defined in: core/dist/config/shell-policy.d.ts:680

EXT-52 — the ONE shell approval-gate policy both agent backends resolve (GthLangChainAgent = lean/default, GthDeepAgent = deep). 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. The backends differ only in HOW they install the interrupt; the policy and its user-facing copy live here so the two can never 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. • read-only/write — deny list, allow-list, else escalate to the human. • auto-safe/full-auto — deny list, allow-list, then the rater. • With the shell tool disabled — or on a non-dev-tools command (chat/api/…) — nothing is gated and nothing is announced.

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, "builtInTools" | "approvals" | "commands" | "askWriteMode"> | undefined

GthCommand | undefined

ShellApprovalGateDecision