Permission Modes
Permission modes determine how Qoder handles tool calls — each mode balances automation and security differently.| Mode | Best for | Behavior |
|---|---|---|
default | Normal interactive use | Safe reads and internal actions run automatically; sensitive actions require confirmation. |
accept_edits | Routine coding tasks | Automatically approves safe file edits inside working directories. Shell commands, external actions, and sensitive paths still go through normal checks. |
auto | Autonomous runs, Goal execution | Zero prompts. Safe reads and workspace edits are auto-approved; risky actions are denied or evaluated by the AI classifier. |
bypass_permissions (YOLO) | Trusted local experiments only | Skips all approval prompts. All tool calls are allowed automatically. |
dont_ask | Headless flows that must not prompt | Never prompts. Any action that would normally ask is denied instead. |
Plan Mode
Plan is an independent work state (not a permission policy) that can coexist with any permission mode above. Toggle it with the/plan command. While active, Qoder explores code in read-only mode and outputs proposals; writes are restricted to plan files. On exit you can choose a follow-up permission mode or start a Goal execution.
Goal Mode
Goal is an autonomous execution state. Enter via/goal set <objective> — this automatically switches to auto mode and locks Shift+Tab switching to ensure zero-interruption execution. Goal can coexist with Plan (plan first, execute second). Exit with /goal clear or /goal pause.
Mode Cycling
In interactive sessions, press Shift+Tab to cycle through all permission modes. Press Ctrl+Y to jump directly to YOLO mode.Startup Parameters
Use--permission-mode to set the default behavior for the current session:
| Standard (snake_case) | camelCase | Alias |
|---|---|---|
accept_edits | acceptEdits | — |
bypass_permissions | bypassPermissions | yolo, YOLO |
dont_ask | dontAsk | — |
default.
How Decisions Are Made
Qoder checks permissions before every tool call. The result is always one of three outcomes:allow: Execute the tool immediately.ask: Requires external confirmation before execution.deny: Block the tool call.
Decision Order
Qoder evaluates permissions in a fixed order:- Check
denyrules first — if matched, deny immediately. - Tool’s own safety checks (e.g., dangerous command detection, sensitive path detection).
askrules — if matched, mark as requiring confirmation.- Tool-level
allowrules and mode-based auto-allow behavior. - If the final result is still
ask, the runtime environment determines how to consume it.
How ask Is Consumed in Different Environments
| Environment | ask outcome | Notes |
|---|---|---|
| TUI (interactive terminal) | Confirmation prompt | User selects allow/deny in the terminal. |
Headless (-p/--prompt) | Auto-deny | No interaction available; ask becomes deny. |
| SDK (stdio protocol) | Sends canUseTool callback to host | Host program decides allow/deny. |
| ACP (IDE integration) | Sends requestPermission RPC to IDE | IDE prompts or auto-decides. |
-p/--prompt) can be combined with permission modes:
Permission Configuration
Configuration Sources (8-Layer Priority)
Rules merge from multiple sources, from lowest to highest priority:| Layer | Source | Description |
|---|---|---|
| 1 | userSettings | ~/.qoder/settings.json (user global) |
| 2 | projectSettings | <project>/.qoder/settings.json (project-level, team-shared) |
| 3 | localSettings | <project>/.qoder/settings.local.json (machine-local, add to .gitignore) |
| 4 | flagSettings | --settings <path> CLI argument specifying an additional file |
| 5 | policySettings | Organization policy (managed, highest persistent source) |
| 6 | cliArg | --allowed-tools / --disallowed-tools CLI arguments |
| 7 | command | /allow, /deny in-session commands |
| 8 | session | Runtime temporary rules (“Allow for this session” in prompts) |
allowManagedPermissionRulesOnly, only policy-managed rules are used.
How each source is configured:
- Layers 1-3 (settings files): Write
permissions.allow/permissions.deny/permissions.askarrays in the corresponding JSON file.settings.local.jsonis ideal for machine-local approval rules; add it to.gitignore. - Layer 4 (flagSettings):
qodercli --settings ./custom-settings.jsonspecifies an additional settings file. Same format as standard settings.json. - Layer 5 (policySettings): Distributed by organization admins via the policy system; cannot be overridden locally.
- Layer 6 (cliArg): Configured via
--permission-mode,--allowed-tools,--disallowed-tools,--toolsCLI arguments; applies to current session only. - Layer 7 (command): Type
/allow Bash(npm test)or/deny WebFetchin-session; persisted tosettings.local.json. - Layer 8 (session): Temporary rules from selecting “Allow for this session” in prompts; lost when the process exits.
Mode Configuration
Set default mode — configuregeneral.defaultPermissionMode in settings:
--yolo, --permission-mode bypass_permissions, and Ctrl+Y are all disabled, and the Shift+Tab cycle skips this mode. Sub-agents declaring bypass are also downgraded to acceptEdits.
Disable Plan mode — if the Plan workflow is not needed:
/plan command is unavailable, --permission-mode plan falls back to default, and EnterPlanMode/ExitPlanMode tools are not registered.
Auto mode classifier configuration — guide the AI classifier’s decisions with natural language rules:
| Field | Purpose |
|---|---|
allow | Operation descriptions the classifier tends to auto-approve |
soft_deny | Operation descriptions the classifier tends to deny |
environment | Environment context provided to the classifier |
autoMode configuration is only read from trusted sources (user global settings and localSettings); project settings are excluded to prevent malicious privilege escalation.
Permission Rule Configuration
Rules are grouped underallow, ask, and deny:
Rule Syntax
| Form | Meaning |
|---|---|
ToolName | Applies to the entire tool. |
ToolName(content) | Applies to a specific path, command, agent type, or other tool-specific value. |
* | Matches all tools. |
Read, Edit, Write, Bash, Grep, Glob, WebFetch, WebSearch, Agent, and MCP names like mcp__github__create_issue.
If the content contains parentheses, escape them:
ToolName(*) is equivalent to ToolName (tool-level rule).
Command-Line Overrides
--allowed-tools and --disallowed-tools use the same rule syntax as settings. --tools restricts the available built-in tool set for the current run (unlisted tools are denied).
Trust Directories
Qoder treats the startup current working directory (CWD) as the main trust directory. Within trusted directories:- File reads are allowed by default
- File writes can be auto-approved in
accept_editsandautomodes - Non-default permission modes (auto, bypass, etc.) are allowed to take effect
default mode.
Extending Trust
Add additional trusted working directories via--add-dir, the /add-dir command, or permissions.additionalDirectories:
permissions.trustDirectories in global settings to permanently trust frequently-used directories.
Protected Paths
Some paths are protected because editing them can change execution behavior, credentials, or tool behavior. Examples include.git, .vscode, .idea, .husky, most .qoder configuration files, shell startup files like .bashrc/.zshrc, Git config, .mcp.json, and .ripgreprc. In normal interactive modes these paths require explicit approval; in auto mode they are denied.
File Access Rules
Path-scoped read rules useRead(...). Path-scoped write rules use Edit(...); they cover file editing and writing checks for Edit, Write, and NotebookEdit. An Edit(...) allow rule also implies read permission for the same path.
File rules use gitignore-style matching.
| Pattern | Meaning |
|---|---|
/src/** | Rooted at the rule source’s root directory. In project/local settings, relative to project root; in user settings, relative to home directory. |
~/Documents/** | Home-directory-based path. |
//tmp/data/** | Absolute path from system /. Use double slash for absolute paths. |
*.secret | Rootless filename pattern that matches at any location. |
Bash Rules
Bash(...) rules can match exact commands, command prefixes, or wildcard patterns.
| Rule | Matches |
|---|---|
Bash(npm run build) | Exactly npm run build. |
Bash(npm run test:*) | npm run test and commands beginning with npm run test . |
Bash(git log *) | Glob-style wildcard matching. |
Bash(git status) | Exactly git status. |
denyandaskrules see through common wrappers and environment variable prefixes, soBash(rm -rf:*)still catches wrapped destructive commands.- Prefix and wildcard
allowrules do not silently approve compound commands unless every top-level command segment is independently allowed. - Some provably read-only shell commands can be automatically allowed after deny, ask, and path checks.
- Dangerous commands (destructive deletes, force pushes) can still force confirmation even with broad allow rules. In
automode, dangerous shell commands are denied.
Bash or Bash(*) unless you fully trust the session.
Web and MCP Rules
Web tools can be controlled at the tool level. Useask when every web fetch should require confirmation, or deny when web access should be blocked for a session or project.
| Rule | Meaning |
|---|---|
mcp__github__create_issue | A single MCP tool. |
mcp__github__* | All tools from the github MCP server. |
mcp__github | All tools from the github MCP server. |
mcp__* | All MCP tools. |
alwaysAllow for tools from that server. To enable only selected MCP servers for a run, use --allowed-mcp-server-names.
Hooks and Permissions
Qoder’s Hook system has two injection points in the permission decision pipeline, allowing custom scripts to influence allow/deny behavior.Hook Events That Affect Permissions
| Hook Event | Trigger | Permission Impact | ||
|---|---|---|---|---|
PreToolUse | Before tool execution (permission check phase) | Can return `permissionDecision: “allow" | "deny" | "ask”` to directly override the pipeline result |
PermissionRequest | After pipeline produces ask, before prompt | Can return a decision object with behavior: "allow" or behavior: "deny" to replace user interaction |
PostToolUse, SessionStart, Stop, etc.) do not participate in permission decisions.
PreToolUse Hook
Triggered before tool execution. The hook script can inspect the tool name and parameters, returning a permission decision:tool_name, tool_input, session_id, etc.) and output JSON results via stdout:
permissionDecision values:
"allow": Skip permission pipeline, approve directly"deny": Skip permission pipeline, deny directly"ask": Continue through normal permission pipeline (default behavior)
PermissionRequest Hook
Triggered after the permission pipeline producesask, before the prompt/callback. Suitable for automated approval systems or external notifications (e.g., Slack/email alerts):
Hook Priority vs. Permission Modes
Hook permission decisions have higher priority than permission modes — even inbypass_permissions mode, a PreToolUse hook returning deny will still block execution. This provides an unbypassable interception capability for organization-level security policies.
Execution order:
- Hook
PreToolUse→ if returns allow/deny, short-circuit - Permission pipeline (rules + mode + safety checks)
- If result is
ask→ HookPermissionRequest→ if returns allow/deny, short-circuit - Finally, the runtime environment consumes
ask(prompt/deny/callback)