The Qoder Agent SDK's permission control capabilities manage what the model can do within a single
The example expresses a common policy: the model sees
Permission-related options fall into four groups. The first sets the default policy—plan mode, auto-accept edits, no interactive prompts. The second sets tool scope and rules. The third brings the host into runtime approval. The fourth covers advanced settings, hooks, and MCP tool policy.
To stay focused on permission config, later examples omit the message-consumption code; real usage still consumes the returned async message stream.
Use the permission callback when tool calls must go through your own approval logic. At runtime the SDK hands your callback the tool name, tool input, and a set of displayable approval details. Returning allow lets the tool run; deny rejects it.
Here
The permission mode (
To switch modes within a session, use the runtime control method:
Tool control answers "which tools the model can see, and which are allowed or denied by default". The three fields often appear together but differ semantically.
This configuration means: only provide
When the same tool matches both allow and deny, deny takes priority. This ensures deny rules cannot be bypassed by broader allow rules.
MCP tools also use full tool name matching. For example, with SDK MCP server named
The permission callback suits hosts that take part in approval—showing permission requests in your own UI with "allow once", "always allow this session", or "deny"; or asking an enterprise risk service whether a command may run.
The callback signature:
Key fields (on the third
Return allow to continue executing the tool:
The updated input is what the tool ultimately receives. Return it unchanged, or modify it post-approval—adding a tenant ID, rewriting paths into a safe directory, or stripping disallowed fields.
Return deny to reject the tool:
Such messages typically appear with
You can also construct rules directly:
Supported update types:
Prefer writing dynamic permission updates to the current session (
By default the session treats
This configuration means the session's main working directory is
Directory authorization is part of the permission boundary. Don't make broad directories a default; add the minimal set per task instead.
This option (TypeScript:
Three things to note:
It needs to return a permission result:
Field descriptions:
If your application reads and applies the default permission mode from settings, consider performing your own product-level confirmation before executing high-risk modes. Modes like
Hooks suit teams already on the SDK hooks system that want finer-grained control across the tool lifecycle. Compared with the permission callback, hooks fit cross-cutting logic: auditing, alerting, unified interception, recording rejection reasons.
The main permission-related hooks are three types:
If a permission policy naturally belongs to one MCP server, declare tool-level permission policy right in the MCP server config. The policy travels with the server config instead of being scattered across global tool allow/deny lists.
Policy meanings:
query() session. It can restrict which tools are visible to the model, set default authorization policies, delegate tool execution approval to the host application, and apply new rules to the current session after user authorization.
Permission control isn't a single API but a set of options. Typically you decide which tools the session may use, then when those tools may execute, then wire in runtime approval, dynamic rule updates, settings, or hooks as needed.
Read, Grep, and Bash; Read and Grep are pre-approved; Bash is denied. In real projects, add the permission callback (canUseTool / can_use_tool) to route non-pre-approved operations to your product UI, approval system, or risk service.
Capability overview
Permission-related options fall into four groups. The first sets the default policy—plan mode, auto-accept edits, no interactive prompts. The second sets tool scope and rules. The third brings the host into runtime approval. The fourth covers advanced settings, hooks, and MCP tool policy.
| Problem to solve | Recommended entry (TypeScript / Python) | Notes |
|---|---|---|
| Set the session's default permission behavior | permissionMode / permission_mode | Decides how tool calls are handled when no explicit rule matches |
| Explicitly confirm skipping permission checks | allowDangerouslySkipPermissions / allow_dangerously_skip_permissions | Only with bypassPermissions or yolo |
| Restrict tools visible in this session | tools | Tools not included are not provided to the model |
| Pre-approve certain tools | allowedTools / allowed_tools | Matches usually skip the authorization prompt |
| Deny certain tools | disallowedTools / disallowed_tools | Matches are rejected; takes precedence over allow |
| Let the host approve tool calls | canUseTool / can_use_tool | The SDK host returns allow or deny at runtime |
| Hand approval to an external prompt tool | permissionPromptToolName / permission_prompt_tool_name | For runtimes that already provide a permission prompt tool |
| Update session rules after approval | PermissionUpdate | Commonly "allow once" or "always allow this session" |
| Allow access outside cwd | additionalDirectories / add_dirs | Extends the session's accessible directories |
| Provide permission rules from settings | settings | Suitable for static permission configuration at session start |
| Intercept or audit during the lifecycle | hooks | Suitable for advanced interception, auditing, and alerting |
| Declare tool policy on an MCP server | MCP tool policy | Declare per-tool allow/ask/deny in the MCP server config |
Quick Start: Host Application Approving Tool Calls
Use the permission callback when tool calls must go through your own approval logic. At runtime the SDK hands your callback the tool name, tool input, and a set of displayable approval details. Returning allow lets the tool run; deny rejects it.
read_order is an SDK MCP tool. When the model calls it, the full tool name is mcp__orders__read_order. The permission callback only allows this tool and returns the original input as the updated input. In TypeScript, returning toolUseID lets the runtime match the approval result to this exact tool call.
Controlling Default Policy: permissionMode
The permission mode (permissionMode / permission_mode) sets the session's default permission policy. It expresses "what mode this session is in overall"—plan first, auto-accept edits, reject without asking, or skip checks in controlled environments.
plan mode is designed for having the model produce a plan before making changes.
| Mode | Behavior |
|---|---|
default | Standard permission behavior. Tool calls are processed according to tools, allow/deny rules, dynamic approval, or runtime policy |
acceptEdits | Auto-accepts file edit operations; use this when workspace modification is confirmed |
bypassPermissions | Skips permission checks; requires the explicit skip confirmation as well |
yolo | Compatibility alias of bypassPermissions; also requires explicit confirmation |
plan | Plan mode; designed for producing an execution plan first; no actual changes by default |
dontAsk | No interactive prompts. Operations not pre-authorized or allowed by rules are denied |
auto | Runtime capability automatically determines allow or deny. Safe in-workspace file edits may be auto-approved |
bypassPermissions and yolo are high-risk modes. The SDK requires an explicit allowDangerouslySkipPermissions: true (Python: allow_dangerously_skip_permissions=True) so ordinary sessions can't accidentally skip permission checks.
Controlling Tool Scope: tools, allowedTools, disallowedTools
Tool control answers "which tools the model can see, and which are allowed or denied by default". The three fields often appear together but differ semantically.
Read, Grep, and Bash tools for this session; Read and Grep are pre-authorized; Bash is denied — even if the model wants to call it, it won't execute.
| Field (TypeScript / Python) | Effect | Best for |
|---|---|---|
tools / tools | Restricts the session's available tool set | Narrowing the model's capability surface |
allowedTools / allowed_tools | Adds allow rules | Letting low-risk tools skip repeated approval |
disallowedTools / disallowed_tools | Adds deny rules | Explicitly banning high-risk tools |
orders and tool named read_order, the full tool name is mcp__orders__read_order.
Runtime Approval: canUseTool
The permission callback suits hosts that take part in approval—showing permission requests in your own UI with "allow once", "always allow this session", or "deny"; or asking an enterprise risk service whether a command may run.
options parameter in TypeScript, on context in Python):
| Field | Description |
|---|---|
| Tool name | Full tool name, e.g. Read, Bash, mcp__orders__read_order |
| Input | The tool call's original arguments |
toolUseID / tool_use_id | This tool call's ID; in TypeScript, include it in the returned result |
signal | Fires when the authorization request is cancelled; UIs or remote approvals should watch it |
title / displayName / description | Runtime-generated human-readable text, ready for approval UIs |
suggestions | Runtime-suggested permission updates, usable for "always allow this session" |
blockedPath / blocked_path | The restricted path in path-related authorization scenarios |
decisionReason / decision_reason | Runtime-provided reasoning, for display or audit |
agentID / agent_id | The agent ID when a subagent initiated the tool call |
deny.message is required; it becomes part of the rejection reason for the model, logs, or host display. If the SDK receives a CLI authorization request without a configured permission callback, it returns an error—nothing is allowed by default.
When the permission system directly denies a tool call, a structured permission denial message may appear in the message stream:
dontAsk mode, auto-rejects, or rule rejects. Hosts can use them to update UI state or write audit logs.
Updating Permissions Within a Session: PermissionUpdate
PermissionUpdate updates the session's permission rules after an approval. The most common case is the user choosing "always allow this session" in the approval UI. Return the runtime's suggestions as-is, or construct explicit rules yourself.
| Type | Purpose |
|---|---|
addRules | Append allow, ask, or deny rules |
replaceRules | Replace rules |
removeRules | Remove rules |
setMode | Switch permission mode |
addDirectories | Append allowed access directories |
removeDirectories | Remove directory authorizations |
destination: 'session'). session only affects subsequent checks in this query session. For persistence at local/project/user level, prefer a settings-management flow over dynamic updates from a single approval callback.
Additional directories
By default the session treats cwd as the primary working directory. When the model must read or modify directories outside cwd, pass them explicitly (TypeScript: additionalDirectories; Python: add_dirs).
/repo/app, and the model is also allowed to access /repo/packages/shared. This works well for monorepos, cross-repository debugging, shared library investigation, and similar scenarios.
During execution, directory authorization can also be adjusted via PermissionUpdate:
External Authorization Tool: permissionPromptToolName
This option (TypeScript: permissionPromptToolName; Python: permission_prompt_tool_name) hands permission requests to a permission prompt tool in the runtime environment instead of implementing the permission callback in the SDK host. It suits existing external approval tools, remote runtimes, or unified permission gateways.
- It must be a prompt tool name the current runtime recognizes.
- It is mutually exclusive with the permission callback (
canUseTool/can_use_tool). - When the SDK host itself decides approvals, prefer the permission callback.
allow.updatedInput is the final parameters used when executing the tool. If you want to keep the original parameters, return the received input as-is. deny.message is required. interrupt: true means deny and also interrupt the current Agent flow.
Using settings to Provide Permission Rules
settings provides static permission configuration before the session starts. It beats the permission callback at expressing "what this project allows, denies, and which extra directories exist".
| Field | Description |
|---|---|
permissions.allow | Allow rules |
permissions.deny | Deny rules |
permissions.ask | Always-ask rules |
permissions.defaultMode | Default permission mode |
permissions.disableBypassPermissionsMode | Set to 'disable' to disable bypass permissions mode |
permissions.additionalDirectories | Additional accessible directories |
bypassPermissions and yolo should only appear in explicitly trusted environments.
Using hooks for Advanced Interception and Auditing
Hooks suit teams already on the SDK hooks system that want finer-grained control across the tool lifecycle. Compared with the permission callback, hooks fit cross-cutting logic: auditing, alerting, unified interception, recording rejection reasons.
| Hook | Trigger Timing | Common Use |
|---|---|---|
PreToolUse | Before tool invocation | Pre-allow, deny, request ask, or pass to subsequent flow |
PermissionRequest | When entering a permission request | Return allow or deny directly before the normal prompt |
PermissionDenied | After permission is denied | Auditing, alerting, recording denial reasons |
PreToolUse can return:
PermissionRequest can return a permission result similar to tool approval:
PermissionDenied is typically used for observing results, not for allowing tools. Its input includes the denied tool name, tool input, tool invocation ID, and denial reason.
MCP Tool Policy
If a permission policy naturally belongs to one MCP server, declare tool-level permission policy right in the MCP server config. The policy travels with the server config instead of being scattered across global tool allow/deny lists.
| Policy | Behavior |
|---|---|
always_allow | Matched tool is directly allowed |
always_ask | Matched tool enters authorization flow |
always_deny | Matched tool is directly denied |
name can be the MCP tool's original name or the full tool name, e.g., mcp__repo_tools__search. During actual matching, the runtime maps policy names to the current MCP tool invocation.