GHES 3.22 Points Copilot CLI At A Private LLM, One Per Instance
The case for a private LLM was never about the model. It is about where the prompt goes. A coding agent reads source files, config with credentials in it, and whatever the developer pastes in from an incident channel, and all of that leaves the building unless something stops it. GitHub Enterprise Server 3.22 went generally available on 8 September with a mechanism that can stop it — and the mechanism is narrower, and more your problem, than the announcement suggests.
What shipped, and where the detail actually is
The changelog entry gives it three sentences: administrators can configure Copilot CLI to work with GHES for enterprises operating in disconnected or air-gapped environments without connectivity to GitHub Cloud; a model provider is set up once; end users across the enterprise connect with their GHES credentials. Technical preview, subject to change.
The 3.22 release notes on docs.github.com repeat that and link the admin page, which is where the shape of the thing appears. It is a proxy. An administrator with administrative SSH access sets keys under app.copilot-proxy with ghe-config and applies them:
ghe-config app.copilot-proxy.enabled true
ghe-config app.copilot-proxy.endpoint-url 'https://api.openai.com/v1'
ghe-config secrets.copilot-proxy.endpoint-key 'YOUR-API-KEY'
ghe-config app.copilot-proxy.provider-model-id 'gpt-5.5'
ghe-config app.copilot-proxy.provider-type openai
ghe-config-apply
That is GitHub's own example, and it is the first thing worth noticing: the documented example of the air-gapped feature points at api.openai.com.
A private LLM is the endpoint you choose, not the feature you switch on
provider-type accepts three values — openai, azure, anthropic — and the docs define the first one broadly: OpenAI, Ollama, vLLM, Foundry Local, and any other endpoint that speaks the OpenAI Chat Completions API. The same key that reaches a hosted vendor reaches a box in your own rack. Nothing in the variable table constrains endpoint-url to a private address.
GitHub states the consequence itself on the bring-your-own-key page: offline mode only guarantees full network isolation if the provider is also local or inside the same isolated environment, and if the base URL points at a remote endpoint, prompts and code context are still sent to that provider over the network. The client-side COPILOT_OFFLINE=true, required alongside COPILOT_PROVIDER_GHES_HOST and COPILOT_PROVIDER_GHES_TOKEN, stops the CLI talking to GitHub. It does not stop your instance talking to whatever you configured.
So the claim to take away, and the one that could be wrong: turning this feature on, by itself, changes nothing about where your tokens go. What would show that wrong is a GHES setting that refuses, or even warns on, a non-private upstream. There is no such key in the table. The only upstream-directed control is app.copilot-proxy.enable-upstream-probe, a startup reachability probe that defaults to enabled and can be turned off.
One model, for everyone on the instance
provider-model-id is a single string, not a list; provider-wire-model only overrides the identifier sent upstream when it differs. And the capability table on the same admin page marks Copilot model selection of GitHub-hosted models as unavailable on GHES.
Together those say something a vendor deck will not: the instance serves one model to the entire enterprise, and developers cannot switch away from it. Every argument your teams have had about which model suits which task collapses into one administrator decision, applied over SSH. That makes it a buy, build or fine-tune decision rather than a settings change, and it is the part a private LLM deployment has to settle before anyone installs a client.
The model requirements will disqualify the runtime you already run
The admin page defers to GitHub's bring-your-own-key documentation for model requirements, and those are specific: a model must support tool calling and streaming, and Copilot CLI returns an error if either is missing. GitHub recommends a context window of at least 128k tokens for best results.
Tool calling is the one to check, because in the runtimes the doc names it is not on by default. vLLM's documentation is explicit that automatic tool calling requires two flags — --enable-auto-tool-choice and a --tool-call-parser selected per model family, with hermes, mistral and llama3_json among the options — plus, for models whose chat template does not already handle tool-role messages, a --chat-template. They are opt-in, so a vLLM server started to serve ordinary chat completions does not do automatic tool calling until it is restarted with them. Point GHES at that server and the error comes back from Copilot CLI, on a developer's machine, rather than from the serving stack an operator is watching.
Five things the offline path does not carry
The capability table lists what GitHub Enterprise Cloud has and GHES does not: GitHub MCP server tools, web search and web fetch, model selection, telemetry and usage reporting, and auto-update. GitHub operations such as issues and pull requests still work, but through the gh CLI authenticated to the instance rather than through MCP.
Telemetry is the one to plan around rather than accept. No usage reporting means the rollout arrives with no built-in way to answer whether anyone is using it, and an internal AI tool with no number attached to it is the case why enterprise AI doesn't ship makes about evaluation: without a harness tied to a real KPI, it seems better is the strongest thing anyone can say at the next review.
The checklist for this quarter
- Pick the one model first. It is an instance-wide choice, so run the selection as a procurement decision, not an experiment.
- Stand that model up behind your runtime with tool calling explicitly enabled — on vLLM,
--enable-auto-tool-choiceplus the parser for that model family — and confirm a streaming tool call comes back before anything touches GHES. - Check the context window against the 128k recommendation while the model is still swappable.
- Treat
app.copilot-proxy.endpoint-urlas a change-controlled item. It is set over administrative SSH, and it is the setting that determines whether the deployment is private. - Budget for your own usage measurement, because telemetry and usage reporting are not available here.
- Do not attach a compliance commitment to this in the next three months. It is a technical preview, and GitHub says it is subject to change.
Related reading
- AI Engineering
PatchTST-FM-r2 Beats r1 on Average and Loses on 24 of 97 GIFT-Eval Configurations
By Petru Popa · Read - AI Engineering
AI Agent Governance Does Not Survive The Approval Prompt
By Petru Popa · Read - AI Engineering
Ai2 Audited 16 LLM Benchmarks. Nearly Half the Safety Questions Score Reasoning.
By Petru Popa · Read
Turn this into a plan for your team.
One week, fixed fee: a working session with your team, a prioritized use-case backlog, and an ROI model for the opportunities worth chasing.