Skip to content

Latest commit

 

History

History
311 lines (247 loc) · 16.2 KB

File metadata and controls

311 lines (247 loc) · 16.2 KB

GitHub Copilot CLI

OpenAgents supports GitHub's official Copilot CLI — the standalone executable copilot, distributed as the npm package @github/copilot.

This is not the retired gh copilot extension. The old gh extension install github/gh-copilot flow (binary gh, subcommand gh copilot) is deprecated. OpenAgents detects and launches the copilot executable only and never invokes gh.

  • Internal agent id: copilot
  • User-facing name: GitHub Copilot CLI
  • Adapter: packages/agent-connector/src/adapters/copilot.js
  • Stream parser: packages/agent-connector/src/adapters/copilot-stream-parser.js

Installation

Install from any official source — OpenAgents auto-detects the copilot executable regardless of how it got there:

Method Command Notes
npm (default) npm install -g @github/copilot Requires Node.js. This is what the launcher's installer runs.
Homebrew brew install copilot (if/when published) No Node.js requirement.
WinGet winget install GitHub.Copilot (if/when published) No Node.js requirement; resolves via %LOCALAPPDATA%\Microsoft\WinGet\Links.
Standalone binary per GitHub's instructions No Node.js requirement.

The npm path requires Node.js. Homebrew / WinGet / standalone-binary installs do not require Node.js, and OpenAgents does not force a Node.js requirement on those — only the npm install command is Node-gated.

Detection details

  • OpenAgents looks for copilot (copilot.cmd / copilot.exe on Windows) across: the isolated runtime prefix (~/.openagents/runtimes/copilot), the enriched PATH, the npm global prefix, and common install locations (Homebrew, ~/.local/bin, WinGet Links).
  • An install marker is written only after a successful install and never overrides real binary detection.
  • A binary on PATH always wins over a stale marker.

Minimum supported version

1.0.0 — declared in registry.json (install.min_version), mirrored in the adapter (CopilotAdapter.MIN_VERSION) and asserted equal by a test.

Basis. The adapter requires --output-format=json (JSONL) — which per GitHub's investigation was introduced in 0.0.422 — plus non-interactive -p with --no-ask-user, granular --allow-tool/--add-dir, --resume/--name session control, and --secret-env-vars/--no-remote. Per the spec ("采用所有必需能力中的最高版本"), the floor is the GA 1.0 line, which is the first release series where the full set is present and stable and the documented CLI Reference applies. The integration was verified end-to-end against 1.0.63 (the current latest; published range is 0.0.3261.0.63).

The gate is generic — any registry entry may declare install.min_version (see packages/agent-connector/src/installer.js). If GitHub's changelog later pins an exact earlier 0.0.x build that has all required flags, lower this one field (and the adapter constant) accordingly.

Two enforcement points share the same floor:

  • installer.healthCheck('copilot') for the launcher UI (table below).
  • CopilotAdapter._checkVersionGate() runs copilot --version before spawning a turn and refuses (with an upgrade message) when below the floor, so an old CLI never gets a turn that would fail with unknown option.

Health-check behaviour (installer.healthCheck('copilot')):

Detected version installed compatible ready Behaviour
min_version true true per auth Normal.
< min_version true false false Launch blocked, upgrade prompt. Never shown as "not installed".
unparseable true null (unknown) per auth Not blocked, not falsely "compatible".
not found false null false Offer install.

Version results are cached briefly and the cache is cleared on install/uninstall.


Authentication

The Copilot CLI authenticates against GitHub, not an OpenAgents-collected API key. Verified token precedence (from copilot login --help / copilot help environment, v1.0.63):

  1. COPILOT_GITHUB_TOKEN
  2. GH_TOKEN
  3. GITHUB_TOKEN

If none is set, the CLI uses a token from a prior copilot /login (stored in the system credential store, else plaintext under ~/.copilot/), or a gh auth session. Supported token types: fine-grained v2 PATs (github_pat_…) with the "Copilot Requests" permission, OAuth tokens from the Copilot CLI app, and OAuth tokens from gh. Classic ghp_ PATs are NOT supported. GitHub Enterprise (data residency): GH_HOST / COPILOT_GH_HOST or copilot login --host. BYOK custom providers: COPILOT_PROVIDER_*.

You can either:

  • Sign in interactively: run copilot once and use /login (browser device flow), or
  • Provide a token: set COPILOT_GITHUB_TOKEN (the launcher offers an optional, password-masked field for this).

How OpenAgents reports auth state (auth_status)

There is no side-effect-free, non-interactive "am I authed?" command (verified: an unauthenticated -p … --output-format json run prints the auth error to stderr, leaves stdout empty, and exits 1). So OpenAgents reports a four-state auth_status rather than a binary verdict:

auth_status Meaning
ready A token env var is present (positive signal).
unknown No token env var detected — but you may already be signed in via copilot /login, the keychain, or gh. Not a claim of "no credentials**; does not block a launch attempt.
no_credentials (Other agents) creds definitively absent.
— incompatible — Version below the floor (separate compatible:false).

Copilot is marked unverifiable in the registry, so absence of a token yields unknown, never a false "not signed in". The final authority is the CLI's own run result — auth/authorization failures are classified from live stderr (see Common errors).

OpenAgents never reads, prints, or forwards your token: it does not run commands that echo a token, never logs env-var values, never reads the system keychain contents, and never sends any token to the workspace frontend.


Using it in a Workspace

  1. Install GitHub Copilot CLI from the launcher (or npm install -g @github/copilot).
  2. Sign in (run copilot, or set COPILOT_GITHUB_TOKEN).
  3. Create a "GitHub Copilot CLI" agent and pick a project working directory. The directory must exist — the agent will not silently fall back to another folder.
  4. Send a task in the workspace. You'll receive real-time:
    • assistant text, thinking/status narration,
    • tool calls, shell commands (with exit codes), file edits,
    • and a single final answer per turn.
  5. Stop a running task from the workspace at any time.

Plan vs. Act mode

OpenAgents mode Copilot CLI behaviour
plan Launched with --plan — analysis/planning only; no write tools granted.
act (execute) Read/write/shell granted (least-privilege), scoped to the working directory via --add-dir.

Permissions actually granted

  • Filesystem access is scoped to the working directory (--add-dir <wd>). We do not pass --allow-all-paths.
  • Interactive prompts are disabled (--no-ask-user) because the workspace cannot answer them. If the CLI still asks, the turn fails with a clear message instead of hanging.
  • In act mode a minimal tool set is pre-authorized: --allow-tool=shell and --allow-tool=write (tool IDs verified against copilot help permissions, v1.0.63). We do not default to --allow-all / --yolo, nor grant network/URL access (--allow-url/--allow-all-urls).
  • --secret-env-vars=<names> is passed (only when a secret var is actually set) so the CLI strips/redacts those env values from shell/MCP environments and its own output — in addition to OpenAgents' own redaction. Only variable NAMES are passed; token values never enter argv.
  • Optional-value flags use the = form (--allow-tool=…, --resume=…, --secret-env-vars=…) as required by the CLI's argument parser.

Tool IDs are centralized in ACT_ALLOW_TOOLS in the adapter. write = file create/modify; shell = all shell commands (Copilot also supports finer matchers like shell(git:*)).


Sessions

Verified session semantics (copilot --help, v1.0.63):

  • -r, --resume[=value] resumes by session ID, task ID, ID prefix (7+ hex), or name (name match is exact, case-insensitive).
  • -n, --name <name> sets a name for a new session; --session-id <uuid> resumes by ID or fixes a new session's UUID.
  • Session/state files live under ~/.copilot (override: COPILOT_HOME).

How OpenAgents uses this:

  • It persists the real Copilot session id emitted in the JSONL session event (per channel, under ~/.openagents/sessions/) and resumes via --resume=<id>. It never impersonates a session with the OpenAgents agent id.
  • The first turn seeds a stable, working-directory-bound --name (a hash of working dir + workspace + channel), so a session for one project is never resumed against another, and concurrent agents in the same dir don't cross sessions.
  • A resume against a vanished session — verified real error Error: No session, task, or name matched '…' (stderr, exit 1, empty stdout) — is detected and transparently retried as a fresh session.

Verification status. Session flags are verified against the real CLI. Whether a non-interactive -p run emits a session id on stdout could not be confirmed (no Copilot subscription in CI — auth blocks before any model output). If, in practice, no session id is returned, resume-by-name still works via the seeded --name; if neither proves reliable, the adapter degrades to one-session-per-task and never fakes a resumed conversation.


Interrupting & cleanup

Stopping a task sends an escalating interrupt — SIGINTSIGTERMSIGKILL — to the whole process group (Unix) or via taskkill /T (Windows), so any shell/MCP children Copilot spawned are cleaned up too. After a stop the thread settles to Idle/Stopped and no further messages are pushed.


Security & privacy

What OpenAgents does

  • Tokens (COPILOT_GITHUB_TOKEN, GH_TOKEN, GITHUB_TOKEN, OAuth/fine-grained PATs), Authorization/x-api-key headers, and secret env values are redacted from all OpenAgents logs and diagnostics. Tool args and error text are redacted too.
  • The full prompt is never logged (the spawn log shows <prompt>); raw JSONL is not dumped — unknown events log only a short redacted diagnostic.
  • The prompt is a discrete -p argv element, never concatenated into a shell string — no command/argument injection.

Copilot data flows you should know about

These are Copilot CLI behaviours, not OpenAgents'. We distinguish them precisely rather than claiming "nothing is ever uploaded":

Mechanism Default What OpenAgents does
--share-gist (upload session to a secret gist) opt-in only Never passed.
--share[=path] (write a session markdown file) opt-in only Never passed.
Remote control (--remote: drive the session from GitHub web/mobile) CLI default unspecified We pass --no-remote to disable it for workspace runs.
Session history stored locally under ~/.copilot (COPILOT_HOME) on Not modified — uses your existing Copilot config.
Agentic memory (memory, cross-session fact recall) on (per CLI) Not modified — uses your existing Copilot config.
Telemetry / OpenTelemetry per your Copilot config Not enabled or configured by us.

OpenAgents does not modify your global Copilot configuration. Where the CLI supports a disable flag we use it for the run (--no-remote); session/memory storage remains governed by your Copilot setup.

Caveats

  • A prompt passed as a process argument may be visible to the OS process list / diagnostic tools while the task runs.
  • Copilot's local session history (under ~/.copilot) may contain prompts, replies, tool output, and file changes — it is local but not OpenAgents- managed; clear it via Copilot if needed.

Platform support

Platform Status
Linux Real CLI 1.0.63 verified: install, --version, --help, help environment/permissions, login --help, and unauthenticated / invalid-token / stale-resume runs (stderr + exit codes). Adapter unit-tested with a mock CLI. A successful task (real subscription) was not run — see below.
macOS Implemented (process-group interrupt, Homebrew detection). Real-CLI run not verified in this environment.
Windows Implemented (copilot.cmd/.exe, npm-shim → node resolution, taskkill /T). Real-CLI run not verified in this environment.

Captured real-CLI output (de-identified) lives in packages/agent-connector/test/fixtures/copilot-cli-real-samples.md.


Common errors

Symptom Likely cause Action
"GitHub Copilot CLI not found" copilot not installed / not on PATH Install via npm/Homebrew/WinGet.
"…is too old — upgrade…" Below min_version Upgrade the CLI.
"Not signed in to GitHub Copilot…" No credentials (real: No authentication information found) Run copilot /login, gh auth login, or set COPILOT_GITHUB_TOKEN.
"token is invalid, expired, or revoked (401)…" Token rejected (real: could not be validated … 401 … Bad credentials) Use a fine-grained token with "Copilot Requests" (classic ghp_ not supported) or /login.
"Access denied (403)… SAML/SSO…" SSO not authorized / insufficient scope Authorize the org's SSO for your token.
"blocked by an organization/enterprise policy" Org disabled Copilot CLI Contact your GitHub org admin.
"No active GitHub Copilot subscription/seat" No Copilot entitlement Obtain a Copilot subscription/seat.
"GitHub host configuration error…" Bad GH_HOST/COPILOT_GH_HOST Fix the GHE data-residency hostname.
"Custom model provider (BYOK) is misconfigured…" Bad COPILOT_PROVIDER_* Fix provider base URL / key / type.
"model is unavailable" COPILOT_MODEL not allowed Clear COPILOT_MODEL or pick a supported model.
"requested interactive input…" CLI hit an ask_user prompt Re-run with a more specific task.
"Working directory does not exist" Bad project path Pick an existing directory.

Known limitations / follow-ups

  • Verified against real CLI 1.0.63: the full flag set the adapter uses (-p, --output-format json, --stream, --model, --add-dir, --no-ask-user, --plan, --allow-tool=shell|write, --resume=, --name, --secret-env-vars=, --no-remote), the tool IDs shell/write, the token env vars, and error/stderr/exit-code behaviour for unauth/invalid-token/stale-resume.
  • NOT verified: the success-path JSONL event schema (text/tool/file/done event names on stdout). No Copilot subscription was available in CI, and auth fails before any model output, so no successful-task JSONL could be captured. The parser's success-event mapping (EVENT_KIND_BY_TYPE) is therefore best-effort, intentionally narrow, and isolated to one table; unknown events degrade to a redacted diagnostic and never crash a task or fake a completion. Confirm against a real authenticated run before relying on rich tool/file event rendering.
  • Whether a non-interactive run emits a session id on stdout is unverified; resume-by-name and a one-session-per-task fallback cover this honestly.
  • No Python SDK adapter ships (the Python daemon was removed; the Node.js agent-connector is the runtime). The Python registry entry is catalog-only.
  • The launcher surfaces a token field rather than a dedicated "Login" button for Copilot, because there is no verified non-interactive status command to drive a hosted-login probe (auth errors only surface at run time, on stderr).