Skip to content

0022. GitHub Copilot Chat extension and Copilot CLI

Status

Accepted

Context

The image already ships Claude Code (the claude CLI in Layer G, and the anthropic.claude-code extension) and the Cline extension. Teams that hold GitHub Copilot subscriptions asked for the same two surfaces: the VS Code Copilot Chat extension and the terminal copilot CLI. Neither works without network access to GitHub's Copilot service, and the egress model is deny-by-default (ADR 0009): the firewall allows exact hostnames only (resolved to IPs at apply time) and privoxy filters by domain, so both allowlists need entries.

Decision

  • CLI: install @github/copilot from npm in a new Layer G2, right after Claude Code, pinned by an ARG with a # renovate: datasource=npm comment and added to the Renovate "pin to exact version" rule next to Claude Code. The package is a small loader plus an optional-dependency platform binary. On Alpine the loader resolves @github/copilot-linuxmusl-x64 or -arm64 (both exist), so no glibc shim is needed (ADR 0001). ~/.copilot is created and owned by the user in the image.
  • Persistence: ~/.copilot (login, config, session state) becomes the named volume ${project}-copilot, mirroring ~/.claude, and fix-permissions.sh fixes its ownership. Without it a rebuild logs the user out.
  • Extension: add github.copilot-chat to the extensions list in .devcontainer/devcontainer.json and the examples/ template. It is the standalone Chat extension; the separate github.copilot completions extension was not added.
  • Egress: add a "GitHub Copilot" block to .devcontainer/egress-allowlist.txt and .devcontainer/proxy.yaml, built from GitHub's Copilot allowlist reference: api., proxy. and telemetry. hosts for the individual, business and enterprise plans, the generic api.githubcopilot.com, copilot-proxy.githubusercontent.com, origin-tracker.githubusercontent.com, copilot-telemetry.githubusercontent.com, collector.github.com and default.exp-tas.com. github.com and api.github.com were already listed. The inference hosts carry # tag:llm so the dashboard highlights them. In the examples/ templates the block is commented out, like the Anthropic block, so consuming projects opt in per plan.

Rejected:

  • Wildcards. *.githubcopilot.com would be shorter but the firewall does not support wildcards, and the privoxy entry is a plain domain either way.
  • Installing the CLI at runtime. It needs registry.npmjs.org plus a writable global prefix, and is lost on rebuild.
  • The github.copilot extension. Not requested; Chat covers the stated need.

Consequences

Accepted:

  • The image gets larger: npm reports the musl arm64 platform package at about 207 MB unpacked (the x64 one was not measured). Layer G2 sits before Layer H, so the first build invalidates the layers below it.
  • @github/copilot releases often, so the Renovate PR for it will be frequent.
  • The Chat extension is installed by VS Code at container creation, as for the other extensions; it is not part of the image.
  • Per-plan hostnames mean some entries are unused for any one subscription. Two of them, proxy.*.githubcopilot.com and telemetry.*.githubcopilot.com, come from the allowlist reference's *.<plan>.githubcopilot.com wildcards rather than from the reference's host table.
  • Copilot sends prompts and code to GitHub. Whether that is acceptable is a project decision; the examples/ allowlists stay opt-in for that reason.

Not verified when this was written:

  • The copilot binary was not executed by the author (the sandbox denied running a downloaded binary). The BATS copilot --version test passed in the pull request's CI build on amd64 (GitHub Actions run 43042993231). The arm64 image is first built by the release workflow, and behavior without a login or network was not observed.
  • The hostnames were checked against GitHub's reference and DNS, but DNS resolves any name under these zones, so it does not prove a host is used. The dashboard's blocked-request list will show any missing host on first use.
  • The dashboard has Copilot CLI support (COPILOT_DIR), but entrypoint.sh does not set it, so Copilot token and cost figures are not shown yet.