# Policy engine The Gemini CLI includes a powerful policy engine that provides fine-grained control over tool execution. It allows users and administrators to define rules that determine whether a tool call should be allowed, denied, or require user confirmation. ## Quick start To create your first policy: 1. **Create the policy directory** if it doesn't exist: **macOS/Linux** ```bash mkdir -p ~/.gemini/policies ``` **Windows (PowerShell)** ```powershell New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.gemini\policies" ``` 2. **Create a new policy file** (e.g., `~/.gemini/policies/my-rules.toml`). You can use any filename ending in `.toml`; all such files in this directory will be loaded and combined: ```toml [[rule]] toolName = "run_shell_command" commandPrefix = "git status" decision = "allow" priority = 100 ``` 3. **Run a command** that triggers the policy (e.g., ask Gemini CLI to `git status`). The tool will now execute automatically without prompting for confirmation. ## Core concepts The policy engine operates on a set of rules. Each rule is a combination of conditions and a resulting decision. When a large language model wants to execute a tool, the policy engine evaluates all rules to find the highest-priority rule that matches the tool call. A rule consists of the following main components: - **Conditions**: Criteria that a tool call must meet for the rule to apply. This can include the tool's name, the arguments provided to it, or the current approval mode. - **Decision**: The action to take if the rule matches (`allow`, `deny`, or `ask_user`). - **Priority**: A number that determines the rule's precedence. Higher numbers win. For example, this rule will ask for user confirmation before executing any `git` command. ```toml [[rule]] toolName = "run_shell_command" commandPrefix = "git " decision = "ask_user" priority = 100 ``` ### Conditions Conditions are the criteria that a tool call must meet for a rule to apply. The primary conditions are the tool's name and its arguments. #### Tool Name The `toolName` in the rule must match the name of the tool being called. - **Wildcards**: You can use wildcards to match multiple tools. - `*`: Matches **any tool** (built-in or MCP). - `mcp_server_*`: Matches any tool from a specific MCP server. - `mcp_*_toolName`: Matches a specific tool name across **all** MCP servers. - `mcp_*`: Matches **any tool from any MCP server**. > **Recommendation:** While FQN wildcards are supported, the recommended > approach for MCP tools is to use the `mcpName` field in your TOML rules. See > [Special syntax for MCP tools](#special-syntax-for-mcp-tools). #### Arguments pattern If `argsPattern` is specified, the tool's arguments are converted to a stable JSON string, which is then tested against the provided regular expression. If the arguments don't match the pattern, the rule does not apply. ### Decisions There are three possible decisions a rule can enforce: - `allow`: The tool call is executed automatically without user interaction. - `deny`: The tool call is blocked and is not executed. For global rules (those without an `argsPattern`), tools that are denied are **completely excluded from the model's memory**. This means the model will not even see the tool as an option, which is more secure and saves context window space. - `ask_user`: The user is prompted to approve or deny the tool call. (In non-interactive mode, this is treated as `deny`.) > **Note:** The `deny` decision is the recommended way to exclude tools. The > legacy `tools.exclude` setting in `settings.json` is deprecated in favor of > policy rules with a `deny` decision. ### Priority system and tiers The policy engine uses a sophisticated priority system to resolve conflicts when multiple rules match a single tool call. The core principle is simple: **the rule with the highest priority wins**. To provide a clear hierarchy, policies are organized into three tiers. Each tier has a designated number that forms the base of the final priority calculation. | Tier | Base | Description | | :-------- | :--- | :------------------------------------------------------------------------- | | Default | 1 | Built-in policies that ship with the Gemini CLI. | | Extension | 2 | Policies defined in extensions. | | Workspace | 3 | Policies defined in the current workspace's configuration directory. | | User | 4 | Custom policies defined by the user. | | Admin | 5 | Policies managed by an administrator (e.g., in an enterprise environment). | Within a TOML policy file, you assign a priority value from **0 to 999**. The engine transforms this into a final priority using the following formula: `final_priority = tier_base + (toml_priority / 1000)` This system guarantees that: - Admin policies always override User, Workspace, and Default policies. - User policies override Workspace and Default policies. - Workspace policies override Default policies. - You can still order rules within a single tier with fine-grained control. For example: - A `priority: 50` rule in a Default policy file becomes `1.050`. - A `priority: 10` rule in a Workspace policy policy file becomes `2.010`. - A `priority: 100` rule in a User policy file becomes `3.100`. - A `priority: 20` rule in an Admin policy file becomes `4.020`. ### Approval modes Approval modes allow the policy engine to apply different sets of rules based on the CLI's operational mode. A rule can be associated with one or more modes (e.g., `yolo`, `autoEdit`, `plan`). The rule will only be active if the CLI is running in one of its specified modes. If a rule has no modes specified, it is always active. - `default`: The standard interactive mode where most write tools require confirmation. - `autoEdit`: Optimized for automated code editing; some write tools may be auto-approved. - `plan`: A strict, read-only mode for research and design. See [Customizing Plan Mode Policies](../cli/plan-mode.md#customizing-policies). - `yolo`: A mode where all tools are auto-approved (use with extreme caution). ## Rule matching When a tool call is made, the engine checks it against all active rules, starting from the highest priority. The first rule that matches determines the outcome. A rule matches a tool call if all of its conditions are met: 1. **Tool name**: The `toolName` in the rule must match the name of the tool being called. - **Wildcards**: You can use wildcards like `*`, `mcp_server_*`, or `mcp_*_toolName` to match multiple tools. See [Tool Name](#tool-name) for details. 2. **Arguments pattern**: If `argsPattern` is specified, the tool's arguments are converted to a stable JSON string, which is then tested against the provided regular expression. If the arguments don't match the pattern, the rule does not apply. ## Configuration Policies are defined in `.toml` files. The CLI loads these files from Default, User, and (if configured) Admin directories. ### Policy locations | Tier | Type | Location | | :------------ | :----- | :---------------------------------------- | | **User** | Custom | `~/.gemini/policies/*.toml` | | **Workspace** | Custom | `$WORKSPACE_ROOT/.gemini/policies/*.toml` | | **Admin** | System | _See below (OS specific)_ | #### System-wide policies (Admin) Administrators can enforce system-wide policies (Tier 3) that override all user and default settings. These policies must be placed in specific, secure directories: | OS | Policy Directory Path | | :---------- | :------------------------------------------------ | | **Linux** | `/etc/gemini-cli/policies` | | **macOS** | `/Library/Application Support/GeminiCli/policies` | | **Windows** | `C:\ProgramData\gemini-cli\policies` | **Security Requirements:** To prevent privilege escalation, the CLI enforces strict security checks on admin directories. If checks fail, system policies are **ignored**. - **Linux / macOS:** Must be owned by `root` (UID 0) and NOT writable by group or others (e.g., `chmod 755`). - **Windows:** Must be in `C:\ProgramData`. Standard users (`Users`, `Everyone`) must NOT have `Write`, `Modify`, or `Full Control` permissions. _Tip: If you see a security warning, use the folder properties to remove write permissions for non-admin groups. You may need to "Disable inheritance" in Advanced Security Settings._ ### TOML rule schema Here is a breakdown of the fields available in a TOML policy rule: ```toml [[rule]] # A unique name for the tool, or an array of names. toolName = "run_shell_command" # (Optional) The name of a subagent. If provided, the rule only applies to tool calls # made by this specific subagent. subagent = "generalist" # (Optional) The name of an MCP server. Can be combined with toolName # to form a composite FQN internally like "mcp_mcpName_toolName". mcpName = "my-custom-server" # (Optional) Metadata hints provided by the tool. A rule matches if all # key-value pairs provided here are present in the tool's annotations. toolAnnotations = { readOnlyHint = true } # (Optional) A regex to match against the tool's arguments. argsPattern = '"command":"(git|npm)' # (Optional) A string or array of strings that a shell command must start with. # This is syntactic sugar for `toolName = "run_shell_command"` and an `argsPattern`. commandPrefix = "git " # (Optional) A regex to match against the entire shell command. # This is also syntactic sugar for `toolName = "run_shell_command"`. # Note: This pattern is tested against the JSON representation of the arguments (e.g., `{"command":""}`). # Because it prepends `"command":"`, it effectively matches from the start of the command. # Anchors like `^` or `$` apply to the full JSON string, so `^` should usually be avoided here. # You cannot use commandPrefix and commandRegex in the same rule. commandRegex = "git (commit|push)" # The decision to take. Must be "allow", "deny", or "ask_user". decision = "ask_user" # The priority of the rule, from 0 to 999. priority = 10 # (Optional) A custom message to display when a tool call is denied by this rule. # This message is returned to the model and user, useful for explaining *why* it was denied. deny_message = "Deletion is permanent" # (Optional) An array of approval modes where this rule is active. modes = ["autoEdit"] ``` ### Using arrays (lists) To apply the same rule to multiple tools or command prefixes, you can provide an array of strings for the `toolName` and `commandPrefix` fields. **Example:** This single rule will apply to both the `write_file` and `replace` tools. ```toml [[rule]] toolName = ["write_file", "replace"] decision = "ask_user" priority = 10 ``` ### Special syntax for `run_shell_command` To simplify writing policies for `run_shell_command`, you can use `commandPrefix` or `commandRegex` instead of the more complex `argsPattern`. - `commandPrefix`: Matches if the `command` argument starts with the given string. - `commandRegex`: Matches if the `command` argument matches the given regular expression. **Example:** This rule will ask for user confirmation before executing any `git` command. ```toml [[rule]] toolName = "run_shell_command" commandPrefix = "git " decision = "ask_user" priority = 100 ``` ### Special syntax for MCP tools You can create rules that target tools from Model Context Protocol (MCP) servers using the `mcpName` field. **This is the recommended approach** for defining MCP policies, as it is much more robust than manually writing Fully Qualified Names (FQNs) or string wildcards. > **Warning:** Do not use underscores (`_`) in your MCP server names (e.g., use > `my-server` rather than `my_server`). The policy parser splits Fully Qualified > Names (`mcp_server_tool`) on the _first_ underscore following the `mcp_` > prefix. If your server name contains an underscore, the parser will > misinterpret the server identity, which can cause wildcard rules and security > policies to fail silently. **1. Targeting a specific tool on a server** Combine `mcpName` and `toolName` to target a single operation. ```toml # Allows the `search` tool on the `my-jira-server` MCP [[rule]] mcpName = "my-jira-server" toolName = "search" decision = "allow" priority = 200 ``` **2. Targeting all tools on a specific server** Specify only the `mcpName` to apply a rule to every tool provided by that server. ```toml # Denies all tools from the `untrusted-server` MCP [[rule]] mcpName = "untrusted-server" decision = "deny" priority = 500 deny_message = "This server is not trusted by the admin." ``` **3. Targeting all MCP servers** Use `mcpName = "*"` to create a rule that applies to **all** tools from **any** registered MCP server. This is useful for setting category-wide defaults. ```toml # Ask user for any tool call from any MCP server [[rule]] mcpName = "*" decision = "ask_user" priority = 10 ``` **4. Targeting a tool name across all servers** Use `mcpName = "*"` with a specific `toolName` to target that operation regardless of which server provides it. ```toml # Allow the `search` tool across all connected MCP servers [[rule]] mcpName = "*" toolName = "search" decision = "allow" priority = 50 ``` ## Default policies The Gemini CLI ships with a set of default policies to provide a safe out-of-the-box experience. - **Read-only tools** (like `read_file`, `glob`) are generally **allowed**. - **Agent delegation** defaults to **`ask_user`** to ensure remote agents can prompt for confirmation, but local sub-agent actions are executed silently and checked individually. - **Write tools** (like `write_file`, `run_shell_command`) default to **`ask_user`**. - In **`yolo`** mode, a high-priority rule allows all tools. - In **`autoEdit`** mode, rules allow certain write operations to happen without prompting.