mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-28 22:36:48 +00:00
* docs: replace openclaw docs skill * docs: align technical documentation skill policy * docs: restore openclaw refactor docs skill
194 lines
9.0 KiB
Markdown
194 lines
9.0 KiB
Markdown
---
|
|
summary: "Ask users to approve plugin tool calls and plugin-owned permission prompts"
|
|
title: "Plugin permission requests"
|
|
sidebarTitle: "Permission requests"
|
|
read_when:
|
|
- You need a plugin hook or tool to ask before a side effect runs
|
|
- You need to configure where plugin approval prompts are delivered
|
|
- You are deciding between optional tools, exec approvals, and plugin approvals
|
|
---
|
|
|
|
Plugin permission requests let plugin code pause a tool call or plugin-owned
|
|
operation until a user approves or denies it. They use the Gateway
|
|
`plugin.approval.*` flow and the same approval UI surfaces that handle chat
|
|
approval buttons and `/approve` commands.
|
|
|
|
Use plugin permission requests for plugin/app permissions. They do not replace
|
|
host exec approvals, optional tool allowlists, or Codex's native permission
|
|
review.
|
|
|
|
## Choose the right gate
|
|
|
|
Pick the gate that matches the decision point you need:
|
|
|
|
| Gate | Use it when | What it controls |
|
|
| -------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
|
|
| Optional tools | A tool should not be visible to the model until the user opts in. | Tool exposure through `tools.allow`. |
|
|
| Plugin permission requests | A plugin hook or plugin-owned operation must ask before one action runs. | Runtime approval through `plugin.approval.*`. |
|
|
| Exec approvals | A host command or shell-like tool needs operator approval. | Host exec policy and durable exec allowlists. |
|
|
| Codex native permission requests | Codex asks before native shell, file, MCP, or app-server actions. | Codex app-server or native hook approval handling, routed through plugin approvals when OpenClaw owns the prompt. |
|
|
| MCP approval elicitations | A Codex MCP server requests approval for a tool call. | MCP approval responses bridged through OpenClaw plugin approvals. |
|
|
|
|
Optional tools are a discovery-time gate. Plugin permission requests are a
|
|
per-call gate. Use both when a sensitive tool should require explicit opt-in
|
|
before the model can see it and approval before the action runs.
|
|
|
|
## Request approval before a tool call
|
|
|
|
Most plugin-authored prompts should start in a `before_tool_call` hook. The hook
|
|
runs after the model selects a tool and before OpenClaw executes it:
|
|
|
|
```typescript
|
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
|
|
export default definePluginEntry({
|
|
id: "deploy-policy",
|
|
name: "Deploy Policy",
|
|
register(api) {
|
|
api.on("before_tool_call", async (event) => {
|
|
if (event.toolName !== "deploy_service") {
|
|
return;
|
|
}
|
|
|
|
const environment =
|
|
typeof event.params.environment === "string" ? event.params.environment : "unknown";
|
|
|
|
return {
|
|
requireApproval: {
|
|
title: "Deploy service",
|
|
description: `Deploy service to ${environment}.`,
|
|
severity: environment === "production" ? "critical" : "warning",
|
|
allowedDecisions:
|
|
environment === "production"
|
|
? ["allow-once", "deny"]
|
|
: ["allow-once", "allow-always", "deny"],
|
|
timeoutMs: 120_000,
|
|
timeoutBehavior: "deny",
|
|
onResolution(decision) {
|
|
console.log(`deploy approval resolved: ${decision}`);
|
|
},
|
|
},
|
|
};
|
|
});
|
|
},
|
|
});
|
|
```
|
|
|
|
Write prompt text for the person who will approve the action:
|
|
|
|
- Keep `title` short and action-focused. The Gateway accepts up to 80
|
|
characters.
|
|
- Keep `description` specific and bounded. The Gateway accepts up to 256
|
|
characters.
|
|
- Include the action, target, and risk. Do not include secrets, tokens, or
|
|
private payloads that should not appear in chat approval surfaces.
|
|
- Use `severity: "critical"` only for actions where the wrong decision could
|
|
cause production damage or data loss.
|
|
- Use `allowedDecisions: ["allow-once", "deny"]` when persistent trust is
|
|
unsafe for that action.
|
|
|
|
## Decision behavior
|
|
|
|
OpenClaw creates a pending approval with a `plugin:` ID, delivers it to the
|
|
available approval surfaces, and waits for a decision.
|
|
|
|
| Decision | Result |
|
|
| ----------------- | ------------------------------------------------------------------------- |
|
|
| `allow-once` | The current call continues. |
|
|
| `allow-always` | The current call continues and the decision is passed to the plugin. |
|
|
| `deny` | The call is blocked with a denied tool result. |
|
|
| Timeout | The call is blocked unless `timeoutBehavior` is `"allow"`. |
|
|
| Cancellation | The call is blocked when the run is aborted. |
|
|
| No approval route | The call is blocked because no connected approval surface can resolve it. |
|
|
|
|
`allow-always` is only durable when the requesting plugin or runtime implements
|
|
that persistence. For ordinary `before_tool_call.requireApproval` hooks,
|
|
OpenClaw treats `allow-once` and `allow-always` as approval decisions for the
|
|
current call and passes the resolved value to `onResolution`. If your plugin
|
|
offers `allow-always`, document and implement exactly what future calls it
|
|
trusts.
|
|
|
|
If the hook also returns `params`, OpenClaw applies those parameter changes only
|
|
after the approval succeeds. A lower-priority hook can still block after a
|
|
higher-priority hook requested approval.
|
|
|
|
`allowedDecisions` limits the buttons and commands shown to the user. The
|
|
Gateway rejects a resolve attempt for any decision the request did not offer.
|
|
|
|
## Route approval prompts
|
|
|
|
Approval prompts can resolve in local UI surfaces or in chat channels that
|
|
support approval handling. To forward plugin approval prompts to explicit chat
|
|
targets, configure `approvals.plugin`:
|
|
|
|
```json5
|
|
{
|
|
approvals: {
|
|
plugin: {
|
|
enabled: true,
|
|
mode: "targets",
|
|
agentFilter: ["main"],
|
|
targets: [{ channel: "slack", to: "U12345678" }],
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
`approvals.plugin` is independent from `approvals.exec`. Enabling exec approval
|
|
forwarding does not route plugin approval prompts, and enabling plugin approval
|
|
forwarding does not change host exec policy.
|
|
|
|
When a prompt includes manual approval text, resolve it with one of the offered
|
|
decisions:
|
|
|
|
```text
|
|
/approve <id> allow-once
|
|
/approve <id> allow-always
|
|
/approve <id> deny
|
|
```
|
|
|
|
See [Advanced exec approvals](/tools/exec-approvals-advanced#plugin-approval-forwarding)
|
|
for the full forwarding model, same-chat approval behavior, native channel
|
|
delivery, and channel-specific approver rules.
|
|
|
|
## Codex native permissions
|
|
|
|
Codex native permission prompts can also travel through plugin approvals, but
|
|
they have different ownership than plugin-authored hooks.
|
|
|
|
- Codex app-server approval requests route through OpenClaw after Codex review.
|
|
- The native hook `permission_request` relay can ask through
|
|
`plugin.approval.request` when that relay is enabled.
|
|
- MCP tool approval elicitations route through plugin approvals when Codex marks
|
|
`_meta.codex_approval_kind` as `"mcp_tool_call"`.
|
|
|
|
See [Codex harness runtime](/plugins/codex-harness-runtime#native-permissions-and-mcp-elicitations)
|
|
for the Codex-specific behavior and fallback rules.
|
|
|
|
## Troubleshooting
|
|
|
|
**The tool says plugin approvals are unavailable.** No approval UI or configured
|
|
approval route accepted the request. Connect an approval-capable client, use a
|
|
channel that supports same-chat `/approve`, or configure `approvals.plugin`.
|
|
|
|
**`allow-always` appears but the next call prompts again.** The generic plugin
|
|
approval flow does not automatically persist trust for arbitrary hooks. Persist
|
|
plugin-owned trust in your plugin after `onResolution("allow-always")`, or
|
|
offer only `allow-once` and `deny`.
|
|
|
|
**`/approve` rejects the decision.** The request restricted
|
|
`allowedDecisions`. Use one of the decisions printed in the prompt.
|
|
|
|
**A Slack, Discord, Telegram, or Matrix prompt routes differently from exec
|
|
approvals.** Plugin approvals and exec approvals use separate config and may use
|
|
different authorization checks. Verify `approvals.plugin` and the channel's
|
|
plugin approval support instead of only checking `approvals.exec`.
|
|
|
|
## Related
|
|
|
|
- [Plugin hooks](/plugins/hooks#tool-call-policy)
|
|
- [Building plugins](/plugins/building-plugins#registering-agent-tools)
|
|
- [Advanced exec approvals](/tools/exec-approvals-advanced#plugin-approval-forwarding)
|
|
- [Gateway protocol](/gateway/protocol)
|
|
- [Codex harness runtime](/plugins/codex-harness-runtime#native-permissions-and-mcp-elicitations)
|