# 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:
    ```bash
    mkdir -p ~/.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**: For Model-hosting-protocol (MCP) servers, you can use a
  wildcard. A `toolName` of `my-server__*` will match any tool from the
  `my-server` MCP.

#### 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.
- `ask_user`: The user is prompted to approve or deny the tool call. (In
  non-interactive mode, this is treated as `deny`.)

### 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.                           |
| User    | 2    | Custom policies defined by the user.                                       |
| Admin   | 3    | 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 and Default policies.
- User policies always 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: 100` rule in a User policy file becomes `2.100`.
- A `priority: 20` rule in an Admin policy file becomes `3.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].
- `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**: For Model-hosting-protocol (MCP) servers, you can use a
      wildcard. A `toolName` of `my-server__*` will match any tool from the
      `my-server` MCP.
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` |
| **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 an MCP server. Can be combined with toolName
# to form a composite name like "mcpName__toolName".
mcpName = "my-custom-server"

# (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":"<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.
# 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-hosting-protocol (MCP) servers
using the `mcpName` field or a wildcard pattern.

**1. Using `mcpName`**

To target a specific tool from a specific server, combine `mcpName` and
`toolName`.

```toml
# Allows the `search` tool on the `my-jira-server` MCP
[[rule]]
mcpName = "my-jira-server"
toolName = "search"
decision = "allow"
priority = 200
```

**2. Using a wildcard**

To create a rule that applies to _all_ tools on a specific MCP server, specify
only the `mcpName`.

```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."
```

## 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.

[Customizing Plan Mode Policies]: /docs/cli/plan-mode.md#customizing-policies
