Terminal Profiles and Shell Integration
Purpose and Scope
Terminal profiles and shell integration are two related layers of the integrated terminal. A terminal profile describes how a shell is launched: the executable path or detected source, arguments, and other launch customizations. Shell integration describes what VS Code can learn after that shell starts, such as prompt boundaries, command start and end events, current working directory updates, and environment data. Together they let users choose the shell they want while letting the workbench provide richer terminal behavior than plain character input and output.
The profile side is configured by users through settings such as platform-specific terminal profiles and default profiles. The shell integration side is implemented in the repository as protocol parsing, terminal capabilities, main-thread to extension-host forwarding, and public API events. This page focuses on the source-backed shell integration path while using official terminal documentation terminology for the profile workflow. Readers who are configuring their own terminal should start with profile selection, then verify shell integration when they need command decorations, command navigation, reliable current directory detection, extension API access, or richer automation.
Sources: src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts, src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts, src/vs/workbench/api/common/extHostTerminalShellIntegration.ts
Relevant Source Files
src/vs/platform/terminal/common/xterm/shellIntegrationAddon.tsimplements the xterm-side shell integration protocol handling, including OSC sequence identifiers and terminal capabilities for command, current-working-directory, prompt, buffer mark, and shell environment detection.src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.tsbridges terminal capabilities from workbench terminal instances to extension-host RPC events such as current directory, shell environment, execution start, and execution end.src/vs/workbench/api/common/extHostTerminalShellIntegration.tsowns the extension-host representation of terminal shell integration, active integrations, and public events exposed through the VS Code API surface.extensions/terminal-suggest/src/fig/shell-parser/index.tsre-exports the terminal suggest shell parser and command model, showing where command-line parsing support enters the bundled terminal suggestions extension.extensions/vscode-api-tests/src/singlefolder-tests/terminal.shellIntegration.test.tsverifies shell integration API behavior by enablingterminal.integrated.shellIntegration.enabled, waiting forwindow.onDidChangeTerminalShellIntegration, executing commands, and observing end events.src/vscode-dts/vscode.proposed.terminalShellEnv.d.tsdeclares the proposed API shape for terminal shell environment data, including the environment dictionary and trust flag.
Core Concepts
A terminal profile is selected before the terminal process exists. In the user model, profiles are platform-specific shell configurations with a path or source, optional arguments, and launch customizations. Users can select a default profile from the terminal dropdown or command palette, and can define custom entries such as PowerShell with -NoProfile or zsh as a login shell. Those choices determine which shell starts, but they do not by themselves explain what happened inside the shell after launch.
Shell integration begins after the shell emits recognizable sequences. The xterm add-on describes this as special sequences injected into the shell prompt using OSC, or Operating System Command, control sequences. It defines identifiers for FinalTerm-style sequences, VS Code-specific sequences, iTerm-style sequences, and current-working-directory reporting. The implementation imports and coordinates terminal capability types such as command detection, current-working-directory detection, shell environment detection, prompt type detection, buffer marks, and partial command detection. That capability model is the repository’s bridge between raw terminal output and higher-level workbench behavior.
Sources: src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts
System-to-Code Mapping
| User-facing behavior | Source-backed implementation | Notes |
|---|---|---|
| Detect that shell integration is available | MainThreadTerminalShellIntegration watches terminal capabilities and enables integration when command detection appears | Capability discovery drives onDidChangeTerminalShellIntegration. |
| Track current working directory | Main thread listens to the CwdDetection capability and forwards $cwdChange | This underpins features that need to know where commands are running. |
| Expose command execution events | Main thread listens to command detection start and end events; extension host exposes start and end events | Extensions can observe shell executions through VS Code API events. |
| Expose shell environment data | Shell environment detection forwards keys, values, and trust to the extension host | Proposed API models trusted versus untrusted environment values. |
| Parse command-line text for suggestions | terminal suggest re-exports shell parser and command modules | This supports command-aware terminal suggestions rather than plain text matching. |
The main-thread class is the workbench-side router. It receives terminal capability changes from ITerminalService, checks existing terminal instances at construction time, and subscribes to later capability additions. When current directory data changes, it calls the extension-host proxy with the instance id and new data. When shell environment data changes, it extracts keys and values before forwarding them with a trust value. This design keeps terminal process observation in the workbench process while giving extensions a stable API-shaped view.
Sources: src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts, src/vs/workbench/api/common/extHostTerminalShellIntegration.ts
Execution Flow
A typical session starts when the user opens a terminal from a selected profile. If the launched shell supports automatic shell integration, or if the user installed the integration manually, the shell prompt emits the integration sequences recognized by the terminal add-on. The add-on turns those sequences into capabilities such as command detection and current-working-directory detection. Once command detection is present for an instance, the main-thread API customer enables shell integration for that terminal and notifies the extension host.
On the extension-host side, ExtHostTerminalShellIntegration maintains a map of active integrations by terminal instance id. It exposes events named onDidChangeTerminalShellIntegration, onDidStartTerminalShellExecution, and onDidEndTerminalShellExecution. The same class keeps the RPC proxy to the main-thread shell integration customer and disposes active integration objects during cleanup. For extension authors, the important point is that shell integration is not assumed to exist for every terminal; extensions must wait for the change event or check the terminal’s shell integration state before using execution-specific APIs.
The API test demonstrates that sequencing. The suite enables terminal.integrated.shellIntegration.enabled, creates a terminal, waits for window.onDidChangeTerminalShellIntegration, and then uses shellIntegration.executeCommand to run commands. It also listens for window.onDidEndTerminalShellExecution to associate completion with the same shell integration. The test skips environments where the feature is not reliable for that suite, including web and some platforms, which is a useful reminder that shell integration depends on shell, platform, and launch conditions rather than only on VS Code settings.
Sources: extensions/vscode-api-tests/src/singlefolder-tests/terminal.shellIntegration.test.ts
API Components
The public API surface centers on terminal shell integration events and execution objects. window.onDidChangeTerminalShellIntegration signals when a terminal gains or changes integration data. window.onDidStartTerminalShellExecution and window.onDidEndTerminalShellExecution describe command execution boundaries. A TerminalShellIntegration can execute a command programmatically, and the resulting execution can be read as output through the API pattern shown in the extension-host source comments and exercised by tests. Command-line confidence is represented by TerminalShellExecutionCommandLineConfidence, allowing consumers to understand how reliable a detected command line is.
The proposed terminal shell environment API adds TerminalShellIntegrationEnvironment, with a value dictionary of environment variables and an isTrusted boolean. The trust flag is significant: the declaration states that untrusted values should not be used in ways that could lead to arbitrary code execution without warning the user. The main-thread implementation mirrors that concern by forwarding environment keys, values, and trust state from the detected shell environment. This makes environment-aware extensions possible while keeping trust visible in the API shape.
Sources: src/vscode-dts/vscode.proposed.terminalShellEnv.d.ts, src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts
Profiles, Appearance, Sticky Scroll, and Split CWD
Profiles determine what launches; appearance and navigation settings determine how terminal information is presented. For example, a profile can start a shell with login arguments, while shell integration can later mark prompt and command boundaries. Those boundaries are what make command-aware decorations and navigation possible. Appearance-related terminal behavior should therefore be understood as a consumer of terminal state, not the source of that state. If command or current-directory information is unavailable, presentation features have less semantic information to work with.
Split current-working-directory behavior follows the same mental model. When users split terminals, they often expect the new terminal to start in a useful directory, such as the active terminal’s current directory. Shell integration improves VS Code’s ability to know that directory because the current directory is reported as a capability change rather than inferred from text alone. Terminal sticky scroll and related command navigation features likewise benefit from command and prompt boundaries because they can treat command regions as structure within the scrollback instead of opaque output.
For implementation work, keep the boundary clear: profile settings decide process launch, shell integration add-ons interpret shell-emitted protocol, terminal capabilities represent detected state, and the main-thread and extension-host classes publish API events. When adding a feature that depends on the active directory, command lifecycle, or shell environment, prefer the capability and API path over parsing visible terminal text. When adding a feature that depends on launch arguments or executable selection, start from terminal profile configuration rather than shell integration events.
Sources: src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts, src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts, src/vs/workbench/api/common/extHostTerminalShellIntegration.ts
Testing and Next Steps
Use the API test as the source-backed pattern for validating shell integration behavior. It updates terminal.integrated.shellIntegration.enabled, creates a terminal, waits for integration, executes a command, and waits for the execution end event. That flow is preferable to assuming immediate availability, because shell integration activation depends on the shell startup path and prompt initialization. If you are writing an extension, mirror that defensive sequence: listen for integration changes, verify the terminal you care about, execute only after integration is available, and dispose listeners when the terminal closes.
For reader tasks, start by configuring the terminal profile that launches the right shell with the right arguments. Then verify shell integration if you need command decorations, current-working-directory tracking, command-aware terminal suggestions, or extension API execution events. Contributors should inspect the xterm add-on for protocol changes, the main-thread customer for workbench event routing, the extension-host service for API behavior, and the API tests for expected sequencing. Related areas include Terminal Basics for terminal lifecycle, Tasks and Task Runners for command automation, and Extension Authoring Overview for consuming the public API.
Sources: extensions/terminal-suggest/src/fig/shell-parser/index.ts, extensions/vscode-api-tests/src/singlefolder-tests/terminal.shellIntegration.test.ts