Skip to content

GitHub Copilot CLI: Complete Guide

Lesson 1 of 9Intermediate → Advanced15 min readGitHub Copilot & AI Engineering · Copilot CLIVerified: GitHub Copilot CLI command reference and configuration documentation, September 2026

Copilot CLI is an agent in your terminal. It reads your repository, runs commands, edits files, calls GitHub, and asks permission before doing anything that touches your system.

That last property is what makes it the best surface for learning how agents should be operated: the permission model is explicit, visible, and yours to configure.

Copilot CLI runs on Linux, macOS, and Windows via PowerShell or the Windows Subsystem for Linux.

Terminal window
copilot

What it doesStarts an interactive Copilot CLI session in the current directory.

Why we run itThe interactive session is the primary mode; the current directory determines what it can see by default.

Expected resultAn interactive interface. If you are not signed in you will be prompted to run /login.

Authentication uses OAuth:

Terminal window
copilot login

--web-flow forces browser-based authentication, --device-code forces the device flow, and --with-token reads a token from standard input. --host targets a GitHub Enterprise instance.

For non-interactive use — a script, a CI step, a one-off — the -p form runs a single prompt:

Terminal window
copilot -p "Show me this week's commits and summarize them" --allow-tool='shell(git)'

Note the explicit allowance. Non-interactive mode cannot prompt for approval, so anything it needs must be permitted up front — which forces you to state what the task requires.

The most important part of this article. Every tool use that touches your filesystem or runs a command requires approval.

ControlEffect
Approve onceThis call only
Approve for sessionThis class, for this session
--allow-tool='shell(git)'Pre-approve a specific tool class
--deny-tool=...Refuse regardless
--allow-all-toolsApprove everything
/allow-all or /yoloThe same, from inside a session
/permissionsManage permissions and trust settings

The narrow allowance is the one to reach for. --allow-tool='shell(git)' lets an agent run Git freely while still asking before anything else — which keeps a Git-heavy session fast without giving away the boundary.

Inside a session, slash commands manage the environment rather than the conversation. The current list is always /help; these are the ones that recur.

CommandDoes
/helpThe authoritative current command list
/loginAuthenticate
/modelDisplay or set the model
/contextContext window usage and visualisation
/compactSummarise history to reclaim context
/clear, /new, /resetStart a new conversation
/sessionCreate, name and manage sessions
/resumeReopen a previous session
/cwd, /cdChange or show the working directory
/add-dir PATHAllow access to a directory, loading its .github/skills and .github/agents
/agentBrowse and select available agents
/planPlanning mode for multi-step work
/review [FILE]Review code changes or file contents
/diffReview changes in the current directory
/mcpManage MCP server connections
/permissionsManage permissions and trust
/toolsManage available tools
/envShow loaded instructions, MCP servers, skills, agents, hooks, plugins
/sandboxManage sandboxed execution
/delegateDelegate changes to a remote repository with a generated pull request
/fleetParallel subagent execution
/shareGenerate or redeem session share codes

Four are worth knowing before you need them.

/env shows everything currently loaded — instructions, skills, agents, hooks, MCP servers, plugins. This is the first command to run when behaviour is unexpected, because “is my configuration even loaded” is the most common answer.

/context shows window usage. A session getting vaguer is usually a full window, and this is how you confirm it rather than guessing.

/add-dir brings another directory into scope and loads its skills and agents. That is a scope decision as much as a convenience — you are granting file access and adopting configuration at the same time.

/plan produces an approach before actions. The cheapest intervention point in any agentic interaction.

The default mode acts; plan mode, reachable with Shift+Tab, collaborates on the approach first.

The rule from agent mode applies identically: correcting a plan costs a sentence; correcting six edited files costs a review. For anything where the approach is not obvious, plan first.

Copilot CLI reads repository configuration, which means the work you did in the Copilot cluster applies here.

InstructionsAGENTS.md, .github/copilot-instructions.md and CLAUDE.md, plus path-specific instructions and personal instructions from ~/.copilot/. File references with @ followed by a relative path let one file include another rather than duplicating content.

Custom agents — specialised personas with restricted tools. See Custom Agents.

Agent skills — loaded when relevant, from .github/skills/ among other locations, with personal skills in ~/.copilot/skills/ or ~/.agents/skills/.

Hooks — deterministic lifecycle control from .github/hooks/*.json. The only mechanism here that enforces.

MCP servers — external tools and data.

Plugins — bundles of the above, managed with copilot plugin and copilot plugins.

copilot init initialises custom instructions for a repository, which is a reasonable starting point if you have none.

Terminal window
copilot plugins list

What it doesLists every plugin, MCP server, skill, instruction source and language server currently configured, without entering a session.

Why we run itIt answers 'what is actually loaded' from outside a session, which is the fastest way to diagnose configuration that seems inert.

Expected resultGrouped text, or JSON with --json.

--kind filters to mcp, skill, instruction, plugin or lsp, and --json makes it scriptable.

Three command families for the configuration surface:

Terminal window
{/* List, add and remove agent skills */}
copilot skill
Terminal window
{/* Manage MCP server configurations */}
copilot mcp
Terminal window
{/* Enable, disable or remove a plugin, MCP server or skill */}
copilot plugins enable NAME --skill
copilot plugins disable NAME --mcp
copilot plugins remove NAME --plugin

The enable and disable operations are useful for diagnosis: turning something off and seeing whether behaviour changes is more reliable than reasoning about what a piece of configuration is doing.

Everything else the CLI reads influences behaviour. Hooks control it, which makes them the most important configuration on this page for anything that must not happen.

A hook is defined in .github/hooks/*.json:

.github/hooks/validation.json
{
"version": 1,
"hooks": {
"preToolUse": [
{
"type": "command",
"bash": "scripts/check-tool-use.sh",
"timeoutSec": 10
}
]
}
}

The events include sessionStart, sessionEnd, userPromptSubmitted, preToolUse, postToolUse, postToolUseFailure, agentStop, subagentStart, subagentStop, errorOccurred, notification and permissionRequest.

preToolUse is the one that matters. It runs before the agent uses any tool and can approve or deny the call. A command hook denies by writing a decision to stdout:

{
"permissionDecision": "deny",
"permissionDecisionReason": "Reason shown to the agent"
}

For command hooks, exit code 2 is treated as a deny, and the tool call is blocked. Non-timeout errors also fail closed for preToolUse — which is the correct default for a security control and worth knowing, because a broken hook script blocks rather than passes.

Hooks can also be http — posting to a URL — or prompt, which auto-submits text at session start.

The practical uses: blocking commands touching production paths, requiring a secret scan before a commit, logging tool use for audit, and enforcing organisation policy that instructions can only request. Building Repository AI Agents covers the design properly.

The security consideration specific to this surface.

The CLI runs in your shell. It inherits your environment variables, your cloud CLI sessions, your kubectl context and whatever your credential helper will hand over.

That is convenient — it is why the CLI can do useful work without configuration — and it means the agent’s effective permissions are your permissions.

The rules:

Do not run it in a shell with production credentials loaded. No task in this cluster requires them.

Know your context before letting it run context-sensitive commands. kubectl config current-context and the cloud equivalent, before rather than after.

Prefer read-only credentials for anything diagnostic, which is most of what you will do.

Use a scoped, expiring token where a token is needed at all, following fine-grained tokens.

Two commands that change the shape of what the CLI can do, and both deserve care.

/delegate hands work to a remote repository, producing a generated pull request. That is the CLI entry point to delegation — the same model as the cloud agent, started from your terminal rather than from an issue.

The distinction worth holding: everything else in the CLI happens on your machine and you watch it. /delegate does not, which means the controls move from supervision to scope-and-review. Everything the agents cluster says about delegation applies.

/fleet enables parallel subagent execution of parts of a task. Genuinely useful for work that decomposes — analysing several services, applying the same change across modules — and it multiplies the review surface proportionally.

Two cautions on parallel work:

Subagent output is less visible. What comes back is a summary. For anything consequential, check what was actually done rather than what was reported.

Parallel changes can conflict. Several agents editing a shared file produces exactly the merge problem the conflict lesson describes, with the added difficulty that nobody understood either side’s intent.

Scheduling exists too — /every for recurring prompts and /after for one-off delayed ones. Useful, and worth the same scrutiny as any other automation that runs without you present.

Copilot supports sandboxed execution, managed with /sandbox. Cloud and local sandboxes are in public preview.

The value is straightforward: a sandbox bounds what a mistake can reach. An agent running in an isolated environment cannot touch your home directory, your credentials or your other repositories, which changes the calculus on how much to approve.

Where it fits: exploratory work, anything using --allow-all-tools, and unfamiliar plugins or MCP servers. Where it does not: work that genuinely needs your local environment — a database running on your machine, a service you have port-forwarded.

Plugins bundle agents, skills, hooks and MCP or language-server configuration into an installable package. A plugin directory contains, at minimum, a plugin.json manifest at its root naming the plugin and pointing at what it provides.

Terminal window
{/* Install from a registered marketplace */}
copilot plugin install NAME

Marketplaces are defined by a marketplace.json in a repository, which is the only required component — adding it makes the repository installable from. Copilot ships with copilot-plugins and awesome-copilot registered by default.

The trust question is the whole story here. A plugin can contain hooks — shell commands that run at lifecycle points — and MCP server configuration, which grants tools an agent can invoke. Installing one is closer to adding a dependency than to changing a setting.

Apply the same standard as dependency security:

Read what it contains before installing. copilot plugins list --json shows what a plugin provides once installed; reading the repository shows it before.

Prefer known publishers, and be suspicious of a plugin with few users offering broad capability — the same signal that matters for packages.

Enterprise plugin standards exist precisely so this can be a policy decision rather than an individual one, which is the right answer for an organisation.

The CLI exposes context management more directly than other surfaces, which is useful because context exhaustion is the most common cause of an agent getting worse mid-task.

/context shows the window’s usage and a visualisation of what is in it. Worth checking on any session running longer than a few minutes.

/compact summarises the conversation to reclaim space, optionally with focus instructions telling it what to preserve. That last part matters: an unfocused compaction may summarise away the constraint you established early.

/clear starts fresh, and is frequently better than compacting. A new session with a tight goal and two attached files outperforms a compacted session that has already drifted.

/ask asks a quick side question without adding to the conversation history, which is the right tool for “what does this flag do” during a longer task — it does not spend context on a digression.

Subagents, via /fleet or automatic delegation, keep a large subtask’s reading out of the main conversation entirely. Sending “read these forty files and report which handle auth” to a subagent returns an answer without the forty files.

The signal that context is the problem: the agent re-reads files it has already read, asks about something you established earlier, or produces vaguer output than it did twenty minutes ago. None of these presents as an error, which is why /context is worth checking rather than inferring.

  1. Start in the right directory. Scope is the working directory plus anything you /add-dir.

  2. Check what is loaded. /env on a new repository, once.

  3. Use plan mode for anything non-trivial.

  4. Grant narrow allowances up front. --allow-tool='shell(git)' for Git work beats approving forty prompts.

  5. Watch /context on long sessions. Compact or start fresh rather than pushing through.

  6. Review the diff, not the transcript. git diff after the session, always.

  7. Branch first for anything that edits files.

Being concrete about the fit, because “an agent in the terminal” is vague.

Anything where the context is command output. A failing build, a kubectl describe full of events, a Terraform plan, a stack trace in a log file. The CLI reads them directly rather than you copying them into a browser, and that fidelity difference is substantial.

Iterative diagnosis. Run, read the error, adjust, run again. The loop is the point, and it is painfully slow through a chat window.

Git work. The repository is right there, the commands are safe to read and dangerous to run, and the permission model maps onto that distinction precisely. See Copilot CLI for Git.

Reviewing your own changes. /review and /diff operate on your working tree without you assembling anything, which removes the friction that makes people skip self-review.

Multi-step operational tasks where each step’s output determines the next.

Where it is the wrong tool: anything you want a durable, reviewable record of — sessions are local and ephemeral, so that is a pull request. Anything requiring a graphical view of a diff. And anything you would not want happening while you looked away, which is delegation rather than an interactive session.

The non-interactive form makes CI use possible, and it deserves a specific warning.

- name: Summarise the changes for the release notes
run: |
copilot -p "Summarise the commits in this range for release notes" \
--allow-tool='shell(git)' > notes.md
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Three constraints that apply in CI and not interactively.

Nothing can prompt. Every permission must be granted up front, which means you must state exactly what the job needs. That is a feature — it forces the scope to be explicit and reviewable in the workflow file.

Never --allow-all-tools in CI. In an interactive session it is a bad idea you can interrupt. In CI it is an unsupervised agent with the job’s credentials and no one watching. If a task seems to need it, the task is wrong for CI.

Scope the credentials to the task. The job’s GITHUB_TOKEN permissions are the agent’s permissions. Read-only unless there is a reason, following least-privilege workflow permissions.

The tasks that suit CI are the ones producing text for a human to read — a release note draft, a summary of what changed, an analysis of a failure. Tasks that produce changes belong in a pull request from a delegated agent, where they get reviewed, rather than in a job that commits.

--allow-all-tools on a repository that matters. It removes the control.

Running in a shell with production credentials. The agent inherits them.

Not checking /env. Configuration that is not loaded looks identical to configuration being ignored.

Ignoring /context. A full window presents as the agent getting worse, not as an error.

/add-dir without thinking about scope. It grants file access and loads that directory’s agents and skills.

Approving a command because the explanation was convincing. The explanation came from the same system.

Treating agent-run tests as CI. Local evidence, not the gate.

Using it to troubleshoot with broad permissions. The situation where you can least evaluate the commands is the one where they should be most scrutinised.

The habit this whole cluster rests on, made concrete.

When the CLI proposes a command, four questions take about five seconds:

What does it actually do? Not what the explanation says — what the command does. If you cannot read it, that is the answer: ask what it does before approving.

What does it touch? Which files, which host, which cluster, which account. A command with a path is easier to evaluate than one with a glob.

Is it reversible? git status is free. git reset --hard is not. kubectl delete is not. terraform apply is definitely not.

What would I do if it were wrong? If the answer is “I do not know”, do not run it yet.

Two patterns worth insisting on for anything consequential:

Ask for the read-only version first. terraform plan before apply, kubectl diff before apply, --dry-run where it exists, git status before anything that changes state. A useful instruction to give the agent directly:

Show me read-only commands to understand the situation first. Do not propose anything that changes state until I have shown you the output.

Make it explain destructive commands unprompted. A repository instruction along the lines of “for any command that deletes, force-pushes, or modifies infrastructure, state what it does and what would be lost before proposing it” changes the default behaviour usefully.

The framing that carries across this whole cluster: generating a command is research; running it is a decision. The CLI makes the first cheap, and it must not make the second automatic.

Where configuration comes from, since the CLI reads more sources than any other surface.

Repository.github/ in the working directory: instructions, skills, agents, hooks.

Directories added with /add-dir — their skills and agents are loaded too, which is the part people miss.

Personal~/.copilot/, including personal instructions and skills in ~/.copilot/skills/ or ~/.agents/skills/. These follow you across projects.

Plugins — whatever they bundle, from wherever they were installed.

Organisation and enterprise — custom agents from an organisation’s .github or .github-private repository. Note that organisation-level policies for MCP servers are not currently supported, which is a real gap for anyone wanting to centrally restrict them.

Two practical consequences.

/env is the ground truth. With this many sources, reasoning about what should be loaded is less reliable than asking.

Personal configuration can surprise colleagues. A skill in your home directory shapes your results and nobody else’s. When explaining a workflow to somebody, check whether it depends on something only you have — this is a common source of “it works for me”.

Copilot CLI is an agent with your shell, your credentials and your repository, that asks before it acts. Everything about using it safely is deciding, in advance and while thinking clearly, what it should not have to ask about.

  • copilot starts an interactive session; -p runs a single prompt non-interactively
  • Non-interactive mode requires explicit allowances, which forces you to state what the task needs
  • Narrow allowances like --allow-tool='shell(git)' beat blanket approval
  • /env shows what configuration is actually loaded; /context shows window usage
  • /add-dir grants file access and loads that directory’s skills and agents
  • Plan mode makes the approach reviewable before any action
  • The CLI reads AGENTS.md, copilot-instructions.md, CLAUDE.md, skills, hooks, agents and MCP
  • It runs in your shell and inherits your environment and credentials
  • Sandboxes bound what a mistake can reach, and are in public preview

Use a disposable repository.

  1. Start a session and run /env. Predict: is anything loaded that you did not expect?

  2. Ask it to summarise recent commits. Predict: does it ask permission before running git log?

  3. Restart with --allow-tool='shell(git)'. Predict: which prompts disappear, and which remain?

  4. Ask for something requiring a non-Git command. Predict: does the allowance cover it?

  5. Use /plan for a multi-file change. Read the plan. Predict: would you have caught a wrong approach?

  6. Run a long session and watch /context. Predict: at what point does output quality change?

  7. Add .github/copilot-instructions.md with a specific rule and run /env again. Predict: does it appear?

  8. Delete the repository.

AI-assisted engineering learning pathEleven lessons on getting value from Copilot and agents without giving up review discipline.