Skip to main content

Development

VS Code API Coverage Matrix

Authoritative map of every top-level vscode.* API surface and its implementation split across Sky (workbench renderer), Cocoon (extension-host Node sidecar), and Mountain (Rust backend). Drives the dual-track strategy.

VS Code API Coverage Matrix

Authoritative map of every top-level vscode.* API surface and its implementation split across Sky (workbench renderer), Cocoon (extension-host Node sidecar), and Mountain (Rust backend). Drives the dual-track strategy:

  • Track A - Stock-Node: Cocoon loads stock VS Code extHost*.ts sources unchanged; the workbench’s mainThread*.ts runs inside Sky (already the case - Sky ships the patched vs/workbench bundle). The ExtHostContext/MainContext RPC glue is provided by Cocoon’s shim alongside stock extHost code. This yields maximum compatibility from day one for any API the stock implementation handles in-process.
  • Track B - Rust-native: Mountain owns the backend. Cocoon’s vscode shim sends gRPC to Mountain which does the work natively (filesystem, process, terminal, search, git). Faster and safer than bouncing through Node for I/O-heavy APIs.

The two tracks are not mutually exclusive. Most APIs live on Track A by default (stock compat guaranteed), and we promote individual operations to Track B when a measured benefit exists. The Cocoon <Namespace>Route.ts tier router documented in Cocoon/Source/Services/Handler/VscodeAPI/ROUTING.md decides per-call.

Legend

TrackMeaning
AStock-Node - lift unchanged extHost*.ts into Cocoon
BRust-native - Mountain owns backend, gRPC from Cocoon
CCocoon-bespoke - hand-rolled TS in Land (last resort)
SSky-direct - call via __CEL_SERVICES__.* workbench accessor

Status symbols:

  • βœ… Working end-to-end (activation + feature render path confirmed)
  • 🟑 Partial - RPC wired but UI render gap, or missing sub-method
  • πŸ”΄ Stubbed / dropped-on-floor - registration accepted, no effect
  • βšͺ Not yet attempted
  • 🟒 Pure-function lift (stateless, no RPC) already landed via Cocoon/.../VscodeAPI/StockLift.ts

Coverage summary (2026-06)

Namespace groupCoverage
Overall weighted~88%
TextEditor~95%
Workspace~96%
Window + SCM~95%
LSP / Language~95%
Debug + Tasks~25%

1. Top-level namespaces

vscode.commands

OperationPrimaryStatusStock fileMountainSkySky
registerCommandA+Sβœ…extHostCommands.tscommands channel__CEL_SERVICES__.CommandRegistry.registerCommand
registerTextEditorCommandAβœ…extHostCommands.ts--
executeCommandA+Sβœ…extHostCommands.tscommands:execute__CEL_SERVICES__.Commands.executeCommand
getCommandsAβœ…extHostCommands.ts--

vscode.window - Editors

OperationPrimaryStatusStock fileMountainSkySky
activeTextEditorAβœ…extHostTextEditor.ts-IEditorService.activeTextEditorControl
visibleTextEditorsAβœ…extHostTextEditors.ts--
showTextDocumentAβœ…extHostDocuments.ts β†’ sky://window/showTextDocumentsky://window/showTextDocument emitvscode.open command dispatch
onDidChangeActiveTextEditorAβœ…event from mainThread--

vscode.window - Surfaces (TreeView, StatusBar, Webview, Terminal)

OperationPrimaryStatusStock fileMountainSkySky
createStatusBarItemS (native)βœ…extHostStatusBar.tssky://statusbar/{update,dispose,set-entry}__CEL_SERVICES__.Statusbar.addEntry
setStatusBarMessageSβœ…extHostStatusBar.tssky://statusbar/set-messageCustomEvent fan-out
createTreeViewA+Sβœ…extHostTreeViews.tstree.register + tree:getChildren + sky://tree-view/{create,dispose,refresh}__CEL_SERVICES__.TreeViewByViewId(id).dataProvider attach from cel:tree-view:create
registerTreeDataProviderA+Sβœ…extHostTreeViews.ts$provideTreeChildren gRPC β†’ CocoondataProvider attached to native ITreeView
createWebviewPanelAπŸ”΄extHostWebviewPanels.ts-stub channel webview
registerWebviewViewProviderAπŸ”΄extHostWebviewView.ts--
registerCustomEditorProviderAπŸ”΄extHostCustomEditors.ts--
createTerminalBβœ…-terminal:create / PTY via portable-pty; $acceptTerminalOpened gRPCworkbench terminal panel
onDidOpen/CloseTerminalBβœ…-$acceptTerminalOpened / $acceptTerminalClosed gRPC β†’ window.didOpenTerminal / window.didCloseTerminal Emitter-
onDidStartTerminalShellExecutionBβœ…-localPty:shellExecutionStart (OSC 633 C) β†’ $acceptTerminalShellExecutionStart gRPCworkbench terminal
onDidEndTerminalShellExecutionBβœ…-localPty:shellExecutionEnd (OSC 633 D) β†’ $acceptTerminalShellExecutionEnd gRPC-
onDidExecuteTerminalCommandBβœ…-localPty:shellExecutionEnd also fans to $acceptExecutedTerminalCommand gRPC-
createOutputChannelSβœ…extHostOutput.tssky://output/{create,append,clear,dispose}local mirror + workbench output panel
showInformationMessage / showWarningMessage / showErrorMessageAβœ…extHostMessageService.tssky://ui/show-message-request + ResolveUIRequestDOM toast fallback
showQuickPick / createQuickPickA🟑extHostQuickOpen.tssky://ui/show-quickpick-request + ResolveUIRequestworkbench quick-input
showInputBoxA🟑extHostQuickOpen.ts--
showOpenDialog / showSaveDialogBβœ…extHostDialogs.tsnativeHost:showOpenDialog / showSaveDialog (Tauri)-
showWorkspaceFolderPickAβšͺextHostDialogs.ts--
withProgressA+S🟑extHostProgress.tssky://progress/{start,update,complete}DOM toast + workbench progress
registerFileDecorationProviderA🟑extHostDecorations.ts--
registerUriHandlerA🟑extHostUrls.tsregister_uri_handler notif-drop covered-
onDidChangeWindowStateAβœ…extHostWindow.ts--
showNotebookDocumentAπŸ”΄extHostNotebookDocuments.ts--

vscode.workspace

OperationPrimaryStatusStock fileMountainSkySky
workspaceFoldersAβœ…extHostWorkspace.tsseeded via InitializationData.FoldersWire-
onDidChangeWorkspaceFoldersAβœ…extHostWorkspace.tssky://workspace/foldersChanged-
getWorkspaceFolderA+Bβœ…extHostWorkspace.ts--
textDocumentsAβœ…extHostDocuments.tssky://lifecycle/synchronizeDocuments-
openTextDocumentA+Bβœ…extHostDocuments.tsfile:read gRPC-
onDidOpen/Close/SaveTextDocumentAβœ…extHostDocuments.ts--
onWillSaveTextDocumentA🟑extHostDocumentSaveParticipant.ts$participateInSave gRPC-
applyEditA+S🟑extHostBulkEdits.tssky://workspace/applyEdit + ResolveUIRequestworkbench.action.applyThemeFromFile (stub)
save / saveAsAβšͺextHostDocuments.ts--
fs.readFile / writeFile / stat / readDirectory / createDirectory / delete / rename / copyBβœ…extHostFileSystemConsumer.tsfile:* gRPC-
fs.isWritableFileSystemAβœ…---
registerFileSystemProviderA🟑extHostFileSystem.tsregister_file_system_provider notif-drop covered-
createFileSystemWatcherB🟑 FileWatcher=StubextHostFileSystemEventService.tsstub (needs notify crate)-
findFilesBβœ…extHostSearch.tssearch:findFiles (globset)new ISearchResultProvider
findTextInFilesBβœ…extHostSearch.tssearch:findInFilesnew provider
registerTextDocumentContentProviderA🟑extHostDocumentContentProviders.tsregister_text_document_content_provider notif-drop covered-
getConfiguration / onDidChangeConfigurationA+Bβœ…extHostConfiguration.tsConfiguration cacheIConfigurationService
registerTaskProviderA🟑extHostTask.tsregister_task_provider notif-drop covered-

vscode.languages

OperationPrimaryStatusStock fileMountainSkySky
registerCompletionItemProviderA🟑extHostLanguageFeatures.tsregister_completion_item_provider + GetCompletions gRPC-
registerHoverProviderA🟑sameregister_hover_provider + GetHoverAtPosition gRPC-
registerDefinitionProviderA🟑sameregister_definition_provider + GetDefinition gRPC-
registerReferenceProviderA🟑sameregister_reference_provider + GetReferences gRPC-
registerDocumentSymbolProviderA🟑sameGetDocumentSymbols gRPC-
registerCodeActionsProviderA🟑sameregister_code_actions_provider-
registerCodeLensProviderA🟑sameregister_code_lens_provider-
registerDocumentFormattingEditProviderA🟑sameregister_document_formatting_provider-
registerRenameProviderA🟑sameregister_rename_provider-
registerInlayHintsProviderA🟑sameregister_inlay_hints_provider-
registerFoldingRangeProviderA🟑sameregister_folding_range_provider-
registerSemanticTokensProviderA🟑sameregister_semantic_tokens_provider-
registerSignatureHelpProviderA🟑sameregister_signature_help_provider-
registerInlineCompletionItemProviderA+B🟑sameregister_inline_completion_item_provider + language:provideInlineCompletions IPC β†’ ProvideInlineCompletionItems gRPCILanguageFeaturesService.inlineCompletionsProvider.register(*)
setTextDocumentLanguageA+Sβœ…extHostLanguages.tssky://languages/setDocumentLanguageMonaco language setter
setLanguageConfigurationA+Sβœ…extHostLanguages.tssky://language/configure-
createDiagnosticCollectionA+Sβœ…extHostDiagnostics.tssky://diagnostics/changedworkbench diagnostics
match🟒 pureβœ…StockLift--

vscode.debug

OperationPrimaryStatusStock fileMountainSkySky
registerDebugConfigurationProviderA🟑extHostDebugService.tsregister_debug_configuration_provider-
registerDebugAdapterDescriptorFactoryA🟑sameregister_debug_adapter notif-drop covered-
registerDebugAdapterTrackerFactoryA🟑same--
startDebuggingA+B🟑sameDebug.Start β†’ Mountain DebugService::StartDebugging-
activeDebugSession / onDidStart/ChangeSessionA🟑samelive getter __activeDebugSession; debug.didStartSession / debug.didChangeActiveSession Emitter events-
addBreakpoints / removeBreakpointsA+S🟑samedebug.addBreakpoints gRPC to Mountain; sky://debug/addBreakpoints β†’ IDebugService.addBreakpoints() in Sky-
activeStackItemAβšͺsame--

vscode.tasks

OperationPrimaryStatusStock fileMountainSkySky
registerTaskProviderA🟑extHostTask.tsregister_task_provider notif-drop covered-
fetchTasksA🟑sameTask.Fetch β†’ Mountain round-trip-
executeTaskA+B🟑sameTask.Execute β†’ Mountain; returns real TaskExecution with .terminate(); fires task.didStart / task.didEnd via gRPC-
taskExecutions / onDidStartTask / onDidEndTaskA🟑samelive Executions Map; task.didStart / task.didEnd / task.didStartProcess / task.didEndProcess Emitter events-

vscode.scm

OperationPrimaryStatusStock fileMountainSkySky
createSourceControlA+S🟑extHostSCM.tsregister_scm_provider + sky://scm/register emitSkyBridge diagnostic subscriber; needs ISCMService route (deferred)
inputBox.value read/writeA🟑extHostSCM.tsround-trip via ResolveUIRequest-
$gitExec (built-in git ext)Bβœ…git/out/model.js β†’ localGit channellocalGit:exec via HandleExec.rs; git:clone/pull/checkout/revParse/fetch/revListCount/cancel/isAvailable in Git/ handlers-

vscode.env

OperationPrimaryStatusStock fileMountainSkySky
appName / appRoot / uriScheme / language / shell / machineId / sessionId / isNewAppInstallAβœ…extHost.api.impl.tsseeded in InitData-
isAppPortableAβšͺsame--
clipboard.readText / writeTextBβœ…extHostClipboard.tsnativeHost:readClipboard / writeClipboard via Tauri-
openExternalBβœ…extHostWindow.tsnative:openExternal via Tauri shell.open-
asExternalUriAβšͺsame--
remoteName / remoteAuthorityAβœ… (always undefined)extHostWorkspace.ts--

Extension secrets: context.secrets.get/store/delete are backed by encryption:encrypt / encryption:decrypt IPC (AES-256-GCM, machine-stable key derived as SHA-256 of the machine UUID). Handlers live in Element/Mountain/Source/IPC/WindServiceHandlers/Encryption/.

vscode.extensions

OperationPrimaryStatusStock fileMountainSkySky
getExtension(id)Aβœ…extHost.api.impl.tsextensions:get-
allAβœ…sameextensions:getInstalled-
onDidChangeAβœ…same$deltaExtensions gRPC-

vscode.authentication

OperationPrimaryStatusStock fileMountainSkySky
registerAuthenticationProviderA🟑extHostAuthentication.tsregister_authentication_provider-
getSessionA🟑same$getSession gRPC-
getAccountsA🟑same--

vscode.notebooks

OperationPrimaryStatusStock fileMountainSkySky
createNotebookControllerAπŸ”΄extHostNotebookKernels.ts--
registerNotebookCellStatusBarItemProviderAπŸ”΄---
registerNotebookSerializerA🟑extHostNotebook.tsregister_notebook_serializer notif-drop-

vscode.tests

OperationPrimaryStatusStock fileMountainSkySky
createTestControllerA🟑extHostTesting.tssky://tests/registered emit-
Run profile / run requestAπŸ”΄same--

vscode.chat / vscode.lm

OperationPrimaryStatusStock fileMountainSkySky
createChatParticipantAπŸ”΄extHostChatAgents2.ts--
registerLanguageModelChatProviderAβšͺextHostLanguageModels.ts--
selectChatModelsAπŸ”΄same--

vscode.l10n

OperationPrimaryStatusStock fileMountainSkySky
t(message, ...)🟒 pureβœ…StockLift-able vs/base/common/l10n.ts--
bundle / uriAβœ…extHostLocalizationService.tsNLS bundle loaded at scan time-

vscode.comments

OperationPrimaryStatusStock fileMountainSkySky
createCommentControllerA🟑extHostComments.tsin-process thread store in Comments/Namespace.ts; no UI rendering yet-

2. Domain-grouped preferred-primary matrix

Grouped to highlight where Rust wins vs where Node-stock wins.

Rust-native primary (Track B wins)

High I/O, process, or syscall-bound operations where Node adds latency and the stock code ultimately bridges to the same native syscall anyway:

  • File system - workspace.fs.*, scanner reads. Mountain owns File::* via tokio, gives us zero-copy, sandbox gating, and transparent scheme resolution. Stock extHostFileSystemConsumer.ts would just marshal JSON over IPC to do the same syscall.
  • Find files / text search - workspace.findFiles / findTextInFiles. Mountain’s globset + walk is measured faster than Node’s glob package; migrating to ripgrep crate is the next perf tier.
  • Terminal PTY - already Mountain-owned via portable-pty. Stock extHostTerminalService.ts is a shim that forwards to a native PTY regardless; Land cuts out the middle hop.
  • Git subprocess - the built-in git extension’s $gitExec call pattern. Mountain spawns git as a child process and returns raw stdout.
  • File watch - createFileSystemWatcher. Today a Stub; next tier is Mountain notify crate which avoids Node’s well-known fs.watch platform-quirk swamp.
  • Native dialogs / clipboard / openExternal - Tauri already covers these. No Node alternative in an Electron-less build anyway.
  • Process spawn for debug adapters / task exec - upcoming; Mountain child_process via tokio::process.

Node-stock primary (Track A wins)

State-heavy or coordination-heavy APIs where stock VS Code already handles nuance (revision history, undo merge, decoration overlay, language feature merge, cancellation token propagation) we’d have to re-implement. Lifting the stock file unchanged is cheaper than maintaining an original Rust backend:

Hybrid (per-operation split)


3. Track-A bring-up plan (full Stock-Node compat)

To get a stock extHost*.ts file running unchanged inside Cocoon, the following glue must exist (most already does):

  1. ExtHostContext / MainContext RPC channels - bidirectional JSON-RPC between Cocoon and Sky. Today Cocoon↔Mountain is gRPC (Vine.proto), Sky↔Mountain is Tauri IPC. A third lane - Cocoon↔Sky direct - would let stock extHost*.ts talk to mainThread*.ts without Mountain as a middle hop. Candidates:
    • Mountain as relay (works today): Cocoon emits gRPC notification β†’ Mountain re-emits as sky:// Tauri event β†’ Sky’s mainThread shim receives. Extra hop, but no new transport. Good for low-rate registrations; skip for hot paths.
    • SharedWorker message port (future): Sky creates a MessageChannel, handshake via Mountain, then Cocoon↔Sky talk directly over the port. Requires Tauri’s worker support to allow SharedWorker in WKWebView, which today is blocked by CSP; tracked as a deferred item.
  2. RPCProtocol instance in Cocoon - stock extHost.api.impl.ts calls rpc.getProxy(MainContext.MainThreadX) to get a proxy. Cocoon needs to supply a RPCProtocol that routes proxy method calls down the Cocoon↔Sky lane. Bespoke MountainClientService.ts in Cocoon is the current stand-in; lifting stock rpcProtocol.ts from src/vs/workbench/services/extensions/common/ is the next step.
  3. Service identifier registration - stock MainContext / ExtHostContext registries (src/vs/workbench/api/common/extHost.protocol.ts) define one proxy identifier per mainThread and extHost class. Cocoon can import this file verbatim once RPCProtocol is in place.
  4. IExtHostRpcService - the DI token stock extHost*.ts asks for. Cocoon’s mini-DI already exists (Services/Handler/*Service.ts) - add an extHostRpcService binding that returns our RPCProtocol.
  5. mainThread*.ts loading in Sky - Sky already ships the vs/workbench/api/browser/mainThreadX.ts bundle. What’s missing is the instantiation at workbench startup; stock VS Code’s ExtensionService calls createExtensionHostManager which registers every mainThread. Sky needs to kick off that registration against Cocoon as the extension host.

Roadmap (concrete, in dependency order):

  1. Lift rpcProtocol.ts into Cocoon β†’ export from Cocoon/Source/Services/Handler/VscodeAPI/StockLift.ts.
  2. Lift extHost.protocol.ts unchanged; expose ExtHostContext and MainContext as importable constants.
  3. Add Cocoon↔Sky Mountain-relay lane: pair of gRPC notifications cocoonToSky(payload) + skyToCocoon(payload) that Mountain just forwards. Both sides marshal the stock MessageType enum.
  4. Instantiate stock mainThread classes in Sky on cel:workbench-ready.
  5. Start with low-risk namespaces: mainThreadCommands.ts first (command registry is the simplest), then mainThreadStatusBar.ts, then mainThreadMessageService.ts. Sky renders via the native workbench services as before.
  6. Once the relay + stock-mainThread loop is green for commands, migrate the remaining namespaces namespace-by-namespace. Each migration is a net removal of Cocoon’s bespoke <Namespace>.ts shim in favour of import { ExtHostX } from '@codeeditorland/output/vs/workbench/api/common/extHostX.js'.

Current status (2026-06): The Mountain-relay lane (pattern 1) is implemented and in production. SharedWorker message port remains deferred pending Tauri WKWebView CSP support.

4. Track-B bring-up plan (Mountain-native acceleration)

For each domain where Rust is the preferred primary, the pattern is:

  1. Add the gRPC method to Mountain/Proto/Vine.proto (the Vine submodule).
  2. Implement the Rust handler under Mountain/Source/IPC/WindServiceHandlers/<Domain>/<Method>.rs - one file per method (per PascalCase naming convention).
  3. In Cocoon’s <Namespace>Route.ts, add a Layer<N> tier that picks Mountain for that operation.
  4. In Cocoon’s <Namespace>.ts shim, call MountainClient.sendRequest(method, args) behind the tier guard.
  5. Update Architecture-Tiers.md manifest at build time so the dual-track dev-log tag reports which ops moved to Mountain.

Priority list (ranked by expected impact):

  1. File watcher (notify crate) - today FileWatcher=Stub, so every extension that relies on watch events to rebuild / reload / re-analyze silently waits forever. Highest user-visible gap among the stubs.
  2. Debug adapter spawn - Mountain spawns the adapter child process over DAP; Cocoon proxies DAP messages. Unblocks every debug extension.
  3. Task execution - Mountain spawns the shell command, streams stdout/stderr through the terminal panel, tracks exit code.
  4. Git subprocess - landed. Every $gitExec round-trip now routes to Mountain’s localGit:exec handler (HandleExec.rs) or the curated handler for clone/pull/checkout/revParse/fetch. Implemented in Batch 4 of the HANDOFF sequence.
  5. Ripgrep-backed text search - swap globset walk for ripgrep crate’s grep_searcher. 10-30Γ— speed-up on large repos.

5. Verification

After each namespace migrates:

  • LAND_DEV_LOG=dual-track line confirms the route decision per op.
  • PostHog land:dual-track:{shim,stock,mountain} marks record traffic by tier.
  • Integration test: launch with LAND_DEV_LOG=short,provider-register, exercise the feature from the UI, grep for Activation failed (must be 0) and $<method> (no handler) (must be 0).

6. Gap register (highest-priority next items)


See Also