Skip to main content
Permissions answer two questions: which tools may this agent use, and may this particular operation proceed? Start with a small allowlist for routine work. Add ordered permission rules or a callback when the decision depends on a path, command, account, or user approval. Default local isolation separates runtime state and configuration. Permission modes do not create a filesystem or operating-system sandbox.

Start with a tool allowlist

For a file-reading agent, use allowedTools: ["read", "glob", "grep"]. For a text-only assistant, use disallowedTools: ["*"]. These are Agent constructor options; the built-in tools example includes a complete runnable file-reading agent. A nonempty allowlist restricts tools and grants matching operations, subject to effective deny rules. A denylist match wins over an allowlist match. allowedTools: [] is unrestricted, and explicitly supplying either list replaces the facade’s default hidden-tool profile. An allowlist cannot create a tool that the selected model or runtime has not made available.
disallowedTools: ["*"] also blocks schema submission through StructuredOutput. For a schema-only task, use allowedTools: ["StructuredOutput"].

Rules apply to operations

The permission option is an ordered array of { permission, pattern, action }. Within a ruleset, the last matching rule wins. Put a broad rule first and narrower exceptions after it. action is "allow", "deny", or "ask". The runtime also makes permission requests such as external_directory when a tool accesses a location outside its workspace. These are permission names, not additional tools you can call. Tool-list shorthand accepts scoped entries such as bash(npm:*) or task(reviewer). In the shell shorthand, : becomes a space, so bash(npm:*) matches the npm * command pattern. This is command-pattern authorization, not a guarantee about what an npm script will do. Use a controlled workspace and application-level boundaries for privileged execution.

Make a decision in your application

This complete example exposes a deterministic order lookup. The broad rule denies other operations; the later rule sends this tool’s requests through the approval path. The callback allows only the sample order. It deliberately does not add allowedTools: ["sdk_lookup_order"], because that matching grant could approve the request before the callback runs. Use the TypeScript example setup.
PermissionDecision.allow(updatedInput) can replace input; validate the replacement as well. deny(message) supplies a reason. ask() delegates to the remaining user-decision path and may keep the request pending. A headless callback should normally return a concrete allow or deny decision.

Understand decision order

For a tool that is available, effective deny rules stop the operation before modes or callbacks can approve it. A matching allow can also settle the request immediately. Rules from the Agent/session and the runtime tool lists are evaluated together; an effective deny from either wins. Unresolved requests pass through plugin permission decisions, the selected permission mode, and then the callback/user-decision path. Consequently, canUseTool is not a universal tool interceptor. An allow rule, accepted edit, bypass mode, or confident automatic classification can settle a request first. Use a denylist or effective deny rule for unconditional restrictions, and validate sensitive operations inside their implementation. Plugin permission hooks can explicitly keep a request on the approval path. The autoPermissionClassifierModel option chooses the classifier; this can incur extra provider usage. Prefer deterministic rules when the decision must not depend on a model.

Keep approval lifetimes bounded

Callbacks run in your application process over the runtime control channel. The server stores a descriptor, not the function. Rebind callbacks after an application restart; an explicit resume override of canUseTool: false removes a prior registration. A callback timeout or unavailable control channel can leave the user-decision path pending. Pass an application cancellation signal or deadline, as in the example, rather than assuming every failure becomes a denial. On an idle session, setPermissionMode(mode) changes its policy, and getAppliedSettings() shows the applied configuration.