Skip to content

Settings and configuration persistence

Configuration state in this bundle spans multiple stores rather than one file. User settings, MCP/LSP configs, permission records, plugin metadata, sandbox and URL policy, trusted folders, terminal setup prompts, feature flags, auth metadata, and runtime session options are loaded from persistent roots and then overlaid by CLI or session state.

Read Tool, path, and URL permissions for how stored permission rules are evaluated, MCP host, transports, and tools for MCP config semantics, and Plugins, extensions, and capabilities for plugin state users.

Store familyMain consumers
SettingsURLs, plugins, MCP enablement, sandbox, UI, model/runtime preferences.
MCP/LSP configMCP host and IDE/LSP integration startup.
PermissionsLocation approvals, allowed directories, and persistent policy state.
State/cache directoriesPlugins, sessions, terminal prompts, migration targets, and runtime artifacts.

Because app.js is bundled/minified, symbol names are unstable. Line references below are searchable anchors in the extracted bundle and will shift across releases.

Source anchors

Semantic aliasMinified anchorApprox. app.js lineRole
Config root resolutionVs(...), configDir, COPILOT_HOME, .copilot234Runtime config root comes from explicit settings, env var, or home directory.
Store factoryload, write, writeKey, path, directoryFiles236Reusable JSON/config store helper with caching and key writes.
Store kindsDEFAULT, SETTINGS, MCP, LSP, LOCATION_PERMISSIONS236Multiple logical config stores exist.
User settings schemaallowedUrls, deniedUrls, disabledMcpServers, enabledMcpServers, sandbox, trustedFolders236, 239Settings schema covers permissions, URLs, MCP, sandbox, plugins, UI, and more.
Scoped settings/settings --repo, /settings --local, .github/copilot/settings.json, settings.local.json2212, 3627Repository defaults and git-ignored local overrides are separate from user settings.
Settings validationnLt, commandHistoryMaxSize, rgi(...)2237, 4175Registered settings are validated and invalid startup values produce a targeted warning.
GitHub MCP selectionsgithubMcpToolsets, githubMcpTools, enableAllGithubMcpTools, Swn(...)2644, 3642Selected GitHub MCP toolsets/tools are normalized and persisted.
Plugin persistenceinstalledPlugins, enabledPlugins, writeKey528Plugin manager writes installed/enabled plugin state.
URL permissionsallowedUrls, deniedUrls, addAllowedUrl, addDeniedUrl555URL allow/deny entries are persisted in settings.
MCP persistencedisabledMcpServers, enabledMcpServers, mcp-config.json4945, 4949, 7717MCP server enablement and config are stored separately.
Sandbox persistencesandbox, resolvedRuntimeSettings(), /sandbox enable1254, 1333Sandbox enablement is read/written via runtime settings.
Trusted folderstrustedFolders, isFolderTrusted, addTrustedFolder6021Trusted folders are normalized and persisted.
Terminal setupaskedSetupTerminals4512“Already asked” prompts are persisted to avoid repeated setup prompts.
Config migrationconfig.json, settings.json, QIn(), HIn(...)4446, 5774Legacy config can be migrated/merged into settings.
Relocation filessession-state, session-store.db, installed-plugins, mcp-config, permissions-config4446State/config files are relocated into .copilot roots.
CLI options--config-dir, --additional-mcp-config, --allow-url, --allow-all-urls5687-5782CLI options override or augment persisted config.

Configuration roots

The root path helper resolves the Copilot config/state home in this order:

  1. explicit runtime configDir if present;
  2. COPILOT_HOME environment variable;
  3. default ~/.copilot directory.

The same helper is reused across settings, MCP config, LSP config, permissions config, state, plugin cache, session state, and migration paths. The bundle also supports tilde expansion and relative-path normalization for user-supplied paths.

Store families

The config store factory defines logical store kinds equivalent to:

Store kindPurpose
config / defaultMain user/runtime configuration.
settingsUser settings-style keys, often migrated from legacy config.
mcpMCP server configuration.
lspLanguage server configuration.
permissionsLocation-scoped permission persistence.

Each store has helpers for:

HelperRole
load(scope, settings)Read and parse a JSON/config file.
write(object, scope, settings)Merge/write an object.
writeKey(key, value, scope, settings)Set/delete one key in a store.
path(scope)Compute the on-disk path.
directoryFiles(...)Enumerate files in a config directory.

The store helper caches loaded values by configDir and scope when caching is enabled. It also supports both .json and extensionless legacy file names.

writeKey semantics

writeKey is used heavily because many commands update one setting without replacing the entire file.

Its behavior is roughly:

  1. Resolve the store path for a scope and runtime settings.
  2. If the target value is undefined and the file does not exist, delete the cache entry and return.
  3. Load existing JSON or start with {}.
  4. Apply normalization/validation transforms if configured.
  5. Set object[key] = value, or delete the key if value is undefined.
  6. Validate the resulting object.
  7. Update cache when validation succeeds; clear cache if validation fails.
  8. Write the file with restricted mode.

This allows commands like /sandbox enable, MCP enable/disable, URL permission additions, and plugin installs to mutate settings incrementally.

User settings schema

The user settings schema is broad. Evidence anchors show support for:

Setting areaExample keys
UI/displaytheme, colorMode, renderMarkdown, footer, statusLine, screenReader.
Model/runtimemodel, effortLevel, continueOnAutoMode, stayInAutopilot, stream, streamerMode.
Timeline/inputpinnedPrompts, commandHistoryMaxSize, timestamps, scrollbar, tabs.
URLsallowedUrls, deniedUrls.
PluginsinstalledPlugins, enabledPlugins, extraKnownMarketplaces.
MCPdisabledMcpServers, enabledMcpServers, githubMcpToolsets, githubMcpTools, enableAllGithubMcpTools.
Sandboxsandbox.enabled, filesystem policy, raw policy, raw config.
Skills/agentsskillDirectories, disabledSkills, dynamicRetrieval, subagents.maxConcurrency, subagents.maxDepth, custom-agent settings.
Scheduling/voicebeepOnSchedule, voice.enabled, voice.selectedModel, voice.selectedDevice.
HooksdisableAllHooks, hooks.
Trust/auth metadatatrustedFolders, lastLoggedInUser, loggedInUsers, copilotTokens.
UX suppressionaskedSetupTerminals, suppressInitFolders, first-launch flags.

The schema is passthrough() in several places, meaning future keys can survive parsing even when the current bundle does not explicitly understand them.

commandHistoryMaxSize defaults to 50; it bounds both Ctrl+R reverse search and up/down prompt history. pinnedPrompts controls whether submitted prompts remain pinned in the timeline. stayInAutopilot defaults to false, so a completed autopilot task normally returns the session to interactive mode.

User, repository, and local scopes

The /settings dashboard and /model now expose three persistence targets:

TargetStorageIntended use
Userregular user settings.jsonDefaults shared across repositories.
Repo.github/copilot/settings.jsonTrusted repository policy/defaults that can be shared in version control.
Repo (local)settings.local.jsonGit-ignored overrides for one local checkout.

--repo and --local select the latter two targets in command form. Repository settings can pin model, reasoning effort, and context tier, and can extend deny lists for URLs, MCP servers, and skills. The runtime treats repository settings as trusted-workspace input rather than as a replacement for managed or user policy.

Runtime settings versus persisted settings

The session object stores runtimeSettings and exposes resolvedRuntimeSettings(). Slash commands use that to write to the correct config root. Examples:

Command/pathPersisted key
/sandbox enable / /sandbox disablesandbox.enabled.
/init suppresssuppressInitFolders.
reset approvalslocation-scoped permissions and allow-all state.
auto-mode continuationcontinueOnAutoMode.
terminal setup promptaskedSetupTerminals.

This distinction matters when the CLI is launched with a non-default configDir or with session-specific runtime settings.

Permission persistence

Permissions are split across several persistence paths:

Permission classPersistence behavior
Tool approvalsSession-scoped and location-scoped approval stores.
Path permissionsAllowed directories and all-paths mode are runtime/session state plus settings.
URL permissionsallowedUrls and deniedUrls in settings.
MCP server enablementdisabledMcpServers and enabledMcpServers.
Trusted folderstrustedFolders list in user settings.
Allow-all modeRuntime/session flag, reset by /reset-allowed-tools/approval reset paths.

The URL manager persists allow/deny entries through Is.writeKey("allowedUrls", ...) and Is.writeKey("deniedUrls", ...). Deny rules take precedence in the CLI help text and permission logic.

URL settings

URL settings are protocol-aware. The CLI help states:

  • domains without protocol default to HTTPS;
  • approving https://example.com does not approve http://example.com;
  • --allow-url and --deny-url accept URL/domain patterns;
  • --allow-all-urls enables unrestricted URL access;
  • --allow-all / --yolo are equivalent to all tools, all paths, and all URLs.

Persisted settings hold allowedUrls and deniedUrls, while runtime flags can set unrestricted mode for a session.

MCP settings

MCP config is loaded from multiple sources, including:

  • user ~/.copilot/mcp-config.json;
  • workspace .mcp.json or .github/mcp.json;
  • installed plugins with MCP servers;
  • built-in/default GitHub MCP config;
  • additional runtime MCP config via --additional-mcp-config.

Server enable/disable state is stored separately with disabledMcpServers and enabledMcpServers. The /mcp disable path adds a server to disabledMcpServers and removes it from enabledMcpServers. The /mcp enable path does the inverse and may explicitly persist built-in enabled servers.

GitHub MCP selection is also persistent in 1.0.71. githubMcpToolsets and githubMcpTools hold additional requested names, while enableAllGithubMcpTools selects the complete surface. Swn(...) sorts and deduplicates these values before comparing effective configuration, so ordering alone does not trigger a reload.

Plugin settings

Plugin install persists two related settings:

KeyPurpose
installedPluginsFull installed plugin records: name, marketplace, version, install timestamp, enabled flag, cache path, and source.
enabledPluginsEnablement map used during config merging.

The plugin cache itself lives under state (installed-plugins) while plugin/user config lives in config/settings stores. This avoids mixing package cache with editable user config.

Sandbox settings

The sandbox config schema includes:

  • sandbox.enabled;
  • filesystem readwritePaths, readonlyPaths, deniedPaths;
  • clearPolicyOnExit;
  • raw policy and raw config objects;
  • addCurrentWorkingDirectory.

The /sandbox slash command reads and writes sandbox.enabled through resolvedRuntimeSettings(). The shell spawn path later reads sandbox config/policy to construct platform sandbox behavior.

Trusted folders

Trusted-folder persistence is implemented by a small helper that:

  1. loads trustedFolders from user settings;
  2. canonicalizes/realpaths candidate paths;
  3. checks whether the candidate is inside an existing trusted folder;
  4. adds the normalized path only if it is not already covered;
  5. writes trustedFolders back with writeKey.

This prevents duplicates and makes trust checks robust against path normalization differences.

Migration and relocation

The bundle includes migration logic for legacy config.json / config files and settings-style keys.

The migration path:

  • reads config.json or config;
  • accepts either JSON object format or simple KEY=VALUE lines;
  • canonicalizes legacy key names;
  • compares values with existing settings.json;
  • warns if both files contain conflicting values;
  • writes migrated settings;
  • preserves unknown/remaining keys where appropriate.

A later relocation helper treats these as state files:

  • session-state;
  • session-store.db;
  • command-history-state;
  • command-history-state.json;
  • installed-plugins.

And these as config files:

  • config.json;
  • config;
  • mcp-config;
  • lsp-config;
  • permissions-config;
  • copilot-instructions.md;
  • mcp-oauth-config;
  • hooks.

Precedence model

The exact merge order is distributed, but the effective precedence is:

  1. built-in defaults;
  2. persisted user settings/config;
  3. trusted repository settings, followed by git-ignored repo-local overrides where applicable;
  4. plugin-provided config contributions;
  5. environment variables such as COPILOT_HOME and feature flag overrides;
  6. CLI flags such as --config-dir, --allow-url, --allow-all-urls, --plugin-dir, and --additional-mcp-config;
  7. session runtime changes made by slash commands or UI actions.

Some sources merge maps (enabledPlugins, marketplaces), some append arrays (additional MCP config, plugin dirs), and some override booleans directly (sandbox.enabled, continueOnAutoMode).

Relationship to other docs

  • integration-config-entrypoints.md gives the broad integration view.
  • tool-path-url-permissions.md explains how persisted approvals are interpreted.
  • plugins-extensions-and-capabilities.md explains plugin install/cache state.
  • mcp-host-transport-and-tools.md explains MCP config merging.
  • sandboxing.md explains how persisted sandbox settings affect shell execution.

Created and maintained by Yingting Huang.