Files
oh-my-pi/docs/approval-mode.md
T
can1357 535f7cfa89 fix(coding-agent/tools): reworked yolo approval resolution to honor user tool policies
- In `resolveApproval`, yolo mode now returns the user policy directly (`allow`/`prompt`/`deny`) and ignores tool `override` prompts.
- Updated approval-mode and approval unit tests to match the new behavior for critical bash patterns under yolo and auto-approve.
- Updated docs and settings metadata to describe yolo as user-policy-driven rather than override-driven.
2026-05-27 00:21:33 +02:00

97 lines
3.4 KiB
Markdown

# Tool approval mode
Tool approval has two independent inputs:
1. **Tool declaration** — every tool may declare an `approval` tier:
- `read`: reads data or updates UI-only session metadata.
- `write`: mutates workspace/session state but does not execute arbitrary code.
- `exec`: executes code, shells out, drives a browser, spawns agents, or performs similarly broad actions.
2. **User policy** — `tools.approval.<toolName>: allow | deny | prompt` overrides the mode for that tool.
Tools without an `approval` declaration are treated as `exec`. This is the safe default for MCP and unknown custom tools.
## Modes
Configure with `tools.approvalMode`:
## Modes
| Mode | Auto-approves | Prompts for |
| --- | --- | --- |
| `always-ask` | `read` | `write`, `exec` |
| `write` | `read`, `write` | `exec` |
| `yolo` (default) | `read`, `write`, `exec` | none |
`--auto-approve` and `--yolo` force `tools.approvalMode: yolo` for the session.
## User overrides
`tools.approval` is honored in every mode:
```yaml
tools:
approvalMode: write
approval:
bash: prompt
read: allow
mcp__filesystem__delete: deny
```
Resolution per tool call:
1. Compute the tool's approval decision from `tool.approval(args)`; omitted means `exec`.
2. A user policy in `tools.approval.<tool>` is always applied.
3. In `yolo` mode, with no user policy, the call is auto-approved.
4. In non-yolo modes, if the tool sets `override: true`, `deny` is blocked and all other cases prompt.
5. Otherwise, the active mode auto-approves or prompts by tier.
Invalid policy values are ignored and fall back to the tool tier/mode decision.
## Safety overrides
A tool can force a prompt with object-form approval:
```ts
approval: { tier: "exec", override: true, reason: "Critical pattern detected" }
```
`bash` uses this for critical destructive patterns such as `rm -rf /`, fork bombs, remote-fetch-then-execute, writes to `/etc/passwd`, and host shutdown commands. These surface as `reason` in the approval prompt, but in `yolo` mode they are auto-approved unless a user policy for the tool is set to `prompt` or `deny`.
## Per-tool prompt details
Tools can add approval-prompt body lines with `formatApprovalDetails(args)`. The standard prompt includes:
- `Allow tool: <name>`
- `Origin: MCP server tool` for unannotated `mcp__...` tools
- `Reason: <reason>` when the tool decision supplies one
- tool-specific details such as command, path, code, browser action, or subagent assignment
## Defining approval on tools
Built-in and custom tools share the same shape:
```ts
export type ToolTier = "read" | "write" | "exec";
export type ToolApprovalDecision = ToolTier | { tier: ToolTier; reason?: string; override?: boolean };
export type ToolApproval = ToolApprovalDecision | ((args: unknown) => ToolApprovalDecision);
approval?: ToolApproval;
formatApprovalDetails?: (args: unknown) => string | string[] | undefined;
```
Examples:
```ts
approval: "read"
approval: args => LSP_READONLY_ACTIONS.has(args.action) ? "read" : "write"
approval: args => isCritical(args.command)
? { tier: "exec", override: true, reason: "Critical pattern detected" }
: "exec"
```
## Subagents
Subagents run headless with `tools.approvalMode: yolo` so they do not stall waiting for UI. The parent `task` approval is the authorization boundary. User `tools.approval.<tool>` settings continue to control whether a tool is allowed, prompted, or blocked.