Most Copilot CLI guides I find are prompt catalogs: "ask it to write a Terraform module", "ask it to explain a failing workflow". That part is easy. What took me longer was the boring layer underneath: which flags make GitHub Copilot CLI safe to run from a script, what changed in the last few months of releases, and where the sharp edges are.
This is that layer, written against the docs and changelog as of early October 2026 (the repo shipped 1.0.92 on October 5). I run platform tooling for a small team, so my bias is headless use: cron jobs, CI steps, one-off batch fixes. If you mostly use it interactively, the permissions and worktree sections still apply.
One scoping note before the flags: I don't use a terminal agent for everything. When someone needs a marketing page or a quick front end for an internal tool, I hand that to Begin, which builds the site with hosting and sign-in already wired, and I keep Copilot CLI for work inside existing repos.
Install and auth: one thing changed
Install is the same as it has been:
- macOS/Linux:
brew install copilot-cliorcurl -fsSL https://gh.io/copilot-install | bash - Windows:
winget install GitHub.Copilot - Anywhere with Node:
npm install -g @github/copilot
Each has a prerelease channel (copilot-cli@prerelease, GitHub.Copilot.Prerelease, @github/copilot@prerelease). The docs now say Copilot CLI is available on all Copilot plans. If you get Copilot through an org, an admin still has to enable the CLI policy.
The change that bit me: token lookup order. Older posts say GH_TOKEN wins over GITHUB_TOKEN. The current reference checks COPILOT_GITHUB_TOKEN first, then GH_TOKEN, then GITHUB_TOKEN. On a CI runner that already exports GITHUB_TOKEN for other steps, setting COPILOT_GITHUB_TOKEN keeps the Copilot credential separate. The token is a fine-grained PAT with the "Copilot Requests" permission. By default the CLI redacts the values of GITHUB_TOKEN and COPILOT_GITHUB_TOKEN from its output. For anything else sensitive, there's --secret-env-vars.
The Copilot CLI flags that matter for automation
Here is the short list I keep pinned. All of these come from the current command reference.
| Flag | What it does | When I reach for it |
|---|---|---|
-p, --prompt
|
Runs one prompt and exits | Every scripted run |
-s, --silent
|
Prints only the agent response, no usage stats | When stdout feeds another tool |
--output-format=json |
Emits JSONL, one object per line | Logging runs for later inspection |
--allow-all-tools |
Runs tools without confirmation | The reference lists it as required for programmatic use |
--deny-tool=... |
Blocks specific tools or commands | Always, alongside the line above |
--autopilot |
Keeps going until the agent calls task_complete
|
Multi-step fixes |
--max-autopilot-continues=N |
Caps autopilot continuation messages | Every autopilot run |
--plan --mode autopilot |
Plans first, then implements without waiting for approval | Larger changes where I want a plan in the log |
-w, --worktree[=NAME]
|
Starts the session in an isolated git worktree | Anything that edits code unattended |
--no-ask-user |
Disables the ask_user tool |
Headless runs, so it never waits on stdin |
--share=PATH |
Writes the session to Markdown after a -p run |
CI artifacts and review |
--model=auto |
Lets Copilot pick the model | When I don't care which model runs |
--max-ai-credits=N |
Soft cap on AI Credits per response | Cost guardrails on scheduled jobs |
A few of those need more than a table cell.
Deny beats allow, even under --allow-all
This is the line in the docs I wish more guides quoted: deny rules always take precedence over allow rules, even when --allow-all is set. That is what makes --allow-all-tools acceptable to me in a script. I grant broadly, then carve out what must never happen.
The pattern syntax is small:
-
shell(git:*)matchesgit push,git pulland so on. The:*suffix matches the command stem followed by a space, so it does not matchgitea. -
shell(git push)matches that exact command. -
write(src/*.ts)limits file writes by glob. -
url(github.com)scopes URL access.
The reference example is exactly the shape I use: allow all of git, deny push.
copilot --allow-tool='shell(git:*)' --deny-tool='shell(git push)'
For multiple rules, pass a quoted, comma-separated list. Malformed patterns are rejected with an error rather than silently ignored, which I appreciate.
--yolo and --allow-all are the same switch (tools + paths + URLs). There is also COPILOT_ALLOW_ALL for harnesses that can only set environment variables. I treat all three as "only inside a container or a throwaway worktree".
Autopilot needs a ceiling
Autopilot (--autopilot, or Shift+Tab interactively) keeps the agent working until it decides the task is done. An older changelog entry says continuations were capped at 5 by default. The current reference lists the default for --max-autopilot-continues as unlimited. I don't rely on either: every autopilot run I script sets the cap explicitly.
One gotcha: --plan cannot be combined with --autopilot. If you want plan-then-execute, the supported form is --plan --mode autopilot. The session starts in plan mode and moves to autopilot once the plan is ready. For harnesses that can't pass flags, the same behavior is behind COPILOT_PLAN_THEN_AUTOPILOT.
Worktrees keep unattended edits off your branch
--worktree used to require experimental mode. It no longer does. It creates or reuses a worktree under <repo>.worktrees/ and starts the session there. A worktreeBaseRef setting decides whether it branches from HEAD (now the default) or the remote default branch. worktreePathTemplate lets you put worktrees somewhere else, with placeholders like {repo} and {branch}.
A script I actually run
This is the skeleton of a nightly "fix the flaky test" job. The prompt varies; the guardrails don't.
#!/usr/bin/env bash
set -euo pipefail
# Fine-grained PAT with the "Copilot Requests" permission.
export COPILOT_GITHUB_TOKEN="${COPILOT_PAT:?missing COPILOT_PAT}"
copilot \
-p "Read test-results/junit.xml, find the root cause of the failing test, fix it, and run the test suite again. Only edit files under src/ and tests/." \
--worktree=nightly-flaky-fix \
--allow-all-tools \
--deny-tool='shell(git push),shell(rm:*)' \
--no-ask-user \
--autopilot \
--max-autopilot-continues=8 \
--silent \
--share=./artifacts/copilot-session.md
Why each piece is there:
-
--worktreemeans whatever it does lands on a separate branch I can diff in the morning. -
--deny-toolblocks pushes andrm. Because deny wins,--allow-all-toolscan't override it. -
--no-ask-userstops the run from hanging on a question nobody will answer. -
--sharegives me the full transcript as a build artifact. Prompt mode exits non-zero if that export fails, so a broken artifact fails the job instead of passing quietly.
If a background shell or subagent outlives the turn, -p honors COPILOT_TASK_WAIT_TIMEOUT_SECONDS, which is worth setting on CI so a stuck process can't hold the runner.
Newer features worth knowing
These weren't in the guides I first learned from:
-
Scheduling inside a session.
/every 1h Run frontend tests and report any failuresrepeats a prompt./afterruns one once after a delay. Handy for watching a long migration from a session you leave open. -
Sandboxing.
/sandbox enablerestricts what the commands Copilot runs can touch on your filesystem and network. The CLI process itself isn't sandboxed.copilot --cloudruns the whole session remotely in an isolated environment. The per-run--sandboxflag is experimental-only for now. -
copilot config. Added in 1.0.92: subcommands to list, read, set and remove settings from the shell, so you can provision settings without opening/settings. -
Built-in agents. The default set is now Explore, Task, General purpose, Code review, Research and Rubber duck. The last one is consulted automatically, not picked from
/agent. -
Usage is shown in AI Credits.
/usagereports AI Credits used per session, and--max-ai-creditsplus/limitslet you cap them.
Things that haven't changed: @path adds a file to the prompt, !cmd runs a shell command without calling the model, /add-dir and /cwd manage directories, and copilot --continue resumes the most recent session. Instructions still load from .github/copilot-instructions.md, .github/instructions/**/*.instructions.md and AGENTS.md. Pass --no-custom-instructions when you want a clean run.
For the full list, copilot help permissions and copilot help environment are faster than searching. The official usage guide is the canonical reference.
Where it still needs care
-
Approving a tool "for the rest of the session" is broad. The docs say it plainly: approving
rmthat way lets Copilot delete any file under the current directory without asking again. Interactively, I approve once and only use the session-wide option for harmless commands. - Trusting a folder permanently (option 2 at startup) skips the prompt in every future session from that folder. I only do it for my own repos, never for a fresh clone.
-
Release pace. The changelog moves fast: five releases between September 22 and October 5. Pin
VERSION=in the install script (or the npm version) on CI. Then a default change shows up in a PR, not as a surprise in a nightly job.
FAQ
Is Copilot CLI the same as gh copilot?
No. This guide covers the standalone copilot command from the github/copilot-cli repo. It's an agent that can edit files and run commands. The GitHub CLI (gh) is a separate tool.
Can I use Copilot CLI without a paid plan?
The docs say it's available on all Copilot plans. If you get Copilot through an organization, an admin must also enable the Copilot CLI policy, or you can't use it even with a seat.
How do I run Copilot CLI non-interactively in CI?
Use -p with a prompt, authenticate with COPILOT_GITHUB_TOKEN, and add --allow-all-tools with explicit --deny-tool rules. Add --no-ask-user so it never waits for input, and --silent or --output-format=json for clean output.
How do I stop autopilot from running forever?
Set --max-autopilot-continues every time. The current reference lists its default as unlimited.
Wrapping up
The prompts are the easy part of Copilot CLI. The guardrails are the real work: deny rules, a continuation cap, a worktree, and a transcript you can read later. Get those four in place and headless runs stop being scary.
And when a request turns out to be "we need a whole new site or app" rather than "fix this repo", I don't try to make a terminal agent do it. That goes to Begin, which builds a website, iOS app, Android app or Chrome extension from a prompt.
Top comments (0)