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
| Track | Meaning |
|---|
| A | Stock-Node - lift unchanged extHost*.ts into Cocoon |
| B | Rust-native - Mountain owns backend, gRPC from Cocoon |
| C | Cocoon-bespoke - hand-rolled TS in Land (last resort) |
| S | Sky-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 group | Coverage |
|---|
| Overall weighted | ~88% |
| TextEditor | ~95% |
| Workspace | ~96% |
| Window + SCM | ~95% |
| LSP / Language | ~95% |
| Debug + Tasks | ~25% |
1. Top-level namespaces
vscode.commands
vscode.window - Editors
vscode.window - Surfaces (TreeView, StatusBar, Webview, Terminal)
vscode.workspace
vscode.languages
vscode.debug
vscode.tasks
vscode.scm
vscode.env
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
vscode.authentication
vscode.notebooks
vscode.tests
vscode.chat / vscode.lm
vscode.l10n
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:
- Command registry -
extHostCommands.ts already does arg validation, contributed-command routing, cancellation. Sky calls the real ICommandService; Cocoon mirrors through stock. - Language features -
extHostLanguageFeatures.ts manages provider registries, merges results from multiple providers, caches. Rust rewrite would be months; the gRPC path just proxies which is cheap. - Editor / document / selection -
extHostDocuments.ts, extHostTextEditor.ts - source-of-truth for dirty state, encoding, EOL, versions. Must live in the extension host where edits originate. - Configuration -
extHostConfiguration.ts with scope resolution, override patterns, deprecation chains. Reuse stock. - Messages / dialogs / quick-input -
extHostMessageService.ts, extHostQuickOpen.ts. The UI is Skyβs, but the request/response serialisation is stock. - Progress -
extHostProgress.ts with cancellation, chained progress reporters. Stock. - Secrets / storage / memento -
extHostSecrets.ts, extHostStorage.ts- state shapes are VS Code-specific; stock lift.
- Authentication - complex session lifecycle, provider precedence. Stock.
- Debug / Tasks - protocol-heavy (DAP, task schema). Stock core + Mountain-owned process spawn for the transport.
- Webviews -
extHostWebview.ts plus iframe-in-workbench UI. Stock end-to-end; Sky hosts the iframe. - Notebooks - large surface, tightly coupled to workbench layout manager. Stock.
- Tree views -
extHostTreeViews.ts handles visibility, selection, reveal, description updates. Stock + Sky render.
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):
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.
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.- 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. 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.- 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):
- Lift
rpcProtocol.ts into Cocoon β export from Cocoon/Source/Services/Handler/VscodeAPI/StockLift.ts. - Lift
extHost.protocol.ts unchanged; expose ExtHostContext and MainContext as importable constants. - 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. - Instantiate stock mainThread classes in Sky on
cel:workbench-ready. - 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. - 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:
- Add the gRPC method to
Mountain/Proto/Vine.proto (the Vine submodule). - Implement the Rust handler under
Mountain/Source/IPC/WindServiceHandlers/<Domain>/<Method>.rs - one file per method (per PascalCase naming convention). - In Cocoonβs
<Namespace>Route.ts, add a Layer<N> tier that picks Mountain for that operation. - In Cocoonβs
<Namespace>.ts shim, call MountainClient.sendRequest(method, args) behind the tier guard. - 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):
- 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. - Debug adapter spawn - Mountain spawns the adapter child process over DAP; Cocoon proxies DAP messages. Unblocks every debug extension.
- Task execution - Mountain spawns the shell command, streams stdout/stderr through the terminal panel, tracks exit code.
- 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. - 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