Skip to content
On this page

Configuration ​

agent config is the typed preference store, and this page is its reference: every key, its scope, its default, and what it changes. The commands that read these keys are on the usage page.

bash
agent config get                                   # every machine key and shared default, with its origin
agent config set daemon.auto-start true            # a machine key
agent config set daemon.auto-start=true            # the same, in one word
agent config unset daemon.idle-timeout             # back to its built-in default
agent config set proxy.small-model gpt-5           # the shared default every profile follows
agent profile set identity copilot-developer-cli   # a profile key, for the default profile
agent profile work set proxy.small-model gpt-5-codex   # work overrides the shared default
agent profile work get proxy.small-model           # what that profile's daemon uses, and where it came from

Scope and precedence ​

Every key has one scope:

ScopeMeaningWhere it is storedCommand
profileThe value follows the credential. default is a profile like any other.The profile's section only, never the global mapagent profile [<name>] set|get|unset
profile-defaultThe shared default every profile follows; a named profile may override it. The default profile never carries an override of its own.The global map, or a named profile's section when overriddenagent config for the shared default; agent profile <name> set for an override
globalHow this machine runs; a profile never carries it.The global map onlyagent config set|get|unset

Every read resolves one way: explicit flag or env (per invocation) > the profile's own value > the global value > the built-in default, each layer only where the key's scope admits it (a global key never resolves from a profile's section).

Both faces take set <key> <value> or set <key>=<value>, split at the first =, so a URL value keeps its ?a=b.

The two faces write the same store. With no name, agent profile set|unset|get <proxy.*|probe.*> is an alias of agent config set|unset|get: the same store bytes, the same output. A machine key under agent profile set, or a profile key under agent config set, is refused with the other face's verb.

A keyless get lists one view. agent config get prints SHARED DEFAULTS (the profile-default groups as every profile inherits them) and GLOBAL (the global keys); agent config --help prints the same. agent profile [<name>] get prints PROFILE <name>: its profile keys, then the profile-default groups with the value this profile resolves to.

A starred row is stored. Under PROFILE a profile-default row names where its value came from: (shared default), (overrides the shared default <v>), or (overrides the built-in default <v>) when no shared default is set; an unstarred row is the built-in default. get <key> prints the value alone on stdout and its origin on stderr.

The key names below are also the stored JSON keys in ~/.local/share/copilot-env/state.json, under global and profiles.<name>, beside the state keys the commands write into the same maps (a profile's credential slot, the Codex catalog throttle).

Which a key is, is a per-key fact: set and unset refuse a state key by name, naming the command that owns it. The file's third map, ownership, is the wiring commands' ledger of the files they wrote.

profile ​

KeyScopeDefaultEffect
hostprofileautoCopilot API host; auto probes
identityprofileauto (probe per credential)Client identity; auto probes
passthroughprofileautoSend a PAT as-is; auto detects
static-keyprofilenoneWhich configs bake the token

identity is surveyed by agent profile [<name>] identity and pinned by agent profile [<name>] set identity <id|auto> (client identity); passthrough is explained under PAT passthrough and static-key under static key.

Copilot host ​

auto resolves the host per credential. The client identity is settled first (identity, probed on https://api.githubcopilot.com as before), then one GET /models under that identity's headers decides:

  • the account's designated host (endpoints.api of api.github.com/copilot_internal/user, one of api.individual. / api.business. / api.enterprise.githubcopilot.com) when it answers 403, 404, 5xx, or fails at the network level; a PAT's identity is then probed again on that host;
  • https://api.githubcopilot.com again when that lookup fails too;
  • https://api.githubcopilot.com on any other answer: 2xx serves, 400 is an identity rejection and 401 a bad token (identical on every host), a transient 408 or 429 says nothing about the host.

A literal https:// origin skips the probe (a GitHub Enterprise Server serves Copilot at https://copilot-api.<ghe-domain>). Either way one host serves everything after the identity probe:

  • the Direct base_url / ANTHROPIC_BASE_URL and the Claude Desktop gateway;
  • the proxy daemon's upstream (a pinned daemon ignores an inherited COPILOT_API_ENTERPRISE_URL);
  • every catalog, discovery, smoke, and web-search request.

The architecture page owns how the probed identity and host are stored and rendered. The table below says when each change applies.

EventWhat happens
host or identity set or clearedapplies at the next re-render (agent profile [<name>] add / sync, agent sync, the cl --profile hook, the Claude Desktop reconcile while the stored pair is complete) and the next proxy start. With a half unstored, the reconcile leaves the entry as it is and names the repair command: agent profile sync --claude for the default, agent sync for a named profile
a new credentialtakes the stored pair with it. A named profile's next re-render probes once and stores the new pair. For the default, see the next row
a default with no record yet, or a Direct default whose stored pair is incompletethe next agent profile sync or launcher write lands both agents and says so
agent settings --import of a bundle naming both agents, or of one Direct agent on a Direct default whose stored pair is incomplete or whose credential the import replaceslands both agents, and the plan names both files
a Direct landing with no resolvable credentialrefused before any write (agent profile auth first): a selection made without one would store the fallback identity and host
a write that fails on one agentthe previous record stays, and the output names the agent that did not move

daemon ​

KeyScopeDefaultEffect
daemon.auto-startglobalfalseAuto-start and idle-stop proxy
daemon.idle-timeoutglobal3600Idle stop in seconds; 0 never
daemon.min-portglobal1024Lowest proxy port to try
daemon.max-portglobal65535Highest proxy port to try
daemon.portglobal4141Proxy port; next free if busy
daemon.logsglobalfalseRequest log in <home>/logs
daemon.versiongloballatest (floated)Pin the proxy version or tag
daemon.release-cooldownglobal604800 (7 days)Min proxy release age, seconds
daemon.strict-portglobalfalseBusy port fails (default only)

daemon.auto-start and daemon.idle-timeout are the managed lifecycle; daemon.version and daemon.release-cooldown are the proxy float.

proxy ​

KeyScopeDefaultEffect
proxy.alpha-search.codex-priorityprofile-defaulttruePrefer Codex for /alpha/search
proxy.alpha-search.modelprofile-defaultgpt-5-mini/alpha/search fallback model
proxy.claude-auto-modelprofile-defaultunsetClaude security-monitor model
proxy.claude-token-multiplierprofile-default1.15Claude token count multiplier
proxy.message-websearch-modelprofile-defaultgpt-5-miniWeb-search model, Messages+MCP
proxy.messages-apiprofile-defaulttruePrefer the native Messages API
proxy.responses.context-managementprofile-defaultfalseResponses context management
proxy.responses.websearchprofile-defaulttrueResponses API web search
proxy.responses.websocketprofile-defaulttrueResponses API over WebSocket
proxy.small-modelprofile-defaultgpt-5-miniThe proxy's small/fast model

The proxy.* keys are projected into the proxy's own config.json at agent start, resolved for the daemon's profile, so changing one needs that daemon restarted. That file sits in the daemon's profile home, ~/.local/share/copilot-env/profiles/<name>/config.json, with default as the default profile's name.

  • One exception: the MCP web_search tool reads proxy.message-websearch-model fresh on every call (web search).
  • The three model keys at their default follow the daemon's catalog: when it does not list gpt-5-mini, agent start lands the cheapest model it does list (Copilot's lightweight tier first, the first listed on a tie; a Responses model for the two search keys) and says so. A stored value lands as stored, listed or not.

codex ​

KeyScopeDefaultEffect
codex.homeglobalautoCodex home root; auto detects
codex.hostglobalfalseCodex home per host (POSIX)
codex.model-catalogglobalfalsePatch the Codex model catalog

codex.home at auto is ~/.codex, or the shell's own CODEX_HOME while codex.host is off (never copilot-env's farm export); codex.host builds its farm under whichever codex.home resolves to.

Codex model catalog ​

codex.model-catalog applies at the next agent profile add / sync wiring or the next default-profile launch (cl / cx on a proxy default, or a direct cx); cx --profile <name> never refreshes it. Credential printing (agent profile auth --get, agent profile proxy-token) never refreshes the catalog or rewrites an agent file. Turning it off also removes the generated codex-model-catalog.json and the managed model_catalog_json reference from the Codex config.

What the generated catalog holds:

  • every model the installed codex bundles, with every field it ships, plus GitHub Copilot's real context window and prompt cap where Copilot serves the model;
  • the OpenAI-family models Copilot serves on /responses that this Codex does not bundle, for example gpt-5.3-codex, gpt-5.6-sol-fast, or gpt-6-astra on an older Codex. They are added as clones of their closest bundled relative, with Copilot's name, limits, and reasoning levels, so they appear in Codex's model picker.

Codex parses that file strictly and treats it as a replacement for its bundled catalog. A Codex build that requires a field the file lacks fails at startup with failed to parse model_catalog_json path ....

copilot-env guards the installed codex: before writing or referencing a catalog it asks that binary to parse it, and a catalog it rejects is left out of the config.

Other Codex consumers sharing ~/.codex, such as an IDE extension's own codex-core or a desktop app, cannot be probed. If one reports that error, run agent profile sync --codex to regenerate from the installed CLI, or agent config set codex.model-catalog false to remove the catalog.

Per-host CODEX_HOME ​

codex.host (Linux/macOS) is the per-host CODEX_HOME symlink farm switch. Setting it is refused on Windows.

bash
agent config set codex.host true    # false removes the farm again
  • What builds the farm, what it holds, and what removes it are in the write list.
  • agent profile env exports CODEX_HOME whenever codex.host is on (the farm path, built or not) or codex.home is set (the path itself); the next wiring pass creates what is missing.
  • agent profile check --codex / agent health report any drift between the key and the disk.

claude ​

KeyScopeDefaultEffect
claude.desktopglobaltrueAlso wire Claude Desktop
claude.desktop-effortglobalhighClaude Desktop default effort
claude.wire-mcpglobaltrueDirect Claude Code web search

claude.wire-mcp is the opt-out for web search.

Claude Desktop ​

claude.desktop applies at the next agent profile [<name>] add / sync or agent sync wiring. Setting the key writes no Desktop file itself. After a wiring pass, quit and reopen Claude Desktop: it reads everything below at launch only, and lands on the GitHub Copilot gateway with no sign-in chooser.

One exception: a configuration you applied in the app yourself stays applied, since a wire never displaces it. agent profile check --claude names it, and the switch is Developer > Configure Third-Party Inference....

SettingWhy
the gateway entry, one per wired default or profileprovider gateway, credential from the agent launcher run as the helper script with its arguments (agent profile [<name>] auth --get or proxy-token --yes) or the static key, the model list (first row = default model, newest of the most capable family), the copilot-env MCP server
"defaultModelEffort": "high"the default model starts at high effort in Chat, Cowork, and Code; agent config set claude.desktop-effort <level> (low, medium, high, xhigh, max) changes it at the next wiring pass
"builtinBrowserEnabled": true and the other switches the app ships offas many capabilities as possible: the built-in browser in Cowork and Code, desktop extensions, file analysis, Auto mode in Cowork, cost display, the 1M window, import/export; all telemetry off
"deploymentMode": "3p"the app boots third-party instead of asking "Continue with Gateway" or "sign in with Claude.ai"; other keys in the file are kept
{"allowDevTools": true}the Developer menu, where saved entries are switched (Developer > Configure Third-Party Inference...)

A wiring pass writes only the keys whose app default differs from what copilot-env wants. A switch the app already ships on (Cowork, Code, skill creation, plugins, scheduled tasks, keep-awake, Developer Mode) is not written, so a change you make to it in the app stands.

The files these land in, what writes and removes them, and where they sit on each platform are in the wiring write list.

  • On: a wiring pass ends with Claude Desktop is ready to use. once the default entry is wired, applied, and the app boots third-party; which passes write what is in the write list.
  • Off: the default entry stays in place as yours, named once and never rewritten; only agent uninstall removes it. Profile entries go; what the same writes remove is in the write list.
  • Drift: agent profile check --claude and agent health report an entry missing or stale with the key on, profile entries left behind after turning it off, which entry the app applies, and whether it will show the sign-in chooser or lacks the Developer menu.

probe ​

KeyScopeDefaultEffect
probe.claude-modelprofile-defaultunset tries the claude CLI's haiku alias, then the newest claude model in the catalogDirect probe's claude model
probe.codex-modelprofile-defaultunset prefers a reduced GPT tier (mini, nano) from the catalog, else its first codex-servable modelDirect probe's codex model

The Direct probe behind auto (agent profile add with neither --direct nor --proxy; a re-render of a recorded mode never probes) runs each CLI's read-only smoke prompt against a throwaway Direct config. A set value is the model that prompt runs, sent as-is: no alias, no catalog check.

bash
agent config set probe.claude-model claude-sonnet-5

Unset, the claude smoke runs --model haiku (the CLI resolves its own alias, so it sends no reasoning-effort field a Copilot model may lack) and, should Copilot reject that model, the newest claude model in the catalog once; any other failure stops with its reason.

shell ​

KeyScopeDefaultEffect
shell.launchersglobalfalseShell launchers cl / co / cx

The functions are described under launchers. agent shell --clis sets the key to true.

Installing the CLIs ​

agent shell --clis runs each vendor's own installer, proves the result with <cli> --version, and turns shell.launchers on. No Node.js or npm is involved: an older npm install -g copy stays until you run npm uninstall -g @anthropic-ai/claude-code @github/copilot @openai/codex yourself.

CLILinux / macOSWindows--cooldown N
Claude Codecurl -fsSL https://claude.ai/install.sh | bashirm https://claude.ai/install.ps1 | iexany positive N: the stable channel, about a week behind latest; 0: latest
GitHub Copilot CLIcurl -fsSL https://gh.io/copilot-install | bashwinget install --id GitHub.Copilot --scope user --location "$env:LOCALAPPDATA\Microsoft\WinGet\Packages\GitHub.Copilot_Microsoft.Winget.Source_8wekyb3d8bbwe"the newest github/copilot-cli release at least N days old (VERSION= / --version)
Codex CLIcurl -fsSL https://chatgpt.com/codex/install.sh | CODEX_NON_INTERACTIVE=1 shirm https://chatgpt.com/codex/install.ps1 | iexthe newest openai/codex release at least N days old (--release)

Every run prints the installer line it runs and names every file that installer writes outside copilot-env's homes, the shell profile it may add a PATH line to included. Without --cooldown, each vendor installs its latest; with one, a vendor whose newest 500 releases hold none that old is skipped rather than pinned to a fresher one.

--no-sudo skips winget, the Copilot CLI's only installer on Windows; the other installers are user-local everywhere. --no-prereqs only reports which CLIs are installed, with their versions.

update ​

KeyScopeDefaultEffect
update.autoglobalfalseDaily self-update at start
update.cooldownglobalnone by hand, 7 for update.autoMin release age in days
update.verify-provenanceglobaltrueSigstore-verify updates

What agent update verifies is under updating; agent update --auto-status shows the last check update.auto made.

cost ​

KeyScopeDefaultEffect
cost.pricing-urlglobalhttps://openrouter.ai/api/v1/modelsOpenRouter models API URL
cost.github-pricing-urlglobalhttps://raw.githubusercontent.com/github/docs/main/data/tables/copilot/models-and-pricing.ymlGitHub's Copilot rate card URL
cost.credits-targetglobalnoneMonthly credits to stay under

What agent cost reads and stores is under cost reporting.

Environment overrides ​

copilot-env loads local defaults from root .env when running its TypeScript entry points. Already-set shell variables win over that file, and env vars win over stored agent config values.

  • COPILOT_API_IDLE_TIMEOUT=<seconds>: the managed-lifecycle idle window for this invocation. Beats the daemon.idle-timeout config key.
  • COPILOT_API_VERSION=<version|tag>: pin the proxy to a release, bypassing the cooldown and float bounds at install. agent start still refuses a proxy below the version floor, and the daemon.version config key is the persistent equivalent.
  • COPILOT_API_MIN_RELEASE_AGE=<seconds>: the cooldown window (0 = no cooldown). Beats the daemon.release-cooldown config key.
  • COPILOT_CREDITS_TARGET=<credits>: the monthly credits agent credits paces against. Beats the cost.credits-target config key; agent credits --target beats both for one run.

Without a pin, the proxy float reads npm publish times, picks the newest version at least the cooldown window old, and clamps it to the bounds in copilot-env.config. The window is the env var, else daemon.release-cooldown, else the 7-day default that tracks minimumReleaseAge under [install] in bunfig.toml.

Built from v5.0.3 at 9f0d36fSource: docs/configuration.md