2025-12-01 11:38:48 -08:00
# Policy engine
2025-10-31 11:11:19 -07:00
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.
2025-12-15 12:17:48 -08:00
## Quick start
To create your first policy:
1. **Create the policy directory ** if it doesn't exist:
2026-02-27 15:41:47 -08:00
**macOS/Linux **
2025-12-15 12:17:48 -08:00
```bash
mkdir -p ~/.gemini/policies
` ``
2026-02-27 15:41:47 -08:00
**Windows (PowerShell)**
` ``powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.gemini\policies"
` ``
2025-12-15 12:17:48 -08:00
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.
2025-10-31 11:11:19 -07:00
## 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"
2026-03-16 23:45:30 +09:00
commandPrefix = "git"
2025-10-31 11:11:19 -07:00
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.
2026-02-23 14:07:06 -05:00
- **Wildcards**: You can use wildcards to match multiple tools.
- ` *`: Matches **any tool** (built-in or MCP).
2026-03-10 15:13:00 -04:00
- ` 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).
2025-10-31 11:11:19 -07:00
2025-12-01 11:38:48 -08:00
#### Arguments pattern
2025-10-31 11:11:19 -07:00
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.
2026-03-18 16:00:26 -04:00
#### Execution environment
If ` interactive` is specified, the rule will only apply if the CLI's execution
environment matches the specified boolean value:
- ` true`: The rule applies only in interactive mode.
- ` false`: The rule applies only in non-interactive (headless) mode.
If omitted, the rule applies to both interactive and non-interactive
environments.
2025-10-31 11:11:19 -07:00
### Decisions
There are three possible decisions a rule can enforce:
- ` allow`: The tool call is executed automatically without user interaction.
2026-03-09 09:29:52 -07:00
- ` 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.
2025-10-31 11:11:19 -07:00
- ` ask_user`: The user is prompted to approve or deny the tool call. (In
non-interactive mode, this is treated as ` deny`.)
2026-03-19 14:11:14 -07:00
<!-- prettier-ignore -->
> [!NOTE]
> The ` deny` decision is the recommended way to exclude tools. The
2026-03-09 09:29:52 -07:00
> legacy ` tools.exclude` setting in ` settings.json` is deprecated in favor of
> policy rules with a ` deny` decision.
2025-12-01 11:38:48 -08:00
### Priority system and tiers
2025-10-31 11:11:19 -07:00
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.
2026-02-19 16:16:03 -08:00
| Tier | Base | Description |
| :-------- | :--- | :------------------------------------------------------------------------- |
| Default | 1 | Built-in policies that ship with the Gemini CLI. |
2026-02-26 22:29:33 -05:00
| 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). |
2025-10-31 11:11:19 -07:00
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:
2026-02-19 16:16:03 -08:00
- Admin policies always override User, Workspace, and Default policies.
- User policies override Workspace and Default policies.
- Workspace policies override Default policies.
2025-10-31 11:11:19 -07:00
- 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`.
2026-02-19 16:16:03 -08:00
- 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`.
2025-10-31 11:11:19 -07:00
### 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
2026-02-11 12:32:02 -05:00
(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.
2026-03-09 08:23:00 -07:00
- ` plan`: A strict, read-only mode for research and design. See
[Customizing Plan Mode Policies](../cli/plan-mode.md#customizing-policies).
2026-02-11 12:32:02 -05:00
- ` yolo`: A mode where all tools are auto-approved (use with extreme caution).
2025-10-31 11:11:19 -07:00
## 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:
2025-12-01 11:38:48 -08:00
1. **Tool name**: The ` toolName` in the rule must match the name of the tool
2025-10-31 11:11:19 -07:00
being called.
2026-03-10 15:13:00 -04:00
- **Wildcards**: You can use wildcards like ` *`, ` mcp_server_*`, or
` mcp_*_toolName` to match multiple tools. See [Tool Name](#tool-name) for
2026-02-23 14:07:06 -05:00
details.
2025-12-01 11:38:48 -08:00
2. **Arguments pattern**: If ` argsPattern` is specified, the tool's arguments
2025-10-31 11:11:19 -07:00
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.
2026-01-26 19:27:49 -05:00
### Policy locations
2026-02-19 16:16:03 -08:00
| Tier | Type | Location |
| :------------ | :----- | :---------------------------------------- |
| **User** | Custom | ` ~/.gemini/policies/*.toml` |
| **Workspace** | Custom | ` $WORKSPACE_ROOT/.gemini/policies/*.toml` |
| **Admin** | System | _See below (OS specific)_ |
2026-01-26 19:27:49 -05:00
#### System-wide policies (Admin)
2026-03-11 10:35:45 -07:00
Administrators can enforce system-wide policies (Tier 4) that override all user
and default settings. These policies can be loaded from standard system
locations or supplemental paths.
##### Standard Locations
These are the default paths the CLI searches for admin policies:
2026-01-26 19:27:49 -05:00
| OS | Policy Directory Path |
| :---------- | :------------------------------------------------ |
| **Linux** | ` /etc/gemini-cli/policies` |
| **macOS** | ` /Library/Application Support/GeminiCli/policies` |
| **Windows** | ` C:\ProgramData\gemini-cli\policies` |
2026-03-11 10:35:45 -07:00
##### Supplemental Admin Policies
Administrators can also specify supplemental policy paths using:
- The ` --admin-policy` command-line flag.
- The ` adminPolicyPaths` setting in a system settings file.
2026-01-26 19:27:49 -05:00
2026-03-11 10:35:45 -07:00
These supplemental policies are assigned the same **Admin** tier (Base 4) as
policies in standard locations.
**Security Guard**: Supplemental admin policies are **ignored** if any ` .toml`
policy files are found in the standard system location. This prevents flag-based
overrides when a central system policy has already been established.
#### Security Requirements
To prevent privilege escalation, the CLI enforces strict security checks on the
**standard system policy directory**. If checks fail, the policies in that
directory are **ignored**.
2026-01-26 19:27:49 -05:00
- **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`)
2026-03-19 14:11:14 -07:00
must NOT have ` Write`, ` Modify`, or ` Full Control` permissions. 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.
<!-- prettier-ignore -->
> [!NOTE]
> Supplemental admin policies (provided via ` --admin-policy` or
> ` adminPolicyPaths` settings) are **NOT** subject to these strict ownership
> checks, as they are explicitly provided by the user or administrator in their
> current execution context.
2026-03-11 10:35:45 -07:00
2025-10-31 11:11:19 -07:00
### 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"
2026-03-21 05:00:09 +05:30
# (Optional) The name of a subagent. If provided, the rule only applies to tool
# calls made by this specific subagent.
2026-03-09 12:22:46 -07:00
subagent = "generalist"
2025-10-31 11:11:19 -07:00
# (Optional) The name of an MCP server. Can be combined with toolName
2026-03-10 15:13:00 -04:00
# to form a composite FQN internally like "mcp_mcpName_toolName".
2025-10-31 11:11:19 -07:00
mcpName = "my-custom-server"
2026-02-24 09:20:11 -05:00
# (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 }
2025-10-31 11:11:19 -07:00
# (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.
2026-03-21 05:00:09 +05:30
# This is syntactic sugar for ` toolName = "run_shell_command"` and an
# ` argsPattern`.
2026-03-16 23:45:30 +09:00
commandPrefix = "git"
2025-10-31 11:11:19 -07:00
# (Optional) A regex to match against the entire shell command.
# This is also syntactic sugar for ` toolName = "run_shell_command"`.
2026-03-21 05:00:09 +05:30
# Note: This pattern is tested against the JSON representation of the arguments
# (e.g., ` {"command":"<your_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.
2025-10-31 11:11:19 -07:00
# You cannot use commandPrefix and commandRegex in the same rule.
2026-02-13 12:02:07 -08:00
commandRegex = "git (commit|push)"
2025-10-31 11:11:19 -07:00
# 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
2026-03-21 05:00:09 +05:30
# (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.
2026-03-23 20:32:50 +00:00
denyMessage = "Deletion is permanent"
2026-01-28 10:52:48 -08:00
2025-10-31 11:11:19 -07:00
# (Optional) An array of approval modes where this rule is active.
modes = ["autoEdit"]
2026-03-18 16:00:26 -04:00
2026-03-21 05:00:09 +05:30
# (Optional) A boolean to restrict the rule to interactive (true) or
# non-interactive (false) environments.
2026-03-18 16:00:26 -04:00
# If omitted, the rule applies to both.
interactive = true
2026-03-23 20:32:50 +00:00
# (Optional) If true, lets shell commands use redirection operators
# (>, >>, <, <<, <<<). By default, the policy engine asks for confirmation
# when redirection is detected, even if a rule matches the command.
# This permission is granular; it only applies to the specific rule it's
# defined in. In chained commands (e.g., cmd1 > file && cmd2), each
# individual command rule must permit redirection if it's used.
allowRedirection = true
2025-10-31 11:11:19 -07:00
` ``
### 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"
2026-03-16 23:45:30 +09:00
commandPrefix = "git"
2025-10-31 11:11:19 -07:00
decision = "ask_user"
priority = 100
` ``
### Special syntax for MCP tools
2026-02-23 14:07:06 -05:00
You can create rules that target tools from Model Context Protocol (MCP) servers
2026-03-10 15:13:00 -04:00
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.
2026-03-19 14:11:14 -07:00
<!-- prettier-ignore -->
> [!WARNING]
> Do not use underscores (` _`) in your MCP server names (e.g., use
2026-03-10 15:13:00 -04:00
> ` 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.
2025-10-31 11:11:19 -07:00
2026-02-23 14:07:06 -05:00
**1. Targeting a specific tool on a server**
2025-10-31 11:11:19 -07:00
2026-03-12 21:31:13 -04:00
Combine ` mcpName` and ` toolName` to target a single operation. When using
` mcpName`, the ` toolName` field should strictly be the simple name of the tool
(e.g., ` search`), **not** the Fully Qualified Name (e.g., ` mcp_server_search`).
2025-10-31 11:11:19 -07:00
` ``toml
# Allows the ` search` tool on the ` my-jira-server` MCP
[[rule]]
mcpName = "my-jira-server"
toolName = "search"
decision = "allow"
priority = 200
` ``
2026-02-23 14:07:06 -05:00
**2. Targeting all tools on a specific server**
2025-10-31 11:11:19 -07:00
2026-02-23 14:07:06 -05:00
Specify only the ` mcpName` to apply a rule to every tool provided by that
server.
2025-10-31 11:11:19 -07:00
2026-03-18 16:24:51 -04:00
**Note:** This applies to all decision types (` allow`, ` deny`, ` ask_user`).
2025-10-31 11:11:19 -07:00
` ``toml
# Denies all tools from the ` untrusted-server` MCP
[[rule]]
mcpName = "untrusted-server"
decision = "deny"
priority = 500
2026-03-23 20:32:50 +00:00
denyMessage = "This server is not trusted by the admin."
2025-10-31 11:11:19 -07:00
` ``
2026-02-23 14:07:06 -05:00
**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]]
2026-03-23 22:35:08 +00:00
toolName = "*"
2026-02-23 14:07:06 -05:00
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
` ``
2025-10-31 11:11:19 -07:00
## 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**.
2026-03-30 17:03:02 -04:00
- **MCP Read-only tools**: MCP tools that explicitly declare themselves as read-only via the ` readOnlyHint` annotation are automatically allowed, but **only if tool sandboxing is enabled**. If sandboxing is disabled, they default to ` ask_user`.
2026-01-29 18:24:35 +00:00
- **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.
2025-10-31 11:11:19 -07:00
- **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.