How Continue's Profiling and Workspace Configuration Works: A Complete Guide
Continue separates LLM-specific configuration (profiles) from the set of folders opened in the IDE (workspaces), persisting the active profile per workspace in global context and synchronizing the selection across the core engine and Redux UI state.
Continue, the open-source AI code assistant, implements a sophisticated dual-configuration architecture that allows developers to maintain distinct LLM settings across different projects. Understanding how Continue's profiling and workspace configuration interact is essential for managing multiple AI assistants and ensuring consistent behavior across IDE restarts. The system centers on the ConfigHandler class in core/config/ConfigHandler.ts, which orchestrates workspace identification, profile discovery, and UI synchronization.
Workspace Identification and the Composite Key
When the ConfigHandler initializes, it generates a unique identifier for the current workspace set by querying the IDE for open directories. The getWorkspaceId() method caches the result of ide.getWorkspaceDirs() and concatenates multiple paths with an ampersand to create a deterministic key:
// core/config/ConfigHandler.ts
private async getWorkspaceId() {
if (!this.workspaceDirs) {
this.workspaceDirs = await this.ide.getWorkspaceDirs();
}
return this.workspaceDirs.join("&"); // e.g., "/projectA&/projectB"
}
This composite string serves as the canonical key for persisting profile preferences. If a user has folderA and folderB open simultaneously, the system generates "folderA&folderB" as the workspace identifier, ensuring that reopening the same combination of folders restores the previously selected profile.
Persisting Profile Selections with GlobalContext
The GlobalContext class in core/util/GlobalContext.ts maintains a JSON map that survives IDE restarts. The relevant entry lastSelectedProfileForWorkspace stores a mapping between workspace IDs and their active profile IDs:
// core/util/GlobalContext.ts
{
"lastSelectedProfileForWorkspace": {
"<workspace-id>": "<profile-id>"
}
}
When ConfigHandler loads available profiles, it retrieves the current workspace ID and checks for an existing selection. If found, the system automatically activates that profile; otherwise, it defaults to the built-in local profile. Upon explicit profile changes, the handler updates the mapping immediately:
// core/config/ConfigHandler.ts
const workspaceId = await this.getWorkspaceId();
const selectedProfiles = this.globalContext.get("lastSelectedProfileForWorkspace") ?? {};
this.globalContext.update("lastSelectedProfileForWorkspace", {
...selectedProfiles,
[workspaceId]: selectedProfile.profileDescription.id,
});
Loading Profiles from Global and Workspace Sources
The loadProfiles() method in ConfigHandler aggregates profiles from multiple locations, each wrapped in a ProfileLifecycleManager that manages configuration loading and lifecycle events:
| Source | Location | Loader |
|---|---|---|
| Global | ~/.continue |
globalLocalProfileManager (built-in default) |
| Workspace | .continue/agents, .continue/assistants, .continue/configs |
LocalProfileLoader per configuration file |
Each discovered profile becomes a ProfileDescription object containing metadata such as title, id, and uri. The ProfileLifecycleManager lazily loads the full configuration only when the profile becomes active, optimizing startup performance for workspaces with many agent definitions.
Synchronizing State with the Redux profilesSlice
The GUI maintains parity with the core state through a dedicated Redux slice located at gui/src/redux/slices/profilesSlice.ts. This slice manages three critical properties:
profiles: Array ofProfileDescriptionobjects populated fromConfigHandler.profileDescriptionsselectedProfileId: String identifier of the active profile for the current workspacepreferencesByProfileId: Record storing UI preferences (e.g., bookmarked slash commands) per profile
Key actions include setSelectedProfile for changing the active selection and initializeProfilePreferences for setting up default UI state when new profiles are detected. The store configuration at gui/src/redux/store.ts filters updates to ensure components only re-render when selectedProfileId or preference data changes.
Switching Active Profiles at Runtime
Profile changes flow through the setSelectedProfileId method in ConfigHandler, which implements guards against redundant updates and ensures atomic persistence:
// core/config/ConfigHandler.ts
async setSelectedProfileId(profileId: string) {
if (this.currentProfile?.profileDescription.id === profileId) return;
const profile = this.profiles.find(p => p.profileDescription.id === profileId);
if (!profile) throw new Error(`Profile ${profileId} not found`);
// Persist to global context
const workspaceId = await this.getWorkspaceId();
const selected = this.globalContext.get("lastSelectedProfileForWorkspace") ?? {};
this.globalContext.update("lastSelectedProfileForWorkspace", {
...selected,
[workspaceId]: profileId,
});
this.currentProfile = profile;
await this.reloadConfig("Selected profile changed");
}
The reloadConfig call clears cached configurations from inactive profiles and loads the complete LLM settings (model name, temperature, API keys, routing rules) for the newly selected profile, notifying all listeners including the Redux store.
Accessing VS Code Workspace Settings
For IDE-specific configuration such as telemetry flags or UI visibility toggles, Continue reads from the standard VS Code configuration namespace. The helper function in extensions/vscode/src/util/workspaceConfig.ts provides typed access:
// extensions/vscode/src/util/workspaceConfig.ts
import { workspace } from "vscode";
export const CONTINUE_WORKSPACE_KEY = "continue";
export function getContinueWorkspaceConfig() {
return workspace.getConfiguration(CONTINUE_WORKSPACE_KEY);
}
Settings defined under continue.* in .vscode/settings.json become accessible through this interface, allowing per-workspace customization of features like default models or playground button visibility without affecting the core profile configuration.
Summary
- Workspace identification uses a concatenated string of directory paths from
ide.getWorkspaceDirs()to create unique keys for folder combinations. - Profile persistence stores the active selection per workspace in
GlobalContextunder thelastSelectedProfileForWorkspacekey. - Profile loading aggregates configurations from
~/.continueand local.continuedirectories, wrapping each in aProfileLifecycleManager. - UI synchronization occurs through the Redux
profilesSlice, which mirrors core state and manages per-profile UI preferences. - Runtime switching triggers
ConfigHandler.setSelectedProfileId(), which updates global persistence and reloads LLM configuration atomically. - IDE settings are accessed separately via
getContinueWorkspaceConfig()for VS Code-specific options.
Frequently Asked Questions
How does Continue remember which profile I used for a specific workspace?
Continue generates a unique workspace ID by joining the paths of all open folders with ampersands (e.g., /projectA&/projectB). This ID serves as a key in the GlobalContext map lastSelectedProfileForWorkspace, which is persisted to disk. When the same folder combination opens again, ConfigHandler retrieves the stored profile ID and automatically activates it.
Where are Continue profiles stored on disk?
Profiles reside in two locations: the global ~/.continue directory contains the default local profile, while workspace-specific profiles live in .continue/agents, .continue/assistants, or .continue/configs folders within the workspace root. The LocalProfileLoader class reads these locations during initialization.
What happens when I switch profiles in the Continue UI?
The UI dispatches the setSelectedProfile Redux action, which calls ConfigHandler.setSelectedProfileId(). This method validates the profile exists, updates the lastSelectedProfileForWorkspace entry in GlobalContext, sets currentProfile to the new instance, and executes reloadConfig() to clear cached configurations and load the new LLM settings.
How do I access Continue-specific settings from a VS Code extension?
Import getContinueWorkspaceConfig from extensions/vscode/src/util/workspaceConfig.ts and call it to receive a VS Code WorkspaceConfiguration object. Access settings using config.get("settingName") for any key defined under the continue namespace in VS Code settings.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →