Permissions
pw code decides what it may do on its own and what needs your approval through four layers: a permission mode that sets the overall level of autonomy, a shell command check that blocks or flags risky commands, allow rules that pre-approve specific tools and commands, and a workspace boundary that keeps file access inside the directory you started in.
Permission Modes
A session runs in one of four modes. The default is accept-edits. Each mode sets what the agent may do across reads, file edits, shell commands, and MCP tools (tools from connected MCP servers).
| Mode | Reads & searches | File edits | Shell commands | MCP tools |
|---|---|---|---|---|
read-only | Allowed | Denied | Inspect-only commands run; others prompt; writes blocked | Denied |
accept-edits (default) | Allowed | Allowed | Prompt each time | Prompt each time |
plan | Allowed | Plan files only | Inspect-only commands run; others prompt; writes blocked | Denied |
bypass-permissions | Allowed | Allowed | Allowed | Allowed |
Inspect-only commands are ones that only report state, such as ls, cat, grep, rg, jq, find (without -exec or -delete), read-only git subcommands (status, log, diff, show, blame, fetch, ...), go test, go vet, go build, and gh subcommands such as view, list, and diff. In read-only and plan, a command made only of these runs without asking, a command pw code does not recognize asks first, and a command that writes is blocked: file writes, output redirection, sed -i, and git commands that change the repository.
Running a notebook cell (NotebookRun) prompts in accept-edits and is denied in read-only and plan.
bypass-permissions runs everything
In bypass-permissions mode every tool call executes without prompting, including shell commands and file access outside the workspace. Use it only where that is acceptable, such as disposable environments or automation.
Plan Mode
Plan mode lets the agent work out an approach before changing anything. It may read, search, fetch web pages, track todos, ask you questions, use skills, and delegate research to subagents. File edits are restricted to plan documents (PLAN.md, plan.md, or Markdown files inside a plans/ directory), shell commands follow the inspect-only rules above, and every other tool is denied. Allow rules have no effect in plan mode.
Setting the Mode
-
At startup: pass the
--permission-modeflag:pw code --permission-mode read-only -
During a session: press Shift+Tab to cycle
read-only→accept-edits→bypass-permissions→plan. The status line below the composer shows the current mode, and you can cycle it even while the agent is working. The new mode applies to its next tool call. -
In the settings menu: run
/settingsand activate the Permission mode row, which cycles through the same order. -
In your settings file: set the
permissionModekey. See Settings.
Mode changes made with Shift+Tab or /settings are saved as your default for future sessions. A resumed session starts in the mode it last ran in, and the --permission-mode flag overrides both. See Mode Precedence.
Shell Command Checks
Before a shell command runs, pw code checks it against known risky patterns. These checks apply on top of the mode, and allow rules do not change them.
| Category | Examples | read-only, plan | accept-edits | bypass-permissions |
|---|---|---|---|---|
| Privilege and system | sudo, shutdown, systemctl, launchctl, useradd, iptables, mount, crontab | Blocked | Blocked | Allowed |
| System state | apt, yum, brew, pip install, npm install -g, go install, cargo install, docker run, docker rm, docker compose up, kubectl apply, kubectl delete, terraform apply, terraform destroy | Blocked | Blocked | Allowed |
| Destructive | rm -rf, shred, truncate, dd of=, mkfs, chmod -R, chown -R, git reset --hard, git clean -f, git push --force, git checkout -- . | Blocked | Prompt | Allowed |
Shell commands time out after 2 minutes by default. The agent can ask for up to 10 minutes, or run a long command in the background.
Approval Prompts
In the default accept-edits mode the agent reads and edits workspace files freely but stops before every shell command and MCP tool call that no allow rule covers. The prompt shows the exact command and why it needs approval:
- Yes, allow this command: run it once. The next command prompts again.
- Yes, and don't ask again for:
<rules>: shown for ordinary shell prompts. Run it and save the suggested allow rules for this repository. The rules are editable before you confirm; separate several with commas. - Yes, and allow
<dir>for the session: shown when a file read, write, or search reaches outside the workspace. Run it and allow that directory for the rest of the session. - No, deny this command: skip it. The agent is told the command was denied.
- No, and provide feedback to the agent: deny it and type an explanation the agent can act on.
Pressing Esc also denies the command. Approving a shell command never grants a directory.
The prompt names the tool that asked and words its rows for it. A shell prompt shows the Command. A notebook prompt shows the whole Code to run in the kernel, with Yes, run this code and No, don't run this code. An outside-workspace file prompt shows the Path, with Yes, allow this once and No, deny. Other tools, such as MCP tools, show the full Call with its arguments, with Yes, allow this call and No, deny this call. Prompts that a hook forces show the same way.
Some prompts appear even when an allow rule matches, in every mode except bypass-permissions:
- Destructive commands.
- Commands that write outside the workspace, run with a working directory outside it, or set environment variables.
- Changes to
pw code's own configuration (see Protected Configuration).
In non-interactive mode there is no way to prompt, so actions that would require confirmation fail instead. Pre-approve them with allow rules, --add-dir, or --permission-mode bypass-permissions.
Allow Rules
Allow rules pre-approve specific tool calls so they never prompt. Manage them from inside a session with /permissions:
/permissions # list the rules in effect, by source
/permissions add Bash(git status:*) # add a rule for this repository
/permissions add user Bash(go test:*) # add a rule for every workspace
/permissions remove Bash(git status:*)
/permissions remove 2 # or remove by its number from the list/permissions add takes an optional scope before the rule:
| Scope | Saved to |
|---|---|
local (default) | <repo-root>/.agents/settings.local.json, for this repository only |
project | <workspace>/.agents/settings.json, shared with the repository |
user | ~/.config/pw/code.json, for every workspace |
Rules take effect immediately. A local or project rule added before you approve the workspace's settings applies to this session only until you approve them at launch. /permissions remove deletes the rule from every file it is saved in. A rule that came from --allowedTools is removed for the current session only.
Rules are stored under permissions.allow in settings, and rules from every settings file and the repeatable --allowedTools flag are combined:
pw code --allowedTools 'ReadFile' --allowedTools 'Bash(git status:*)'Rule Syntax
| Rule | Effect |
|---|---|
ReadFile | A bare tool name allows every call of that tool. |
Bash(git status:*) or Bash(git status *) | A command prefix with any arguments: here git status alone or followed by anything. |
ReadFile(/data/**) | The /** suffix matches a directory and everything under it. Path-scoped rules on file tools also grant access outside the workspace. |
ReadFile(/data/*.csv) | Other patterns are matched as globs. |
mcp__docs__search | An MCP tool, by its full tool name. |
For Bash the rule is tested against the command; for other tools, against the path, file_path, or url argument. Every part of a compound command must match a rule: git status && curl example.com only runs unprompted if both git status and curl example.com are allowed. Commands containing command or process substitution ($(...), backticks, <(...), >(...)) are never auto-approved.
A bare tool rule such as ReadFile suppresses prompts for normal calls but does not widen the tool's reach: reads outside the workspace still require a path-scoped rule, --add-dir, or your approval.
In read-only mode an allow rule can approve a call the mode would otherwise deny or prompt for, but shell commands the checks above block stay blocked.
Workspace Boundary
The agent works within your workspace: the directory you start pw code in, or the one passed with --workspace. Paths are fully resolved before they are checked, so symlinks cannot escape the boundary.
When the agent tries to read, write, or search outside the workspace, it asks first. Choosing Yes, and allow <dir> for the session allows that directory, so further access there does not prompt again. To grant access up front:
--add-dir <path>(repeatable) lets the agent read, search, and edit in that directory for the whole session.- Path-scoped allow rules such as
ReadFile(/data/**)orWriteFile(/tmp/**)grant persistent access.
pw code --add-dir /data --add-dir /shared/resultsIn bypass-permissions mode, outside-workspace access is allowed without prompting.
Commands you type yourself in shell mode (the ! prefix) run outside the agent's permission system entirely.
Protected Configuration
Changes to the files that decide what pw code may do always ask first, in every mode except bypass-permissions, whether the agent uses a file tool or a shell command. No allow rule or directory grant lifts this. The protected paths are:
<workspace>/.mcp.jsonand everything under<workspace>/.agents/- The repository's
.agents/settings.local.jsonand the skill directories of parent folders ~/.config/pw/,~/.config/agents/, and~/.agents/
Inspect-only commands that just read these files keep the ordinary prompt rules.
Web Access
WebFetch only fetches http:// and https:// URLs. It follows up to 10 redirects, gives up after 30 seconds, and reads at most 2 MB of a response. It refuses private, loopback, and link-local addresses, so the agent cannot use it to reach services on your machine or network.
Remote Turns
A turn sent from the web app through remote control runs at most at the remote permission ceiling (accept-edits by default), even if the session is in a wider mode. Remote turns do not use your allow rules or the directories approved for the session, so their actions prompt as if no rule existed. Changes to protected configuration from a remote turn are approved in person, even in bypass-permissions.
Subagents and Permissions
- Inherited at spawn: subagents get the session's permission mode, allow rules, and
--add-dirdirectories. - Live changes reach them: changing the session's mode (for example with Shift+Tab) applies to running subagents immediately, in both directions.
- Definitions only narrow: a custom agent definition can restrict a subagent's mode or tools but never widen them past the session; see Permission Clamping for the exact rules.
- Approvals stay per-subagent: an approval prompt names the agent asking, and what you approve applies to that subagent only. Cycling the mode inside a subagent's window adjusts that subagent alone, still capped by the session.
Related Documentation
- pw code Overview: Feature overview and quick start
- Settings: The
permissionModeandpermissions.allowkeys - Hooks: Approve, deny, or ask for tool calls from your own scripts
- Slash Commands:
/permissionsand other in-session commands - Non-Interactive Mode: How approvals behave in one-shot runs
- Subagents: Delegated tasks and inherited permissions
- Custom Agents: Narrowing permissions per agent
- Remote Control: Driving sessions from the web app
- MCP Servers: How MCP tools are configured and approved
- Interface & Shortcuts: Keyboard shortcuts including Shift+Tab