Phase | Check Item | Action After Hit |
0 | Hooks / Special Cases for Interactive Tools | PreToolUse can directly allow / deny / ask; tools like AskUserQuestion inherently require interaction. |
1 | Deny Rules | Deny immediately with the highest priority. |
2 | Trusted Allow Rules (user / CLI / session / policy / trusted project rules / --allowedTools) | Allow immediately, and can bypass the interactive dangerous command check. |
3 | Command Security Check (Interactive Only) | High-risk Bash commands are forced to go to ask. |
4 | Ask Rules | Force ask. |
5 | Bypass Mode Short Circuit | bypassPermissions allows most actions here; if disabled, it degrades. |
6 | Untrusted Allow Rules (untrusted project rules, command / sandbox sources) | Can be allowed, but cannot bypass the dangerous command check in the previous step. |
7 | Permission Mode Baseline Policy | |
8 | Non-interactive Fallback | When the approval dialog cannot be displayed, convert unresolved ask to deny. |
9 | dontAsk / auto Final Gate | dontAsk rewrites ask to deny; auto only takes over ask and hands it to the classifier. |
deny always takes precedence.allow into two tiers: "trusted allow" and "untrusted allow". Before you explicitly trust the project directory, allow rules in .codebuddy/settings.json / .codebuddy/settings.local.json within the repository cannot bypass dangerous command checks, preventing malicious repositories from committing their own settings to silently weaken local security boundaries.auto is not a replacement for the entire chain. It only handles actions that would still end with an ask. Explicit ask rules do not go to the classifier.deny / ask / allowdefault / acceptEdits / auto / dontAsk / ...deny takes effect before any mode.ask rules take effect before auto, so manual confirmation is still required.dontAsk does not bypass rules. It only rewrites the final ask into deny.bypassPermissions does not erase preceding rules. deny / ask can still block it.bypassPermissions.permissions object correspond to three behaviors:{"permissions": {"allow": ["Bash(npm test)", "Read(/tmp/data/**)"],"ask": ["WebFetch"],"deny": ["Bash(rm -rf *)", "Edit(.git/**)"]}}
allow: CodeBuddy can be used without approval prompts.ask: An approval prompt appears on every use.deny: Never use it./permissions Command/permissions in a session to open the permission management panel. You can view all current allow / ask / deny rules and the settings layer each rule comes from, and temporarily add or remove rules (written to the user, project, or project-local scope). When you select "Yes, don't ask again" in the dialog, CodeBuddy writes the most stable prefix for the current command to the allow array in the corresponding settings scope.Parameter | Function |
--allowedTools <tools...> | Process-level temporary allow rule. Separate by spaces or commas. Example: --allowedTools "Bash(git:*) Edit" |
--disallowedTools <tools...> | Process-level temporary deny rule. Same as above. |
--add-dir <path> | Add extra directories to the trusted directory scope (affects whether Read requires a confirmation prompt). |
-y / --dangerously-skip-permissions | Equivalent to --permission-mode bypassPermissions. |
Scope | Path |
user | ~/.codebuddy/settings.json |
project | <repo>/.codebuddy/settings.json (committed to git) |
project-local | <repo>/.codebuddy/settings.local.json (not committed to git, local override) |
cliArg / flagSettings / session / policySettings | Process state, not persisted to disk |
Tool or Tool(specifier).Rule | Description |
Bash | All Bash Commands |
WebFetch | All web Fetching Operations |
Read | Reads all files |
Edit | Edits all files |
* can also be used alone as a rule, functioning as a full-match wildcard. However, it does not cover MCP tools. For details, see MCP Tools.Rule | Match |
Bash(npm run build) | Exact match for npm run build |
Bash(npm:*) or Bash(npm *) | All commands starting with npm |
Read(./.env) | The .env file in the current directory |
Edit(/src/**/*.ts) | src/**/*.ts under the project root |
Read(~/.zshrc) | The .zshrc file in the user directory |
Read(//tmp/scratch.txt) | An absolute path in the file system: /tmp/scratch.txt |
WebFetch(domain:example.com) | Fetch example.com. |
mcp__puppeteer__navigate | The navigate tool of the puppeteer service in MCP |
Agent(Explore) | Subagent Explore |
Syntax | Description | Example |
Exact match | The pattern exactly matches the command. | Bash(npm run build) matches only npm run build |
:* prefix | A :* at the end of the pattern matches the first word / multi-word prefix of a command. | Bash(git:*) matches git status / git push origin main |
Wildcard | When a pattern contains *, it is matched in bash glob mode (*** can cross /**). | Bash(npm run *) matches npm run build; Bash(ls *) matches ls -al /tmp/x |
* to cross /. Otherwise, ls * cannot match ls -al /xxx, which is the most common pitfall for users.&& / || / ; / |, and evaluates each subcommand independently:allow: ["Bash(git:*)"]git status → Allowedgit status && rm * → Prompt (rm * is not in the allow list, and all subcommands must match)git status; rm * → Prompt (same as above)
> / < / >> / << / &> require exact matching under allow rules, and wildcard rules do not apply.pattern | Description | Example |
//path | File system absolute path | Read(//etc/hosts) |
~/path | Starts from the user directory | Read(~/.zshrc) |
/path | Starts from the project root | Edit(/src/**/*.ts) |
path or ./path | Starts from the current working directory | Read(.env) |
Edit(.git/**) blocks all attempts through Edit / Write / NotebookEdit. However, it does not block indirect paths such as running python -c 'open(".git/config", "w")...' through Bash. OS-level protection relies on the Bash sandbox.cat, head, and tail.WebFetch # Any URLWebFetch(domain:example.com) # Only example.com and its subdomains
domain: prefix is supported for hostname matching, including subdomains.mcp__<server>__<tool>, with segments separated by double underscores __ (single underscores in names are treated as regular characters). Four ways to write rules:Rule | Match |
mcp__puppeteer | All tools with the prefix mcp__puppeteer__ |
mcp__puppeteer__* | Same as above. The two are equivalent. |
mcp__puppeteer__navigate | Only the navigate tool |
mcp__* | All MCP tools. Only deny / ask takes effect. |
mcp__web-search is equivalent to mcp__web_search.* can only replace the entire last segment. mcp__pup* and mcp__puppeteer__nav* do not match any tools, and no error is reported.mcp__. A bare * has no effect on them. To deny all MCP tools, write "deny": ["mcp__*"].{"permissions": {"deny": ["Agent(Explore)", "Agent(Plan)"]}}
codebuddy --disallowedTools "Agent(Explore) Agent(Plan)"
subagent_type is rejected when the main agent invokes an Agent tool.{"permissions": {"deny": ["Skill(dangerous-skill-name)"]}}
Method | Persistence |
--add-dir <path> startup parameter | Process level |
/add-dir command within a session | Session level |
Add directory via Web UI ( /api/v1/workspace-dirs) | Process level (frontend persistence) |
permissions.additionalDirectories configuration item | Persistence |
permissions.trustedDirectories configuration item | Persistence |
settings.trustedDirectories + directories added via --add-dir at startup / /add-dir during a session / the Web UI.--add-dir and permissions.additionalDirectories only grant file access. They do not make CodeBuddy load the .codebuddy/ configuration in these directories. agents, hooks, and settings still follow the startup directory.<repo>/.codebuddy/settings.json and .codebuddy/settings.local.json are classified into the untrusted tier (Phase 6) and cannot bypass command security checks..git, .gitconfig, .gitmodules.bashrc / .zshrc / .envrc, and so on..npmrc / .yarnrc / bunfig.toml, and so on..vscode / .idea / .husky / .devcontainer.codebuddy (except .codebuddy/worktrees).mcp.json / .codebuddy.jsonbypassPermissions mode still allows most of them to pass, but catastrophic commands such as rm -rf / / rm -rf ~ are forcibly prompted for confirmation.PreToolUse hook of the Hooks System runs before the permission approval prompt and can programmatically allow / deny / rewrite the input.{"hooks": {"PreToolUse": [{"matcher": "Bash","hooks": [{ "type": "command", "command": "/path/to/bash-policy.sh" }]}]}}
Exit Code | Action |
0 + JSON decision | Execute according to the permissionDecision (allow / ask / deny) in the JSON. |
2 | Block (stderr content is fed back to the model) |
Other non-zero values | Non-blocking error (prompt but allow) |
permissionDecision from PreToolUse takes effect before regular permission rules: allow / deny / ask directly permit, deny, or force a prompt, respectively.permissions.deny for unified auditing in /permissions and settings.deny rule prevents CodeBuddy from proactively attempting to use restricted tools.domain: allow rule for WebFetch and the sandbox allowedDomains take effect, and the final boundary is the intersection of the two.flagSettings / cliArg / session > userSettings > policySettings >projectSettings > localSettings > command/sandbox sources
deny arrays are merged from all scopes, and a deny in any scope results in denial.allow arrays are merged twice based on "trusted / untrusted": in the trusted merge, user / cli / flag / session / policy are always included, while project / local are considered trusted only when the directory is trusted.disableBypassPermissionsMode takes effect when any of the four layers—user, project, local, or CLI startup parameters—is set to "disable".{"permissions": {"defaultMode": "default","allow": ["Bash(npm test)","Bash(npm run lint)","Read(/src/**)","Read(/test/**)"],"deny": ["Bash(rm:*)","Bash(curl:*)","Bash(wget:*)","Edit(.git/**)","Edit(/.codebuddy/**)"]}}
{"permissions": {"defaultMode": "bypassPermissions","deny": ["Bash(rm -rf /:*)","Bash(sudo:*)","Bash(curl * -o /etc/*)","WebFetch(domain:internal-corp.example)"]}}
<repo>/.codebuddy/settings.json (committed to git):{"permissions": {"deny": ["Bash(rm:*)", "Edit(.git/**)"]}}
~/.codebuddy/settings.json (user-level, private):{"permissions": {"defaultMode": "acceptEdits","allow": ["Bash(git:*)", "Bash(npm:*)"]}}
--allowedTools / --disallowedTools / --add-dir.Was this page helpful?
You can also Contact sales or Submit a Ticket for help.
Help us improve! Rate your documentation experience in 5 mins.
Feedback