GitHub Copilot setup
ghcp is the agent runtime behind every AI task. It is the default
provider: on ai@1, and today it
is the only one that ships — so a task that names no provider runs here,
and so does every SDD phase.
It is a prerequisite, not a plugin. Nothing is bundled and nothing is installed for you. Two things have to be true on the machine before an AI task can run, and this page is both of them.
Skip this page entirely if you are not writing AI tasks. run:,
shell@1, pwsh@1 and file@1 need none of it.
- What must be true
- 1. The Copilot CLI
- 2. A credential
- What you do not need
- What
ai@1hands toghcp - The environment the CLI child gets
- Every tool is approved automatically
- How long a session may run
- Naming a different provider
- When it fails
- Next
What must be true
| Checked | ||
|---|---|---|
| The GitHub Copilot CLI is installed | on PATH, or pointed at by COPILOT_CLI_PATH |
on the first AI task, not at startup |
| A credential is available | the editor’s GitHub sign-in, or the CLI’s own login | when the session is created |
That is the whole list. Neither is checked until an AI task actually runs — a window that never runs one never pays for the check and never nags you about it.
1. The Copilot CLI
npm install -g @github/copilot
That is the install GitHub’s own tooling tells you to run, and it puts
copilot on PATH, which is where this looks first.
Why it is not bundled
The extension does not talk to GitHub itself. It drives the Copilot CLI — a separate program — through GitHub’s SDK. The SDK is the client; the CLI is the thing that runs.
The CLI is roughly 340 MB per platform, across eight platforms.
Shipping that inside an extension is not sensible, so it is a
prerequisite you install, exactly like PowerShell is for shell: pwsh.
Pointing at a copy you already have
If the CLI is somewhere that is not on PATH, name it:
tasks:
draft:
uses: ai@1
env:
COPILOT_CLI_PATH: D:\tools\copilot\copilot.exe
args:
prompt: Summarise the commits since the last tag.
COPILOT_CLI_PATH is honoured wherever an environment variable can be
set — the task’s env:, your shell, or the machine. A copy installed
beside the SDK is found automatically, so most people never set it.
Point it at the executable, not at a .js file. Inside VS Code a
.js entry point gets launched through Code.exe, the CLI’s argument
parser mistakes that for Electron, and the run dies with
error: too many arguments. Expected 0 arguments but got 1.
What it says when the CLI is missing
GitHub Copilot CLI not found. Local Workflows drives the CLI directly rather than the Copilot extension, and does not bundle it (it is ~340 MB per platform). Install it with
npm install -g @github/copilot, or point COPILOT_CLI_PATH at a copy you already have.
This is checked deliberately and early. Without the check the same
machine fails with a native module failing to load, or a spawn error
naming a path inside node_modules — both of which read as “the
extension is broken” rather than “install this one thing”.
2. A credential
The Copilot CLI keeps its own credential store. It knows nothing about the editor’s. Being signed in to Copilot in VS Code buys the CLI nothing on its own — it starts, finds no authentication, and the turn dies.
So a credential is looked for in this order:
| Where it comes from | When it applies | |
|---|---|---|
| 1 | The GitHub sign-in VS Code already holds, requested with the read:user scope |
any machine signed in to GitHub in the editor |
| 2 | The CLI’s own login — whatever copilot holds from you signing in to it directly |
when 1 produced nothing, or you declined |
The one dialog you will see
The editor’s sign-in is asked for silently first. On any machine where this extension has been granted access once, no dialog ever appears again.
But a silent request returns nothing until that first grant has happened — so on the very first AI run you get VS Code’s own consent dialog. That moment is safe to ask in: a run only starts from a click, so someone is watching.
Declining is not fatal. It falls through to the CLI’s own login, and if that is signed in the task runs normally.
Nothing is read out of your files
No credential is asked for, stored, or read out of a tasks.yml. A
credential in a workflow file is a credential in someone’s git history,
which is why there is no key for one.
What you do not need
The GitHub Copilot VS Code extension. Nothing here calls it. A machine with it installed and signed in still needs the CLI; a machine without it works fine with the CLI.
Copilot is also deliberately not declared as an extension dependency — that field force-installs it, and you should not get Copilot pushed onto you for tasks you may never write.
What ai@1 hands to ghcp
Every setting on the task is passed straight through. ghcp adds no
settings of its own, which is what makes swapping a vendor one line.
| On the task | What ghcp does with it |
|---|---|
model: |
the model the session runs on. auto lets the provider pick |
system: |
appended to the SDK’s own system message, so its environment context, tool instructions and guardrails all still stand |
allow: / deny: |
set once on the session as its available and excluded tools, declaratively — not decided per request |
mcp: |
MCP servers the session may call |
attachments: |
files handed over by path, with name as what the agent sees them called |
env: |
layered over the environment the CLI child gets — see below |
the task’s cwd |
the session’s working directory. One client per session, so two tasks can work in different folders at once |
Full arg table, mode: review, and the mcp: guidance:
ai@1.
Model names
They are the provider’s vocabulary, not this extension’s. ai@1
passes the string through and never validates it. model: auto is the
sane default — a pinned name goes stale.
The environment the CLI child gets
Three layers, in this order:
- The whole of the editor’s environment. Merged, never replaced —
handing the child only the task’s declared
env:left it with noPATHand noAPPDATA, so it could not even find your Copilot sign-in. - The task’s own
env:, layered on top. The same order arun:task gets. COPILOT_CLI_PATHresolved to the native binary, andELECTRON_RUN_AS_NODE=1. Both are set for you.
Every tool is approved automatically
ghcp approves each tool the agent asks for, without a card and without
a pause. There is no per-tool permission prompt anywhere in the run.
The agent reads, writes and works in your repository. The place a
human decides anything is a trigger: manual task you put in the file.
See It enforces no gate
for why it is built this way, and use allow: / deny: to set policy
once instead.
How long a session may run
The task’s own timeout: is the limit that matters — it is the one that
actually stops the work.
Underneath it there is a one hour backstop on waiting for a session to report itself idle. That is not a policy; it only stops the extension waiting forever on a session that will never say it has finished.
Naming a different provider
provider: is the only place a vendor is named, so swapping one is that
line:
plugins:
ai:
uses: ai@1
args:
provider: ghcp
model: auto
Only providers this build registers are accepted. A name it does not know fails before the session starts, with the list of the ones it does:
No agent provider ‘claude’ is registered. Available: ghcp.
That is a configuration error, and it reads as one — it is not reported as an agent that could not finish.
When it fails
Every AI task logs one system line naming the provider and the folder it is working in, which is where to start:
ghcp agent working in D:\src\my-repo
| What you see | What it means |
|---|---|
GitHub Copilot CLI not found... |
the CLI is not on PATH and COPILOT_CLI_PATH is unset — see above |
No agent provider '...' is registered. Available: ghcp. |
a typo in provider:, or a vendor this build does not ship |
MCP server 'x' needs a 'command' to launch - or a 'type: http' and a 'url'. |
a malformed mcp: block. Checked before any session opens |
The agent could not finish: ... |
the session started and then failed. Authentication failures land here |
Cancelled before the agent finished. |
the run was stopped |
Authentication looks like the fourth row. The editor’s sign-in was declined or absent and the CLI has no login of its own, so the session is created without authentication and every turn dies. Fix it by signing in to the CLI directly, or by granting the editor’s request the next time it is offered.
The one-line message is the headline. The full story — the error’s
own properties, its cause chain and the stacks — is written to the
task’s log, because a one-line message flattens away exactly what you
need to debug a timeout or a rejected token.
Next
- Your first spec — the first thing that needs all of the above.
ai@1— every argument, andmode: review.- SDD config — setting
provider:andmodel:once for every phase.