Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ While read-only operations like searching, reading files, and running read-only

You can allow or deny permissions for tools either when you start the CLI or during your interactive session. If you haven't granted permission prior to starting a session, {% data variables.copilot.copilot_cli_short %} will prompt you for permission each time it needs to perform a potentially destructive action. You can choose to allow the tool this one time, or for the remainder of the session.

## Persisted permissions

If you answer "yes, always" or otherwise choose the option to allow similar requests for the current location, the approval is saved to `permissions-config.json` in your configuration directory (by default, `~/.copilot/permissions-config.json`).

Command-line options such as `--allow-tool` and `--deny-tool` apply only to the current session and aren't written to `permissions-config.json`. Deny rules still take precedence over saved approvals.

For details about where saved approvals are stored, how locations are matched, and the full `permissions-config.json` schema, see [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-config-dir-reference#permissions-configjson).

## Layers of tool controls

There are two layers of control you can use when specifying tool permissions in command-line options. You can:
Expand Down Expand Up @@ -59,7 +67,7 @@ The value for each of these options is a comma-separated list of tool kinds, whi

If you specify a tool with `--allow-tool`, the AI model can choose to use that tool without prompting you for permission. If you specify a tool with `--deny-tool`, the AI model cannot use that tool at all, even if it would be the best choice for completing a task.

Deny rules always take precedence over allow rules, even when `--allow-all` is set.
Deny rules always take precedence over allow rules, even when `--allow-all` is set or a matching approval has been saved in `permissions-config.json`.

### Examples

Expand Down Expand Up @@ -94,9 +102,12 @@ The following command-line options give {% data variables.copilot.copilot_cli_sh

The `/reset-allowed-tools` slash command revokes all permissions you granted during the current interactive session. This applies equally to permissions you gave by responding to prompts, and to the use of the `/allow-all` or `/yolo` slash commands.

Using `/reset-allowed-tools` resets the permissions to the default, or to the state defined by any command-line options you used when you started {% data variables.copilot.copilot_cli_short %}. For example, if you start a {% data variables.copilot.copilot_cli_short %} interactive session with the option `--allow-tool='shell(git:*)'`, and then you allow and deny further permissions during the session by responding to prompts, when you then use the `/reset-allowed-tools` command, the CLI's permissions return to the original `--allow-tool='shell(git:*)'` state, with no other permissions allowed or denied. As you continue to work in the session, you will be prompted again if {% data variables.product.prodname_copilot_short %} needs additional permissions.
Using `/reset-allowed-tools` resets the permissions to the default, or to the state defined by any command-line options you used when you started {% data variables.copilot.copilot_cli_short %}. It also clears saved tool approvals for the current location from `permissions-config.json`. For example, if you start a {% data variables.copilot.copilot_cli_short %} interactive session with the option `--allow-tool='shell(git:*)'`, and then you allow and deny further permissions during the session by responding to prompts, when you then use the `/reset-allowed-tools` command, the CLI's permissions return to the original `--allow-tool='shell(git:*)'` state, with no other permissions allowed or denied. As you continue to work in the session, you will be prompted again if {% data variables.product.prodname_copilot_short %} needs additional permissions.

To remove saved approvals for a different location, edit or delete the relevant location entry in `permissions-config.json`. For more information, see [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-config-dir-reference#permissions-configjson).

## Further reading

* [AUTOTITLE](/copilot/how-tos/copilot-cli/cli-best-practices#configure-allowed-tools)
* [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-command-reference)
* [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-config-dir-reference#permissions-configjson)
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,192 @@ Stores internal application state that is managed automatically by the CLI, incl

### `permissions-config.json`

Stores your saved tool and directory permission decisions, organized by project location. When you approve a tool or grant access to a directory, the CLI records the decision here so you aren't prompted again in the same project.
Stores your saved tool and directory permission decisions, organized by project location. When you approve a tool or grant access to a directory for the current location, the CLI records the decision here so you aren't prompted again in the same repository or directory.

> [!NOTE]
> If you want to reset permissions for a project, you can delete the relevant entry from this file. However, editing the file while a session is running may cause unexpected behavior.
> If you want to reset permissions for a project, you can delete the relevant entry from this file. However, editing the file while a session is running may cause unexpected behavior. The CLI automatically removes entries whose location path no longer exists on disk.

#### File location

{% data variables.copilot.copilot_cli_short %} resolves the file from the configuration directory.

| Priority | Source | File used |
|----------|--------|-----------|
| 1 | `--config-dir=DIRECTORY` | `DIRECTORY/permissions-config.json` |
| 2 | `COPILOT_HOME` | `$COPILOT_HOME/permissions-config.json` |
| 3 | Default | `~/.copilot/permissions-config.json` |

The `--config-dir` option is a legacy option. Prefer `COPILOT_HOME` when you need to change the configuration directory.

On Windows, the default file is typically:

```text
C:\Users\YOUR-USER\.copilot\permissions-config.json
```

Older builds used an extensionless file named `permissions-config`. If `permissions-config.json` doesn't exist but the extensionless file does, the CLI still honors the legacy file. Use `permissions-config.json` for new edits.

Previous XDG-based configuration locations are migrated to `~/.copilot` at startup when `COPILOT_HOME` isn't set.

#### Location keys

The top-level `locations` object is keyed by an absolute path.

* For a Git repository, use the Git root used for permission scoping.
* Linked worktrees resolve to the main repository root, so they share permissions with the main worktree.
* Submodules use their own working directory.
* For a directory that isn't in a Git repository, use the normalized current working directory.

The key must match the location where {% data variables.copilot.copilot_cli_short %} is running. If the key doesn't match, the saved approvals won't apply.

The CLI loads the matching location's approvals when a session starts and when the active working directory changes.

#### Schema

The file must contain a JSON object.

| Field | Type | Required | Default | Allowed values | Description |
|-------|------|----------|---------|----------------|-------------|
| `locations` | Object | No | `{}` | Absolute path keys | Map of location keys to saved approvals. |
| `locations.<key>` | Object | No | `{}` | Any absolute location key | Saved approvals for one repository or directory. |
| `locations.<key>.tool_approvals` | Array | No | `[]` | Approval objects | Tools approved for this location. |
| `locations.<key>.allowed_directories` | Array of strings | No | `[]` | Absolute directory paths | Extra directories that the path gate can access for this location. Each directory must exist when the CLI applies the configuration. |
| `locations.<key>.tool_approvals[].kind` | String | Yes | None | `commands`, `read`, `write`, `mcp`, `mcp-sampling`, `memory`, `custom-tool`, `extension-management`, `extension-permission-access` | Selects the approval type. |
| `commandIdentifiers` | Array of strings | Yes, for `commands` | None | Command identifiers | Shell command identifiers to approve. |
| `serverName` | String | Yes, for `mcp` and `mcp-sampling` | None | MCP server name | MCP server to approve. |
| `toolName` | String or `null` | Yes, for `mcp` | None | MCP tool name, or `null` | MCP tool to approve. Use `null` to approve every tool on the server. |
| `toolName` | String | Yes, for `custom-tool` | None | Custom tool name | Custom tool to approve by exact name. |
| `operation` | String | No, for `extension-management` | Omitted | Extension operation name | Extension-management operation to approve. Omit this field to approve all extension-management operations. |
| `extensionName` | String | Yes, for `extension-permission-access` | None | Extension name | Extension whose access to permission-gated capabilities is approved. |

`permissions-config.json` doesn't support deny rules, "ask" rules, default modes, URL rules, tool filtering, or repository-local shared policy. For those behaviors, use command-line options such as `--deny-tool`, `--available-tools`, `--excluded-tools`, `--allow-url`, and `--deny-url`. Saved URL rules are stored in `config.json`, not in `permissions-config.json`.

Unknown fields aren't part of the schema. The CLI may ignore them, and later writes may remove them.

#### Approval kinds

Each item in `tool_approvals` must be one of the following objects.

| `kind` | Required fields | Optional fields | Meaning |
|--------|-----------------|-----------------|---------|
| `commands` | `commandIdentifiers` | None | Approves matching shell command identifiers. |
| `read` | None | None | Approves read tool requests. Interactive CLI sessions already approve reads automatically, so this is usually unnecessary. |
| `write` | None | None | Approves file creation and modification tool requests. A path prompt can still apply for paths outside the allowed directories. |
| `mcp` | `serverName`, `toolName` | None | Approves one MCP tool, or every tool on the server when `toolName` is `null`. |
| `mcp-sampling` | `serverName` | None | Approves MCP sampling requests for one server. |
| `memory` | None | None | Approves memory write and vote requests. |
| `custom-tool` | `toolName` | None | Approves a custom tool by exact name. |
| `extension-management` | None | `operation` | Approves extension management. If `operation` is omitted, all extension-management operations match. |
| `extension-permission-access` | `extensionName` | None | Approves an extension's access to permission-gated capabilities. |

For MCP approvals, `serverName` must match the configured MCP server name exactly. Use the raw server name from your MCP configuration, not a sanitized tool-name prefix.

#### Shell command matching

`commandIdentifiers` match the command identifiers extracted from a shell request. Matching is exact except for the `:*` suffix.

| Pattern | Matches | Doesn't match |
|---------|---------|---------------|
| `git status` | `git status` | `git status --short` |
| `git:*` | `git`, `git status`, `git push` | `gitea` |
| `gh pr:*` | `gh pr`, `gh pr view`, `gh pr create` | `gh repo view` |

The `:*` suffix isn't a general glob pattern. It matches the exact stem, or the stem followed by a space and more text.

#### Directory matching

`allowed_directories` entries allow {% data variables.copilot.copilot_cli_short %} to access paths inside those directories without a separate path prompt. They don't approve the tool operation itself. For example, editing a file in an allowed directory can still require a `write` approval.

Each `allowed_directories` entry must be an absolute, non-empty, accessible directory. The CLI resolves symlinks before comparing paths, blocks UNC network paths unless they are extended-length local paths, compares paths case-insensitively on Windows, and compares paths case-sensitively on other platforms. If an entry can't be applied, the CLI logs a warning and skips that entry.

#### Examples

Allow all Git subcommands and access an extra local directory:

```json copy
{
"locations": {
"C:\\src\\my-repo": {
"tool_approvals": [
{
"kind": "commands",
"commandIdentifiers": ["git:*"]
}
],
"allowed_directories": ["C:\\src\\shared-docs"]
}
}
}
```

Allow selected commands while still asking before file writes:

```json copy
{
"locations": {
"/Users/YOUR-USER/src/my-repo": {
"tool_approvals": [
{
"kind": "commands",
"commandIdentifiers": [
"git status",
"git diff",
"git log",
"npm test",
"npm run build"
]
}
]
}
}
}
```

Approve file writes and one MCP server for a repository:

```json copy
{
"locations": {
"/home/YOUR-USER/src/my-repo": {
"tool_approvals": [
{
"kind": "write"
},
{
"kind": "mcp",
"serverName": "github-mcp-server",
"toolName": null
}
]
}
}
}
```

Approve one MCP tool, memory writes, and extension permission access:

```json copy
{
"locations": {
"C:\\src\\my-repo": {
"tool_approvals": [
{
"kind": "mcp",
"serverName": "github-mcp-server",
"toolName": "search_code"
},
{
"kind": "memory"
},
{
"kind": "extension-permission-access",
"extensionName": "my-extension"
}
]
}
}
}
```

### `session-state/`

Expand Down
Loading