GitHub Copilot CLI permissions and hooks reference
GitHub Copilot CLI asks before anything that changes your machine. Reads and read-only shell commands run without a prompt; destructive shell commands, file edits and URL access prompt, unless a rule, a saved approval or an allow-all mode already covers them. Deny rules beat every allow. In -p mode there is no prompt, and a request that needs approval is denied.
This page is the CLI only: the terminal agent you start with copilot, not the editor extension. For VS Code agent mode and the cloud coding agent, see the Copilot controls page. For wiring a check into Copilot’s hooks, see the Copilot install guide.
The default: what prompts and what does not
From GitHub’s Allowing and denying tool use: searching, reading files and read-only shell commands are “generally allowed automatically, subject to applicable policy.” Destructive shell commands, file edits and URL access “need permission before Copilot can use them.”
At a prompt, About Copilot CLI lists the choices:
- Yes. Once. Copilot asks again next time.
- Yes, and approve the tool for the rest of the session. This is broader than it looks. GitHub’s own example: approve
rm ./this-file.txtthis way and Copilot “can run anyrmcommand (for example,rm -rf ./*)” for the rest of that session. - No, and tell Copilot what to do differently. Cancels the call and lets you redirect it.
For a shell command, file write, MCP tool or memory update there is also “don’t ask again in this repo” (or “in this directory”). That approval is saved to ~/.copilot/permissions-config.json, scoped to the git root, or the working directory outside a repository. A permanently approved URL goes to allowedUrls in ~/.copilot/settings.json and applies to every session.
Before any of this, Copilot asks whether you trust the folder you launched in. The CLI overview offers this session only, remember the folder, or no. Access outside it prompts again, or you grant it with /add-dir. GitHub says this scoping “is heuristic and GitHub does not guarantee” files outside it are protected, and that you “should not launch Copilot CLI from your home directory.”
Allow and deny rules
Two layers, both set on the command line.
Which tools exist. --available-tools keeps only the tools you list. --excluded-tools removes the ones you list. If you pass both, the allowlist wins. A tool outside the available set cannot be used even if --allow-tool names it.
copilot --excluded-tools='web_fetch, web_search'
Which tools run without a prompt. --allow-tool pre-approves. --deny-tool blocks: the tool “will not prompt for permission”, per the command reference. Patterns are Kind(argument); leave the argument off to match every tool of that kind.
# all git subcommands except push
copilot --allow-tool='shell(git:*)' --deny-tool='shell(git push)'
# no file writes at all
copilot --deny-tool=write
# all reads, plus writes to one file
copilot --allow-tool='read, write(.github/copilot-instructions.md)'
# two tools from one MCP server
copilot --allow-tool='MyMCP(create_issue), MyMCP(delete_issue)'
# explore, edit and commit; no internet, no pushes
copilot --available-tools='bash,edit,view,grep,glob' \
--allow-tool='shell(git:*)' --deny-tool='shell(git push)'
URLs have their own pair, --allow-url and --deny-url, and --deny-url “takes precedence over --allow-url.” The programmatic reference lists url(github.com) as a filter.
Precedence. “Deny rules always take precedence over allow rules, even when --allow-all is set or a matching approval has been saved.” That sentence is the strongest guarantee in Copilot CLI’s model. A --deny-tool is a real block, not a prompt.
Persistence. --allow-tool and --deny-tool are session-only and “aren’t written to permissions-config.json.” The only persistent allows are the saved prompt approvals and allowedUrls above. To keep a rule set, put the flags in a script, not in a shell alias with allow-all on it; GitHub warns against the alias.
Allow-all, assisted and autopilot
| Mode | How | What it does |
|---|---|---|
| Default | the starting mode, /permissions default |
Prompts for anything not already allowed |
| Assisted | /permissions assisted, --assisted-approval for -p runs |
A model reviews eligible requests and approves “those it judges to be safe”; the rest are put to you, or denied in -p runs |
| Allow all tools | --allow-all-tools, env COPILOT_ALLOW_ALL |
Every available tool runs without a prompt |
| Allow all | --allow-all or --yolo; /permissions allow-all or /yolo mid-session |
--allow-all-tools --allow-all-paths --allow-all-urls together |
Deny rules and enterprise restrictions still apply under --allow-all-tools. On Business and Enterprise licences the allow-all options “may be blocked by an enterprise administrator.” --assisted-approval makes the CLI exit with an error if you start an interactive session with it, and when it is enabled it overrides --allow-all-tools but not the path or URL flags. You can set assisted as your default with defaultPermissionMode: "assisted" in the user config.
/reset-allowed-tools revokes in-session grants, returns to manual mode, and clears saved approvals for the current location. Startup flags such as --allow-tool and --deny-tool stay as the baseline.
Autopilot is separate. It controls continuation, not approvals: the agent keeps going until the task is done or --max-autopilot-continues is reached. If you enter autopilot with manual approval, “Copilot will automatically deny any tool requests that require approval.” GitHub’s own example pairs it with --yolo:
copilot --autopilot --yolo --max-autopilot-continues 10 -p "YOUR PROMPT HERE"
Sandboxing
Copilot CLI has two. Local sandboxing, turned on with /sandbox enable, does not sandbox the CLI itself; “the commands and tools that Copilot CLI runs on your behalf are restricted,” limiting filesystem, network and system access. Cloud sandboxing, copilot --cloud, runs the whole session in a GitHub-hosted environment.
/sandbox enable
/sandbox status
/sandbox policy npm install
copilot --sandbox
The command reference adds the details that matter. /sandbox policy shows path grants, network settings and developer-tool access, and with a command appended it shows what that command could reach without running it. Launching with --sandbox turns it on for that session only. If your organization requires sandboxing, disable is refused unless bypass is allowed. /add-dir also grants the sandbox access to that directory. Under autopilot, a step that needs to escape the sandbox, such as writing outside the working directory, is denied.
Hooks
Copilot CLI has a full hook system. The hooks reference lists these events: sessionStart, sessionEnd, userPromptSubmitted, userPromptTransformed, preToolUse, postToolUse, postToolUseFailure, permissionRequest, preCompact, subagentStart, subagentStop, agentStop, errorOccurred, notification. PascalCase aliases such as PreToolUse are accepted and switch the payload to snake_case fields in Claude Code’s format.
Hooks load in order, policy, then user, then project, then plugins, and are combined:
- Policy:
/etc/github-copilot/policy.d/*.json,C:\ProgramData\GitHub\Copilot\policy.d\*.json, and the Windows registry keyHKLM\Software\Policies\GitHub\Copilot - Repository:
.github/hooks/*.json - User:
~/.copilot/hooks/(or$COPILOT_HOME/hooks/) - Inline
hooksin.github/copilot/settings.json,settings.local.json,~/.copilot/settings.json, and.claude/settings.json/.claude/settings.local.json - Plugin
hooks.json
A minimal preToolUse hook in .github/hooks/policy.json:
{
"version": 1,
"hooks": {
"preToolUse": [
{ "type": "command", "bash": "./scripts/check-tool.sh", "timeoutSec": 10 }
]
}
}
The script reads toolName and toolArgs on stdin and prints:
{ "permissionDecision": "deny", "permissionDecisionReason": "force-push is blocked in this repo" }
permissionDecision is allow, deny or ask; the reason is required on a deny and shown to the agent. modifiedArgs substitutes the tool’s arguments.
What happens when a hook fails.
| Case | Result |
|---|---|
Exit 2 from preToolUse or permissionRequest |
Deny |
Exit 2 from other events |
Warning; the run continues |
Other non-zero exit from a command preToolUse |
Deny (“hook errored”), even if stdout said allow |
| Timeout (default 30 s) | Fail open, “including for preToolUse and admin-deployed policy hooks” |
HTTP preToolUse hook: network error, timeout, non-2xx |
Fail open |
disableAllHooks: true in a hook file skips that file; in the repository settings.json it disables every source except policy hooks, which “continue to run.”
permissionRequest fires before the permission service: before rule checks, saved approvals and prompting. Returning behavior: "allow" or "deny" short-circuits the normal flow. GitHub calls it “especially useful in CLI pipe mode (-p) and other CLI CI usages where no interactive prompt is available.” It is CLI-only. For a sandbox-bypass request, only a deny propagates; an allow does not pre-approve the escape.
Headless and CI
The programmatic reference treats a run as non-interactive when it uses -p or has no terminal attached, as in CI. The rule: “Without any permission options, requests that need approval are denied, and Copilot often can’t finish the task.” Under assisted approval, requests that still need you are denied too, with the reason passed back to the agent. A hook ask in autopilot is denied, per the hooks reference.
copilot -p "Show me this week's commits and summarize them" \
--allow-tool='shell(git)' \
--no-ask-user \
--output-format json
--no-ask-user stops the agent pausing for input. --output-format json emits JSONL. --secret-env-vars keeps named variables out of logs; GITHUB_TOKEN and COPILOT_GITHUB_TOKEN are redacted by default. --trust-folder trusts hooks, MCP servers and plugins for one run but “does not grant tool, path, or URL permissions.”
Limits
- Session approvals are broad. Approving one
rmfor the session approves everyrm. - Folder trust is a heuristic. GitHub does not guarantee files outside it are protected.
- Assisted mode is a model’s judgment. It means fewer prompts, but you cannot audit the rule in advance.
- Hook timeouts fail open, policy hooks included. A slow check is a skipped check.
- Filed bugs. One release did not honour a
preToolUsedeny (copilot-cli#3874), and plugin-bundledpreToolUsehooks did not fire (copilot-cli#2540). Test a deny on the version you run. - No log of decisions. The docs say where approvals are saved, not where each allowed, prompted or denied call is recorded. A
postToolUsehook that writes somewhere you control gives you one. - Subagents. How allow and deny rules carry into
/fleetsubagents is not documented.
ACP has a Copilot hook that covers the CLI and VS Code agent mode with one hook file. It checks shell commands, file edits and MCP calls, and it records each call. Where Copilot’s ask has no prompt to show, the call is blocked and waits for your approval on the console or in the email; then Copilot retries. Copilot’s cloud coding agent is not governed today, because its sandbox has no ACP credentials. Copilot hooks fail open on timeout, and the hook ACP installs fails open when ACP is unreachable unless you set ACP_FAIL_MODE=closed or write closed to ~/.acp/failmode. See the Copilot install guide.
Frequently asked questions
How does GitHub Copilot CLI decide which commands to run without asking?
Read-only tools such as file reads, search and read-only shell commands run without a prompt. Destructive shell commands, file edits and URL access prompt, unless an –allow-tool rule, a saved approval or an allow-all mode covers them. A –deny-tool rule blocks the tool outright and beats every allow.
What happens to Copilot CLI permission prompts in -p mode or CI?
There is no prompt. GitHub’s programmatic reference says that without any permission options, requests that need approval are denied. You pass –allow-tool rules, –assisted-approval or –allow-all for the run, or answer requests with a permissionRequest hook.
Does GitHub Copilot CLI have hooks?
Yes. Copilot CLI runs command hooks on events including preToolUse, postToolUse and permissionRequest, from .github/hooks/, ~/.copilot/hooks/, settings files, plugins and admin policy directories. A preToolUse hook returns permissionDecision allow, ask or deny.
Does deny beat --allow-all in Copilot CLI?
Yes. GitHub’s docs state that deny rules always take precedence over allow rules, even when –allow-all is set or a matching approval has been saved.
Does Copilot CLI have a sandbox?
Yes. /sandbox enable turns on local sandboxing, which restricts the commands and tools Copilot runs on your behalf, not the CLI process itself. copilot –cloud runs the whole session in a GitHub-hosted sandbox.
Where to read more
- About GitHub Copilot CLI
- Allowing and denying tool use
- Copilot CLI command reference
- Copilot CLI programmatic reference
- Autopilot mode
- Copilot hooks reference
- github/copilot-cli on GitHub
Running coding agents? ACP records each tool call its hook sees and makes the dangerous shell commands (a force-push, destructive SQL, curl | sh) wait for you. One command, free up to 5 agents:
curl -fsSL https://agenticcontrolplane.com/install.sh | bash
irm https://agenticcontrolplane.com/install.ps1 | iex