Kiro uses a capability-based permissions system that gives you fine-grained, declarative control over what the agent can do. You define rules per capability with match patterns and explicit effects, replacing older binary trust models.
| Capability | IDE | CLI | Web | Mobile |
|---|---|---|---|---|
| Permissions YAML configuration | ✓ | ✓ | N/A | — |
| Interactive approval prompts | ✓ | ✓ | N/A | — |
| Global + workspace scopes | ✓ | ✓ | N/A | — |
| Managed cloud sandbox instead of permission prompts | N/A | N/A | ✓ | — |
On Web, the permissions.yaml model and interactive approvals do not apply: the agent runs inside an isolated cloud sandbox instead of prompting per action, so those rows are marked N/A rather than unsupported.
The permissions system is built around three core concepts:
| Concept | Description |
|---|---|
| Capabilities | fs_read, fs_write, shell, web_fetch, web_search, mcp, subagent, skill, power, context, diagnostics, sandbox_network. Meta-capabilities expand: all (every capability except sandbox_network), builtin (all built-in tools), filesystem (fs_read + fs_write) |
| Effects | deny (block always), ask (prompt you), allow (proceed silently), evaluate (Kiro judges the action; the weakest effect, added by the approve-for-me preset and active only when the trust classifier is available) |
| Priority | deny > ask > allow > evaluate - a deny rule always wins regardless of scope. sandbox_network host rules are the exception; see Sandbox network rules |
Additional rule properties:
| Property | Description |
|---|---|
| Match patterns | Glob patterns scoping the rule (file paths for fs, command prefixes for shell, server/tool names for MCP) |
| Exclude | Optional glob patterns that must NOT match - enables "allow everything except X" |
The sandbox_network capability applies only when the local command sandbox is active. Its allow and deny rules name the hosts that sandboxed shell commands can reach, and your fs_read and fs_write rules shape which paths those commands can see and write. It is excluded from the all meta-capability.
Host filtering does not use deny-overrides. sandbox_network rules are applied in order and the first rule that matches the host decides, so a specific deny must come before a broader wildcard allow that also matches. Deny-overrides still governs whether the agent may run a tool action. See Local command sandbox for host patterns and network modes.
Permissions are defined in YAML files at two levels:
User-scoped (~/.kiro/settings/permissions.yaml) - applies across all projects. Use to pre-approve trusted operations:
rules: - capability: shell match: ["git *", "npm *", "npx *"] effect: allow - capability: fs_write match: ["src/**", "tests/**"] effect: allow - capability: fs_read effect: allow - capability: mcp match: ["my-server/*"] effect: allow
Workspace-scoped (~/.kiro/workspace-roots/<hash>/permissions.yaml) - applies only to a specific project. Use to scope rules to one codebase:
rules: - capability: fs_write match: ["*.env", "*.pem", "*.key"] effect: deny - capability: shell match: ["rm -rf *", "sudo *"] effect: deny
Both scopes support all effects (deny, ask, allow, and evaluate).
Rules support an exclude field for "allow everything except" patterns:
rules: - capability: mcp match: ["my-server/*"] exclude: ["my-server/dangerous-tool"] effect: allow
Rules use glob patterns. The syntax differs by capability type:
Filesystem patterns (fs_read, fs_write):
* matches within a single path component** matches across path separators{a,b} brace expansion and [abc] character classes are supported~/temp matches ~/temp/childShell, web, and MCP patterns:
* matches any sequence of characters**, ?, and character classes are not supportedrules: # Allow npm commands except npm publish - capability: shell effect: allow match: - "npm *" exclude: - "npm publish*" # Deny reads to secrets at any depth - capability: fs_read effect: deny match: - "**/.env" - "**/.env.*" - "secrets/**" - "**/*.pem"
Shell commands are parsed before pattern matching. Compound commands (using ;, &&, ||, |) are split and each sub-command is evaluated independently. This prevents a rule for npm test * from accidentally matching npm test ; curl attacker.com.
The parser evaluates flags inside combined short options, so a command such as grep -iP still prompts when one of its flags requires approval. Options that can launch another program are never treated as read-only: tar --use-compress-program and tar --to-command require approval even when the base tar command is trusted.
In Kiro IDE 1.4.51 or later and Kiro CLI V3 sessions, Kiro blocks bash or PowerShell commands it cannot parse well enough to check against your permission rules. It asks the agent to rewrite the command instead of asking you to approve an unchecked command. Commands for cmd.exe still ask for approval. A rule that asks about every shell command still shows its normal prompt when no shell deny rule applies. An unconditional allow or deny rule still decides without parsing. If a valid command remains blocked after a few rewrites, the agent tells you it could not check the command.
Permissions are evaluated across multiple scopes. The table lists the scopes you configure or encounter directly; it is not an inventory of every scope the permission engine defines.
| Scope | Location | Allowed effects |
|---|---|---|
| Kiro | Hardcoded security invariants (cannot be changed by configuration) | deny, ask |
| administration | Enterprise permission policies in managed-settings.json | deny, ask |
| user | ~/.kiro/settings/permissions.yaml | deny, ask, allow, evaluate |
| workspace | ~/.kiro/workspace-roots/<hash>/permissions.yaml | deny, ask, allow, evaluate |
| agent | Embedded in agent profile (permissions field) | deny, ask, allow, evaluate |
| session | In-memory rules from consent decisions during the session | deny, ask, allow, evaluate |
Rules are evaluated using a deny-overrides algorithm: deny > ask > allow > evaluate. There is no precedence between scopes - the most restrictive effect wins regardless of which scope it came from. evaluate is the effect the approve-for-me preset adds when it is listed under policies: in a user or workspace permissions file; see Policy presets. sandbox_network host filtering is the exception: it applies rules first-match, as described in Sandbox network rules.
Kiro checks each sub-agent tool call against the parent session's policy and the sub-agent's own permissions. The stricter result wins:
deny from either policy denies the call.ask rule in either policy prompts you.A call that the sub-agent's rules don't mention follows the parent session's policy. A sub-agent's allow rules never grant more than the parent session allows. A subagent capability rule only controls whether a sub-agent can start without a prompt. See Sub-agent permissions.
Policy presets are named, composable sets of rules. Every preset except approve-for-me consists only of allow rules. A preset reaches a session by one of two paths, and the path decides its scope:
policies: in a user or workspace permissions.yaml is expanded at that file's scope and persists with the file. In Kiro CLI 2.36 or later, this is how the approve for me option under /permissions turns on approve-for-me: it writes the preset to the workspace permissions file.approve-for-me is the exception to allow-only. It adds an evaluate rule for every capability on top of a bounded set of allow rules, and it depends on Kiro's trust classifier: when the classifier is unavailable, the preset contributes no rules and the session keeps asking. Turn it on with the approve for me option under /permissions in a Kiro CLI V3 session, where that option appears; see Approve for me.
An ACP client requests presets in the _meta.kiro.policyPreset field of a session/new or session/load request. Multiple presets can be combined; their rules are merged as a union.
{ "_meta": { "kiro": { "policyPreset": ["edit-workspace", "dev-shell"] } } }
Client-requested preset rules are seeded into the session when the client opens it, separately from the rules you configured in permissions.yaml. This is why a session's active rules can include entries you never wrote.
Requesting an unknown preset ID rejects the session request. There is no silent fallback to a default policy.
| Preset ID | Rules it contributes |
|---|---|
allow-all | Every capability except sandbox_network (equivalent to capability: all, effect: allow) |
edit-workspace | fs_read and fs_write within ./** only |
read-workspace | fs_read within ./** only |
read-all | fs_read anywhere, plus web_fetch and web_search |
read-only-shell | Read-only shell commands: system info plus git, cargo, npm, docker, kubectl, and rustup queries |
dev-shell | Read-only shell commands (the read-only-shell set) plus git write commands; build tools cargo, npm, bun, yarn; workspace ops mkdir, touch, mv, cp; inspection commands ls, cat, grep, echo |
approve-for-me | The edit-workspace and read-only-shell sets, plus an evaluate rule for every capability, so Kiro judges each action that no deny, ask, or allow rule settles. Requires the trust classifier; when it is unavailable, this preset contributes no rules. In Kiro CLI 2.36 or later, choosing approve for me under /permissions in a V3 session lists this preset under policies: in the workspace permissions file, so its rules apply at workspace scope; see Approve for me |
The allow-only presets remove prompts for the operations a session is meant to perform, and everything else keeps the default of asking for approval. Pick the narrowest profile that matches the session's job. approve-for-me is not in this table: it is chosen under /permissions in a Kiro CLI V3 session, which lists it in the workspace permissions file rather than requesting it for one session, and it only takes effect when the trust classifier is available.
| Session profile | Presets | What you get |
|---|---|---|
| Code review or audit | read-workspace | Workspace files are read silently. Writes and shell commands still ask, so the session prompts before any change. |
| Investigation and research | read-all | File reads anywhere on disk, plus web_fetch and web_search, for sessions that trace an issue across code and external documentation without needing write access. |
| Diagnostics and triage | read-workspace + read-only-shell | The agent reads workspace files and queries git, docker, kubectl, and other tool state. Nothing grants a write, so every change still asks. |
| Autonomous build-and-test loop | edit-workspace + dev-shell | The agent edits workspace files, runs git write commands and the standard build tools, and creates or moves files in the workspace without a prompt per action. Writes outside the workspace and unlisted commands still ask. |
| Disposable sandbox | allow-all | Every capability is allowed. Use it where the environment itself is the boundary, such as a container that is discarded after the run. |
Each profile is requested the same way: the preset IDs go in the policyPreset array of the session request. A code review bot opens its session with:
{ "_meta": { "kiro": { "policyPreset": ["read-workspace"] } } }
A diagnostics session pairs workspace reads with read-only shell queries:
{ "_meta": { "kiro": { "policyPreset": ["read-workspace", "read-only-shell"] } } }
A CI harness that edits, builds, and tests combines the two write-capable presets:
{ "_meta": { "kiro": { "policyPreset": ["edit-workspace", "dev-shell"] } } }
deny rules and the Kiro scope invariants below still apply regardless of which profile is active.
The same profiles map onto common integration patterns. An editor integration that embeds Kiro typically requests edit-workspace so in-workspace file edits do not prompt. A code review bot requests read-workspace and nothing more. A CI or evaluation harness driving the agent programmatically combines edit-workspace with dev-shell, then adds its own deny rules for anything the pipeline must never touch.
Presets extend what a session is allowed to do, but they cannot override higher-precedence rules. The deny-overrides algorithm described in the Scopes section above still applies in full:
~/.kiro/settings/, .kiro/settings/, ~/.kiro/workspace-roots/, .kiroignore, and the other stores listed under Default behavior) block the action regardless of any preset..git/**, .vscode/**, **/*.code-workspace, and the agents, hooks, workflows, and powers directories under .kiro and ~/.kiro) still prompt, even when a preset grants broad write access.deny rule you have configured at the user, workspace, or administration scope wins over a preset allow.sandbox_network capability is not part of the all meta-capability, so no preset, including allow-all, changes sandbox network gating.Without any permissions.yaml configured, the default agent policy allows:
fs_read on ./** - read any workspace file silentlyshell for common git read-only commands - git status, git log, git diff, git branch, and similarshell for system info commands - pwd, whoami, uname, and similarThe Kiro scope (hardcoded, not changeable by configuration) enforces:
~/.kiro/settings/, .kiro/settings/, and ~/.kiro/workspace-roots/ (prevents the agent from modifying its own permission files), to .kiroignore at any depth (it defines the agent's own read boundary), to the MCP configuration of an installed Power (~/.kiro/powers/installed/<name>/mcp.json), and to Kiro's own state stores (~/.kiro/sandbox-state/, ~/.kiro/web-session/, ~/.kiro/cloud-cache/, ~/.kiro/sandbox-curl/).git/**, .vscode/**, **/*.code-workspace, and the agents, hooks, workflows, and powers directories of both the workspace .kiro and ~/.kiro. These ask in trusted and untrusted workspaces alike, and no allow rule from any scope removes the prompt, with one exception inside the managed cloud sandbox described under Workspace trust..kiro/steering, .kiro/skills, .kiro/extensions, the .kiro/specs directory itself, and any .kiro directory Kiro does not declare, even when a saved rule allows the write. See Workspace trust.Everything else prompts for approval. Creating a permissions.yaml adds to these defaults; it does not replace them.
Some agent inputs live inside the repository you open: custom agent profiles in .kiro/agents/, Steering files in .kiro/steering/, workspace MCP server configuration, Skills, and Workflow files. A cloned repository could use them to change how the agent behaves, so Kiro treats a workspace as untrusted until you trust it. Your decision is stored outside the workspace, so a repository cannot change its own trust status.
Until you trust a workspace, Kiro:
deny rule still refuses.autoApprove allows it, and asks again when a call is retried after MCP authentication or a URL prompt. A matching deny rule still refuses..kiro/steering, .kiro/skills, .kiro/extensions, the .kiro/specs directory itself, or any .kiro directory Kiro does not declare, in both the workspace and ~/.kiro, even when a saved rule allows the write. Writes to the agents, hooks, workflows, and powers directories ask in every workspace.~/.kiro/memories/ and to the agent's session store (~/.kiro/sessions/ by default) without prompting, so an untrusted session cannot rewrite another session's state.Your user, administration, agent, and session rules still apply, and so does the per-workspace store under ~/.kiro/workspace-roots/: it lives outside the repository, so it loads regardless of trust.
Trust changes one tier of .kiro writes and leaves the others alone. The table applies to both the workspace .kiro and ~/.kiro; files under .kiro/specs/ follow your ordinary rules.
Path under .kiro | Untrusted workspace | Trusted workspace |
|---|---|---|
steering, skills, extensions, the specs directory itself, any directory Kiro does not declare | Asks, even when a saved rule allows the write | Follows your rules |
agents, hooks, powers, workflows | Asks | Asks, except as described under the fs_write exception below |
settings | Refused | Refused |
A matching deny rule wins in every row.
One rule lifts the untrusted-only asks for .kiro directories: an fs_write allow rule in your own ~/.kiro/settings/permissions.yaml with no match restriction and no exclude. It does not remove the always-ask paths, does not override a matching ask or deny, and does not load the untrusted workspace inputs listed above. One environment widens that rule: in a trusted workspace inside the managed cloud sandbox that cloud sessions run in, the same unrestricted user-level fs_write allow also lifts the always-ask prompts for .git/**, .vscode/**, **/*.code-workspace, and the agents, hooks, workflows, and powers directories. Outside the cloud sandbox, those paths ask in every workspace.
In Kiro CLI 2.33 or later, an interactive V3 session shows a Trust this workspace? screen the first time you start Kiro CLI in a folder, before it loads the folder's hooks, agents, MCP servers, steering, workflows, or language server configuration. Non-interactive runs (--no-interactive) and V1 and V2 sessions are not gated: they load workspace configuration without asking, as before. The screen is specific to Kiro CLI.
Not trusted: <folder>. Kiro exited without loading this folder.workspaceTrusted in the per-workspace permissions file under ~/.kiro/workspace-roots/, so the screen appears once per folder. The screen names the exact file.When the folder is your home directory, the screen notes that its .kiro configuration is your user-level configuration, and the answer lasts for that session only. Trust for your home directory is never saved, so Kiro asks at every launch there.
In Kiro CLI 2.34 or later, pass --trust-workspace to trust the current folder for one V3 launch. The flag skips the prompt and does not save workspaceTrusted, so a later launch asks again unless you previously saved trust for that folder.
To revoke trust, remove the workspaceTrusted line from the file the screen named; the next launch in that folder shows the screen again. To confirm a folder is trusted, start Kiro CLI in it again: the screen does not appear and the session starts with the folder's configuration loaded.
In addition to permissions.yaml rules, the IDE's agent autonomy is controlled via Settings → Agent → Agent Autonomy (settings key: kiroAgent.agentAutonomy). The two modes are:
The capability-based permissions layer applies after the autonomy mode determines whether to proceed. Together, these two layers give you coarse-grained control (Autopilot vs Supervised) plus fine-grained rules (permissions.yaml) for specific capabilities.
When a tool requires approval, a prompt appears in chat. Allow and Deny are available for the current invocation. Kiro also shows persistent choices when it can derive a saved rule that will work for the requested command:
| Action | Effect |
|---|---|
| Allow | Approve this specific invocation once |
| Always allow | Create a persistent allow rule (opens pattern/scope picker) |
| Deny | Block this specific invocation once |
| Always deny | Create a persistent deny rule |
If Kiro cannot verify a working saved rule, it hides Always allow and Always deny and explains why in the prompt.
When you select Always allow or Always deny, you configure two things:
cd * for any cd command, or the exact command path)~/.kiro/settings/permissions.yaml~/.kiro/workspace-roots/<hash>/permissions.yaml (per-user, outside the repository). In Kiro IDE, when the window has more than one workspace folder, this choice reads This workspace folder (folder-name), so you can see which folder the rule is saved for. The label does not change how the rule is enforced: shell command rules still apply to the whole session. In Kiro IDE, the choice is also hidden for files and folders outside every workspace folder.The pattern dropdown suggests a generalized version of the specific operation - for example, exact command git add contents/docs/ becomes pattern git add *, and exact path .env.local becomes .env* or **/.env*. You can edit the suggestion to be more restrictive or more permissive.
For chained commands (e.g., cd /path && cargo build), each sub-command in the chain is presented separately for approval.
Here are common patterns for configuring permissions:
| Scenario | Configuration |
|---|---|
| Trust file reads | capability: fs_read, effect: allow |
| Trust write in project dirs | capability: fs_write, match: ["src/**", "tests/**"], effect: allow |
| Block sensitive files | capability: fs_write, match: ["*.env", "*.pem", "*.key"], effect: deny |
| Block dangerous commands | capability: shell, match: ["rm -rf *", "sudo *"], effect: deny |
| Trust specific MCP server | capability: mcp, match: ["my-server/*"], effect: allow |
| Require approval for shell in production | capability: shell, effect: ask |
If you're upgrading from CLI 2.x or IDE 0.x, see the reference pages for how permissions worked previously and what changed:
Permissions