# How Continue's Profiling and Workspace Configuration Works: A Complete Guide

> Learn how Continue's profiling and workspace configuration works. This guide explains how profiles and workspaces are managed to enhance your IDE experience.

- Repository: [Continue/continue](https://github.com/continuedev/continue)
- Tags: how-to-guide
- Published: 2026-06-24

---

**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`](https://github.com/continuedev/continue/blob/main/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:

```ts
// 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`](https://github.com/continuedev/continue/blob/main/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:

```ts
// 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:

```ts
// 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`](https://github.com/continuedev/continue/blob/main/gui/src/redux/slices/profilesSlice.ts). This slice manages three critical properties:

- **`profiles`**: Array of `ProfileDescription` objects populated from `ConfigHandler.profileDescriptions`
- **`selectedProfileId`**: String identifier of the active profile for the current workspace
- **`preferencesByProfileId`**: 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`](https://github.com/continuedev/continue/blob/main/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:

```ts
// 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`](https://github.com/continuedev/continue/blob/main/extensions/vscode/src/util/workspaceConfig.ts) provides typed access:

```ts
// 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`](https://github.com/continuedev/continue/blob/main/.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 `GlobalContext` under the `lastSelectedProfileForWorkspace` key.
- **Profile loading** aggregates configurations from `~/.continue` and local `.continue` directories, wrapping each in a `ProfileLifecycleManager`.
- **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`](https://github.com/continuedev/continue/blob/main/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.