Skip to main content

Guide

Inter-Component Protocol

Specifies the communication protocols used between Land components: gRPC service definitions (Vine protocol), Tauri IPC mechanism, Spine extension coordination protocol, and connection lifecycle management.

Inter-Component Protocol

This document specifies the communication protocols used between Land components. It covers the gRPC service definitions (Vine protocol), the Tauri IPC mechanism, the Spine extension coordination protocol, and the connection lifecycle management.


Table of Contents

  1. Protocol Overview
  2. Tauri IPC
  3. Vine gRPC Protocol
  4. Spine Extension Protocol
  5. Connection Lifecycle
  6. Health Monitoring
  7. Protocol Buffer Definitions
  8. Security
  9. Related Documentation

Protocol Overview 🔌

Land uses three communication protocols operating at different abstraction levels:

ProtocolTransportLayerComponentsPurpose
Tauri IPCIn-process IPCApplicationWind/Sky <-> MountainUI-backend communication
gRPC (Vine)TCP localhostServiceCocoon <-> Mountain, Air <-> MountainInter-service RPC
SpinegRPC + ActionEffectExtensionCocoon -> MountainExtension host coordination

Protocol Stack

graph BT
    subgraph Transport[Transport Layer]
        TCP[TCP localhost]
        IPC[IPC pipes]
    end

    subgraph TauriIPC[Tauri IPC]
        Commands[In-process command/event transport]
    end

    subgraph VinegRPC[Vine gRPC Protocol]
        Proto[Service contracts defined in .proto files]
    end

    subgraph SpineProto[Spine Protocol]
        ActionResp[Extension action/response pattern]
    end

    TCP --> Commands
    IPC --> Commands
    TCP --> Proto
    IPC --> Proto
    Commands --> ActionResp
    Proto --> ActionResp

    style Transport fill:#f0f0f0,stroke:#333
    style SpineProto fill:#e8f8e8,stroke:#363

Tauri IPC 🎮

TierIPC Runtime Routing

The TierIPC environment variable controls how Wind and Output route Tauri IPC calls at runtime. No rebuild is required to switch tiers.

ValueBehaviour
MountainAll calls route to Mountain (default)
NodeDeferredMountain first; on miss or undefined result, falls back to Cocoon via cocoon:request bridge
NodeAll calls bypass Mountain and route directly to Cocoon via cocoon:request

Individual subsystems have their own tier constants (e.g. TierTerminal, TierStorage, TierSearch) baked at compile time from .env.Land. A runtime shell export (e.g. export TierStorage=Node) overrides the baked value without a rebuild. The active tier for each subsystem is logged at boot by Mountain/Source/LandFixTier.rs.

Commands (Request-Response)

Wind invokes Mountain handlers through @tauri-apps/api invoke(). Each command maps to a registered Rust handler in Mountain.

Wind-side invocation:

import { invoke } from "@tauri-apps/api/core";

const content: Uint8Array = await invoke("read_file", {
	path: "/Users/user/Documents/example.ts",
});

Mountain-side handler:

use tauri;

#[tauri::command]
async fn read_file(
    path: String,
    state: State<'_, AppState>
) -> Result<Vec<u8>, String> {
    let fs = state.file_system();
    fs.read_file(std::path::Path::new(&path))
        .await
        .map_err(|e| e.to_string())
}

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![read_file])
        .run(tauri::generate_context!());
}

Command Catalog

All commands are dispatched through the single Tauri command MountainIPCInvoke with { method: string, params: any[] }. The method string corresponds to the channel wire name defined in Common/Source/IPC/Channel.rs.

Encryption

CommandParametersReturnsPurpose
encryption:encrypt[plaintext: string]stringAES-256-GCM encryption; key is SHA-256 of machine UUID, cached per-process
encryption:decrypt[ciphertext: string]stringSymmetric decryption; used by extension context secrets API

The encryption key is derived once per process in Encryption/Key.rs using SHA-256("Land-Encryption-v1" + machine_id). Returns an empty string on failure rather than throwing, so callers treat a corrupt blob as “no stored secret”.

File System

CommandParametersReturnsPurpose
file:watch[path: string, options?]voidRegister a file watcher via FileWatcherProvider
file:unwatch[path: string]voidDeregister a file watcher
file:open[path: string, opts?]numberOpen a file descriptor; fd is tracked in Mountain’s fd table
file:close[fd: number]voidClose a tracked file descriptor
file:stat[path: string]FileStatStat a path
file:readFile[path: string]Uint8ArrayRead file (VS Code native path)
file:readdir[path: string]DirEntry[]List directory entries
file:writeFile[path: string, content: Uint8Array]voidWrite file
file:delete[path: string, opts?]voidDelete file or directory; fires $acceptDidDeleteFiles
file:rename[from: string, to: string]voidRename/move file; fires $acceptDidRenameFiles
file:mkdir[path: string]voidCreate directory; fires $acceptDidCreateFiles
file:copy[from: string, to: string]voidCopy file
file:cloneFile[from: string, to: string]voidClone file (reflink where supported); fires $acceptDidCreateFiles
file:realpath[path: string]stringResolve symlinks
file:exists[path: string]booleanCheck existence

file:open / file:close are classified as high-frequency and short-circuit the Echo scheduler.

Terminal

CommandParametersReturnsPurpose
localPty:createProcess[shellLaunchConfig, cols, rows, ...]{ id, pid }Spawn a PTY process; returns its internal id and OS PID
localPty:resize[id, cols, rows]voidResize PTY via SIGWINCH
localPty:attachToProcess[id: number]{ id, pid }Reconnect workbench to an existing live PTY after window reload
localPty:detachFromProcess[id: number]voidDetach the workbench from a PTY without killing the process
localPty:reviveTerminalProcesses[states: TerminalState[]]voidRe-spawn terminals from serialised state after reload; populates id-remap table
localPty:shellExecutionStart[{ id, commandLine, cwd }]voidFired by Sky on OSC 633 ;C (command output begins); forwards $acceptTerminalShellExecutionStart to Cocoon
localPty:shellExecutionEnd[{ id, commandLine, cwd, exitCode }]voidFired by Sky on OSC 633 ;D (command finished); fans out $acceptTerminalShellExecutionEnd and $acceptExecutedTerminalCommand to Cocoon
localPty:freePortKillProcess[port: number]voidFind process owning a port (lsof) and SIGKILL it
localPty:getDefaultShell[]stringReturn the user’s default login shell path
localPty:getEnvironment[]objectReturn the login-shell environment variables
localPty:getProfiles[includeDetected?]Profile[]List available shell profiles
terminal:create[options]{ id }Create a terminal tab (calls TerminalProvider)
terminal:sendText[id, text]voidWrite text to terminal PTY
terminal:show[id]voidReveal terminal tab in UI
terminal:hide[id]voidHide terminal tab
terminal:dispose[id]voidDestroy terminal and PTY

NativeHost

CommandPurpose
nativeHost:quitRequest graceful application quit
nativeHost:exitExit with process code
nativeHost:relaunchRestart the application
nativeHost:reloadReload the webview
nativeHost:openDevToolsOpen Tauri/WebView developer tools
nativeHost:toggleDevToolsToggle developer tools visibility
nativeHost:killProcessKill a process by PID
nativeHost:installShellCommandInstall fiddee CLI symlink in /usr/local/bin
nativeHost:uninstallShellCommandRemove fiddee CLI symlink
nativeHost:findFreePortFind an available TCP port
nativeHost:isPortFreeCheck whether a specific port is free (real TCP bind check)
nativeHost:resolveProxyRead HTTPS_PROXY / HTTP_PROXY environment variables
nativeHost:getEnvironmentPathsReturn home, appRoot, userData, temp and related paths
nativeHost:isRunningUnderARM64TranslationDetect Rosetta 2 translation on macOS
nativeHost:moveItemToTrashMove a file to the OS trash
nativeHost:showMessageBoxShow a native OS alert/confirm dialog
nativeHost:showSaveDialogShow a native save-file dialog
nativeHost:showOpenDialogShow a native open-file/folder dialog
nativeHost:readClipboardTextRead text from clipboard
nativeHost:writeClipboardTextWrite text to clipboard
nativeHost:readClipboardFindTextRead macOS find-pasteboard text
nativeHost:writeClipboardFindTextWrite macOS find-pasteboard text
nativeHost:readClipboardBufferRead clipboard in a specific format (e.g. text/html)
nativeHost:writeClipboardBufferWrite clipboard in a specific format
nativeHost:hasClipboardTest whether clipboard contains data in a given format
nativeHost:readImageRead an image from clipboard as PNG bytes
nativeHost:triggerPasteProgrammatically trigger a paste action in the focused element
nativeHost:setMinimumSizeSet the window minimum size constraints
nativeHost:positionWindowReposition or resize the window
nativeHost:setRepresentedFilenameSet the macOS proxy-icon path in the window title bar
nativeHost:getWindowsReturn the list of open windows with product name and active document
nativeHost:getOSColorSchemeReturn the current OS light/dark/high-contrast scheme
nativeHost:getOSPropertiesReturn OS name, version, architecture
nativeHost:getOSStatisticsReturn memory and CPU usage snapshot

Language

CommandParametersReturnsPurpose
language:provideInlineCompletions[uri, position, context]InlineCompletion[]Request inline completion items via LanguageFeatureProviderRegistry; used by Sky’s Monaco InlineCompletionsProvider
language:getLanguages[]string[]Return all registered Monaco language IDs

Other Core Commands

CommandPurpose
commands:executeExecute a registered VS Code command by ID
configuration:getRead a configuration value
configuration:updateWrite a configuration value
storage:get / storage:set / storage:deleteKey-value storage backed by Mountain’s StorageProvider
textFile:read / textFile:write / textFile:saveEditor working-copy surface
output:create / output:append / output:appendLineOutput channel management
notification:show / notification:showProgressUser-facing notifications
quickInput:showQuickPick / quickInput:showInputBoxQuick-pick and input-box UI round-trips
themes:getActive / themes:list / themes:setTheme management
workspaces:getFolders / workspaces:addFolder / workspaces:removeFolderWorkspace folder management
decorations:get / decorations:set / decorations:clearFile decoration provider
keybinding:add / keybinding:remove / keybinding:lookupKeybinding registry
lifecycle:getPhase / lifecycle:whenPhaseWorkbench lifecycle phase queries
model:open / model:get / model:updateContent / model:closeText model management
search:findFiles / search:findInFilesFile search (routes to Cocoon when TierSearch=Node)
update:checkForUpdates / update:downloadUpdate / update:applyUpdateUpdate service (all stubs; no update server)
auth:getSessions / auth:createSession / auth:removeSessionAuthentication (routes to Cocoon)
tasks:executeTask / tasks:getTasksTask execution (routes to Cocoon)
scm:createSourceControl / scm:getSourceControlsSource control management
debug:startDebugging / debug:getSessions / debug:addBreakpointsDebug session management

The full channel enum is defined in Common/Source/IPC/Channel.rs (Rust) and mirrored in Wind/Source/IPC/Channel.ts (TypeScript). Both must be kept in lockstep — adding a channel to one requires adding it to the other.

Events (Push from Mountain)

Mountain emits events that Wind/Sky listen to via @tauri-apps/api/event:

import { listen } from "@tauri-apps/api/event";

const unlisten = await listen("configuration-changed", (event) => {
	// event.payload contains the changed configuration keys
	updateLocalConfiguration(event.payload);
});

Event Catalog

EventPayloadDirectionPurpose
configuration-changed{ keys: string[] }Mountain -> WindConfiguration updates
extension-activated{ id: string }Mountain -> WindExtension activation notification
terminal-data{ id: number, data: string }Mountain -> WindTerminal output streaming
file-changed{ path: string, type: string }Mountain -> WindFile system watcher notification
theme-changed{ theme: string }Mountain -> WindColor theme change
window-state-changed{ state: string }Mountain -> WindWindow maximize/minimize/fullscreen

Serialization

Tauri IPC uses JSON serialization with the following conventions:

  • Strings are UTF-8 encoded
  • Numbers are JSON numbers (f64), deserialized to appropriate Rust types
  • Binary data is Vec<u8> / Uint8Array, serialized as JSON number arrays for small payloads, or via custom serializer for large files
  • Complex types are serialized through serde Serialize/Deserialize traits

Vine gRPC Protocol 🏔️

Vine defines the gRPC service contracts for Mountain-Cocoon and Mountain-Air communication. The canonical definition lives at Element/Vine/Proto/Vine.proto. Mountain keeps a local sync’d copy at Element/Mountain/Proto/Vine.proto which its build.rs compiles directly.

Service Definitions

syntax = "proto3";

package Vine;

// Service running on the Mountain host, listening for requests from Cocoon.
service MountainService {
  // Generic request-response: Cocoon -> Mountain.
  rpc ProcessCocoonRequest(GenericRequest) returns (GenericResponse);
  // Fire-and-forget notification: Cocoon -> Mountain.
  rpc SendCocoonNotification(GenericNotification) returns (Empty);
  // Cancel a long-running operation.
  rpc CancelOperation(CancelOperationRequest) returns (Empty);
  // LAND-PATCH B7-S6 P2: bidirectional streaming channel.
  rpc OpenChannelFromCocoon(stream Envelope) returns (stream Envelope);
}

// Service running on the Cocoon sidecar, listening for requests from Mountain.
service CocoonService {
  // A generic request-response method for Mountain to call a function on Cocoon.
  rpc ProcessMountainRequest(GenericRequest) returns (GenericResponse);

  // A generic fire-and-forget method for Mountain to send a notification to Cocoon.
  rpc SendMountainNotification(GenericNotification) returns (Empty);

  // A method for Mountain to request that Cocoon cancel a long-running operation.
  rpc CancelOperation(CancelOperationRequest) returns (Empty);

  // LAND-PATCH B7-S6 P2: bidirectional streaming channel (mirror of
  // MountainService::OpenChannelFromCocoon). Mountain opens this
  // stream once per Cocoon connection; all subsequent traffic
  // multiplexes over it.
  rpc OpenChannelFromMountain(stream Envelope) returns (stream Envelope);

  // ==================== Initialization ====================

  // Handshake - Called by Cocoon to signal readiness
  rpc InitialHandshake(Empty) returns (Empty);

  // Initialize Extension Host - Mountain sends initialization data to Cocoon
  rpc InitExtensionHost(InitExtensionHostRequest) returns (Empty);

  // ==================== Commands ====================

  // Register Command - Cocoon registers an extension command
  rpc RegisterCommand(RegisterCommandRequest) returns (Empty);

  // Execute Contributed Command - Mountain executes an extension command
  rpc ExecuteContributedCommand(ExecuteCommandRequest) returns (ExecuteCommandResponse);

  // Unregister Command - Unregister a previously registered command
  rpc UnregisterCommand(UnregisterCommandRequest) returns (Empty);

  // ==================== Language Features ====================

  // Register Hover Provider - Register a hover provider
  rpc RegisterHoverProvider(RegisterProviderRequest) returns (Empty);

  // Provide Hover - Request hover information
  rpc ProvideHover(ProvideHoverRequest) returns (ProvideHoverResponse);

  // Register Completion Item Provider - Register a completion provider
  rpc RegisterCompletionItemProvider(RegisterProviderRequest) returns (Empty);

  // Provide Completion Items - Request completion items
  rpc ProvideCompletionItems(ProvideCompletionItemsRequest) returns (ProvideCompletionItemsResponse);

  // Register Definition Provider - Register a definition provider
  rpc RegisterDefinitionProvider(RegisterProviderRequest) returns (Empty);

  // Provide Definition - Request definition location
  rpc ProvideDefinition(ProvideDefinitionRequest) returns (ProvideDefinitionResponse);

  // Register Reference Provider - Register a reference provider
  rpc RegisterReferenceProvider(RegisterProviderRequest) returns (Empty);

  // Provide References - Request references
  rpc ProvideReferences(ProvideReferencesRequest) returns (ProvideReferencesResponse);

  // Register Code Actions Provider - Register code actions provider
  rpc RegisterCodeActionsProvider(RegisterProviderRequest) returns (Empty);

  // Provide Code Actions - Request code actions
  rpc ProvideCodeActions(ProvideCodeActionsRequest) returns (ProvideCodeActionsResponse);

  // ==================== Language Features (Extended) ====================

  // Register Document Highlight Provider
  rpc RegisterDocumentHighlightProvider(RegisterProviderRequest) returns (Empty);

  // Provide Document Highlights
  rpc ProvideDocumentHighlights(ProvideDocumentHighlightsRequest) returns (ProvideDocumentHighlightsResponse);

  // Register Document Symbol Provider
  rpc RegisterDocumentSymbolProvider(RegisterProviderRequest) returns (Empty);

  // Provide Document Symbols
  rpc ProvideDocumentSymbols(ProvideDocumentSymbolsRequest) returns (ProvideDocumentSymbolsResponse);

  // Register Workspace Symbol Provider
  rpc RegisterWorkspaceSymbolProvider(RegisterProviderRequest) returns (Empty);

  // Provide Workspace Symbols
  rpc ProvideWorkspaceSymbols(ProvideWorkspaceSymbolsRequest) returns (ProvideWorkspaceSymbolsResponse);

  // Register Rename Provider
  rpc RegisterRenameProvider(RegisterProviderRequest) returns (Empty);

  // Provide Rename Edits
  rpc ProvideRenameEdits(ProvideRenameEditsRequest) returns (ProvideRenameEditsResponse);

  // Register Document Formatting Provider
  rpc RegisterDocumentFormattingProvider(RegisterProviderRequest) returns (Empty);

  // Provide Document Formatting
  rpc ProvideDocumentFormatting(ProvideDocumentFormattingRequest) returns (ProvideDocumentFormattingResponse);

  // Register Document Range Formatting Provider
  rpc RegisterDocumentRangeFormattingProvider(RegisterProviderRequest) returns (Empty);

  // Provide Document Range Formatting
  rpc ProvideDocumentRangeFormatting(ProvideDocumentRangeFormattingRequest) returns (ProvideDocumentRangeFormattingResponse);

  // Register On Type Formatting Provider
  rpc RegisterOnTypeFormattingProvider(RegisterOnTypeFormattingProviderRequest) returns (Empty);

  // Provide On Type Formatting
  rpc ProvideOnTypeFormatting(ProvideOnTypeFormattingRequest) returns (ProvideOnTypeFormattingResponse);

  // Register Signature Help Provider
  rpc RegisterSignatureHelpProvider(RegisterSignatureHelpProviderRequest) returns (Empty);

  // Provide Signature Help
  rpc ProvideSignatureHelp(ProvideSignatureHelpRequest) returns (ProvideSignatureHelpResponse);

  // Register Code Lens Provider
  rpc RegisterCodeLensProvider(RegisterProviderRequest) returns (Empty);

  // Provide Code Lenses
  rpc ProvideCodeLenses(ProvideCodeLensesRequest) returns (ProvideCodeLensesResponse);

  // Register Folding Range Provider
  rpc RegisterFoldingRangeProvider(RegisterProviderRequest) returns (Empty);

  // Provide Folding Ranges
  rpc ProvideFoldingRanges(ProvideFoldingRangesRequest) returns (ProvideFoldingRangesResponse);

  // Register Selection Range Provider
  rpc RegisterSelectionRangeProvider(RegisterProviderRequest) returns (Empty);

  // Provide Selection Ranges
  rpc ProvideSelectionRanges(ProvideSelectionRangesRequest) returns (ProvideSelectionRangesResponse);

  // Register Semantic Tokens Provider
  rpc RegisterSemanticTokensProvider(RegisterSemanticTokensProviderRequest) returns (Empty);

  // Provide Semantic Tokens Full
  rpc ProvideSemanticTokensFull(ProvideSemanticTokensRequest) returns (ProvideSemanticTokensResponse);

  // Register Inlay Hints Provider
  rpc RegisterInlayHintsProvider(RegisterProviderRequest) returns (Empty);

  // Provide Inlay Hints
  rpc ProvideInlayHints(ProvideInlayHintsRequest) returns (ProvideInlayHintsResponse);

  // Register Type Hierarchy Provider
  rpc RegisterTypeHierarchyProvider(RegisterProviderRequest) returns (Empty);

  // Provide Type Hierarchy Supertypes
  rpc ProvideTypeHierarchySupertypes(ProvideTypeHierarchyRequest) returns (ProvideTypeHierarchyResponse);

  // Provide Type Hierarchy Subtypes
  rpc ProvideTypeHierarchySubtypes(ProvideTypeHierarchyRequest) returns (ProvideTypeHierarchyResponse);

  // Register Call Hierarchy Provider
  rpc RegisterCallHierarchyProvider(RegisterProviderRequest) returns (Empty);

  // Provide Call Hierarchy Incoming Calls
  rpc ProvideCallHierarchyIncomingCalls(ProvideCallHierarchyRequest) returns (ProvideCallHierarchyResponse);

  // Provide Call Hierarchy Outgoing Calls
  rpc ProvideCallHierarchyOutgoingCalls(ProvideCallHierarchyRequest) returns (ProvideCallHierarchyResponse);

  // Register Linked Editing Range Provider
  rpc RegisterLinkedEditingRangeProvider(RegisterProviderRequest) returns (Empty);

  // Provide Linked Editing Ranges
  rpc ProvideLinkedEditingRanges(ProvideLinkedEditingRangesRequest) returns (ProvideLinkedEditingRangesResponse);
}

Service: MountainService

Used for Cocoon -> Mountain communication:

RPCDirectionTriggerPurpose
ProcessCocoonRequestCocoon -> MountainPer API callGeneric request-response for commands / queries
SendCocoonNotificationCocoon -> MountainState changeFire-and-forget event from extension host
CancelOperationCocoon -> MountainUser cancelsCancel an in-flight operation
OpenChannelFromCocoonCocoon -> MountainAfter handshakeLAND-PATCH B7-S6 P2 bidirectional multiplexed stream

Service: CocoonService

Used for Mountain -> Cocoon communication:

RPCDirectionTriggerPurpose
ProcessMountainRequestMountain -> CocoonPer API callGeneric request-response from backend
SendMountainNotificationMountain -> CocoonBackend eventFire-and-forget notification to sidecar
CancelOperationMountain -> CocoonBackend cancelCancel an in-flight extension operation
OpenChannelFromMountainMountain -> CocoonAfter handshakeLAND-PATCH B7-S6 P2 bidirectional multiplexed stream
InitialHandshakeMountain -> CocoonAfter bootstrapHandshake readiness signal
InitExtensionHostMountain -> CocoonAfter handshakeSend workspace root, extensions, configuration
RegisterCommandCocoon -> MountainExtension bootRegister an extension-contributed command
ExecuteContributedCommandMountain -> CocoonUser triggersExecute an extension-contributed command
UnregisterCommandCocoon -> MountainExtension unloadUnregister an extension command
RegisterHoverProviderCocoon -> MountainExtension bootRegister a hover provider
ProvideHoverMountain -> CocoonUser hoversRequest hover from extension provider
RegisterCompletionItemProviderCocoon -> MountainExtension bootRegister a completion provider
ProvideCompletionItemsMountain -> CocoonUser typesRequest completion items
RegisterDefinitionProviderCocoon -> MountainExtension bootRegister a definition provider
ProvideDefinitionMountain -> CocoonUser clicksRequest definition location
RegisterReferenceProviderCocoon -> MountainExtension bootRegister a reference provider
ProvideReferencesMountain -> CocoonUser triggersRequest reference locations
RegisterCodeActionsProviderCocoon -> MountainExtension bootRegister a code actions provider
ProvideCodeActionsMountain -> CocoonUser triggersRequest code actions
RegisterDocumentHighlightProviderCocoon -> MountainExtension bootRegister a document highlight provider
ProvideDocumentHighlightsMountain -> CocoonUser hoversRequest document highlights
RegisterDocumentSymbolProviderCocoon -> MountainExtension bootRegister a document symbol provider
ProvideDocumentSymbolsMountain -> CocoonSidebar openRequest document symbols
RegisterWorkspaceSymbolProviderCocoon -> MountainExtension bootRegister a workspace symbol provider
ProvideWorkspaceSymbolsMountain -> CocoonSearch typesRequest workspace symbols
RegisterRenameProviderCocoon -> MountainExtension bootRegister a rename provider
ProvideRenameEditsMountain -> CocoonUser triggersRequest rename edits
RegisterDocumentFormattingProviderCocoon -> MountainExtension bootRegister a document formatting provider
ProvideDocumentFormattingMountain -> CocoonUser triggersRequest document formatting
RegisterDocumentRangeFormattingProviderCocoon -> MountainExtension bootRegister a range formatting provider
ProvideDocumentRangeFormattingMountain -> CocoonUser triggersRequest document range formatting
RegisterOnTypeFormattingProviderCocoon -> MountainExtension bootRegister an on-type formatting provider
ProvideOnTypeFormattingMountain -> CocoonUser typesRequest on-type formatting
RegisterSignatureHelpProviderCocoon -> MountainExtension bootRegister a signature help provider
ProvideSignatureHelpMountain -> CocoonUser typesRequest signature help
RegisterCodeLensProviderCocoon -> MountainExtension bootRegister a code lens provider
ProvideCodeLensesMountain -> CocoonCode lens shownRequest code lenses
RegisterFoldingRangeProviderCocoon -> MountainExtension bootRegister a folding range provider
ProvideFoldingRangesMountain -> CocoonFile openedRequest folding ranges
RegisterSelectionRangeProviderCocoon -> MountainExtension bootRegister a selection range provider
ProvideSelectionRangesMountain -> CocoonUser selectsRequest selection ranges
RegisterSemanticTokensProviderCocoon -> MountainExtension bootRegister a semantic tokens provider
ProvideSemanticTokensFullMountain -> CocoonFile openedRequest semantic tokens
RegisterInlayHintsProviderCocoon -> MountainExtension bootRegister an inlay hints provider
ProvideInlayHintsMountain -> CocoonUser hoversRequest inlay hints
RegisterTypeHierarchyProviderCocoon -> MountainExtension bootRegister a type hierarchy provider
ProvideTypeHierarchySupertypesMountain -> CocoonUser triggersRequest type hierarchy supertypes
ProvideTypeHierarchySubtypesMountain -> CocoonUser triggersRequest type hierarchy subtypes
RegisterCallHierarchyProviderCocoon -> MountainExtension bootRegister a call hierarchy provider
ProvideCallHierarchyIncomingCallsMountain -> CocoonUser triggersRequest call hierarchy incoming calls
ProvideCallHierarchyOutgoingCallsMountain -> CocoonUser triggersRequest call hierarchy outgoing calls
RegisterLinkedEditingRangeProviderCocoon -> MountainExtension bootRegister a linked editing range provider
ProvideLinkedEditingRangesMountain -> CocoonUser editsRequest linked editing ranges

Message Formats

// A generic request / response envelope shared across all RPCs.
message GenericRequest {
  uint64 RequestIdentifier = 1;
  string Method = 2;              // JSON-serialized parameters
  bytes Parameter = 3;
}

message GenericResponse {
  uint64 RequestIdentifier = 1;
  bytes Result = 2;               // JSON-serialized success payload
  optional RPCError error = 3;   // JSON-RPC-style error object
}

message GenericNotification {
  string Method = 1;
  bytes Parameter = 2;           // JSON-serialized
}

message RPCError {
  int32 Code = 1;
  string Message = 2;
  bytes Data = 3;
}

message CancelOperationRequest {
  uint64 RequestIdentifierToCancel = 1;
}

message Empty {}

Common types used across messages:

message Position {
  uint32 Line = 1;
  uint32 Character = 2;
}

message Range {
  Position Start = 1;
  Position End = 2;
}

message Uri {
  string Value = 1;
}

message WorkspaceFolder {
  Uri Uri = 1;
  string Name = 2;
}

message CompletionItem { /* ... */ }
message Location { /* ... */ }

Port Allocation

ServiceElementPortTransport
Mountain VineMountain50051TCP
Cocoon VineCocoon50052TCP
Air VineAir50053TCP

All listeners bind to [::1] (not 0.0.0.0). Environment overrides are described in Vine/Source/Library.rs.


Spine Extension Protocol 🔄

The Spine protocol is the extension host coordination layer built on top of Vine gRPC. It implements an action/response pattern for extension-to-backend communication.

Action/Response Pattern

sequenceDiagram
    participant Extension as Extension code in Cocoon
    participant Shim as Cocoon vscode shim
    participant Spine as Spine protocol
    participant Mountain as Mountain ActionHandler
    participant Trait as Common trait impl

    Extension->>Shim: Call vscode API (e.g., openTextDocument)
    Shim->>Shim: Create ActionEffect
    Shim->>Spine: gRPC PerformAction(ActionRequest)
    Spine->>Mountain: Route to ActionHandler
    Mountain->>Trait: Execute action via Common trait implementation
    Trait-->>Mountain: Action result
    Mountain-->>Spine: ActionResponse { result, error }
    Spine-->>Shim: gRPC response
    Shim-->>Extension: Return result to extension

ActionEffect Types

The Spine protocol encodes all possible extension actions as a discriminated union:

ActionEffect
    +-- ReadFile { path }
    +-- WriteFile { path, content }
    +-- DeleteFile { path }
    +-- ReadDirectory { path }
    +-- CreateDirectory { path }
    +-- Stat { path }
    +-- Rename { from, to }
    +-- Copy { from, to }
    +-- WatchFile { path }
    +-- OpenDialog { options }
    +-- SaveDialog { options }
    +-- ShowMessage { message, options }
    +-- ShowInputBox { options }
    +-- OpenExternal { url }
    +-- ExecuteProcess { command, args }
    +-- ExecuteCommand { command_id, args }
    +-- RegisterCommand { command_id, handler }
    +-- CreateTerminal { options }
    +-- WriteTerminal { id, data }
    +-- ReadClipboard { format }
    +-- WriteClipboard { text }
    +-- GetConfiguration { key }
    +-- SetConfiguration { key, value, target }
    +-- GetSecret { key }
    +-- SetSecret { key, value }
    +-- DeleteSecret { key }
    +-- CreateWebviewPanel { options }
    +-- SendWebviewMessage { id, message }
    // ... 80+ effect variants

Routing

The Cocoon tier router (Cocoon/Source/Services/Handler/VscodeAPI/ROUTING.md) decides per-call whether to:

  1. Track A (Stock Node): Handle entirely in-process via unmodified extHost*.ts code
  2. Track B (Rust Native): Package as ActionEffect, send via Spine gRPC to Mountain, await native execution
  3. Track C (Cocoon Bespoke): Hand-rolled TypeScript implementation in Cocoon (last resort)

Connection Lifecycle 🔄

Mountain-Cocoon Connection

Bootstrap order (critical): Cocoon’s gRPC server (port 50052) must bind before Cocoon attempts to connect to Mountain’s gRPC server (port 50051). The bootstrap stage order is: RPCServer (Stage 5) bind -> MountainConnection (Stage 3) connect. Mountain allows a 30-second connection budget; reversing this order causes Mountain to time out before Cocoon is ready to accept the handshake.

sequenceDiagram
    participant Mountain as Mountain
    participant Server as gRPC Server
    participant Cocoon as Cocoon sidecar
    participant Init as Initialization

    Mountain->>Server: Start gRPC server on port 50051
    Mountain->>Cocoon: Spawn node bootstrap-fork.js
    Cocoon->>Server: Connect gRPC client to 127.0.0.1:50051
    Cocoon->>Server: Send $initialHandshake notification
    Server-->>Mountain: Handshake received
    Mountain->>Mountain: Gather InitData (workspace, extensions, config)
    Mountain->>Cocoon: Send Initialize(InitData)
    Cocoon->>Init: Create InitDataLayer
    Init->>Init: Run FullAppInitialization
    Init->>Init: Install RequireInterceptor
    Init->>Init: Activate startup extensions
    Cocoon->>Server: Send activity ping every 5 seconds
    Server-->>Mountain: Connection established, normal operation

Disconnection and Reconnection

Network failure or Cocoon crash
    |
    v
Mountain detects stale connection (no activity within 30-second check window)
    |
    +---> Option 1: Restart Cocoon (default, up to 3 attempts)
    |       - Kill existing Cocoon process
    |       - Re-spawn from bootstrap-fork.js
    |       - Re-run initialization sequence
    |       - Restored state: configuration, open files
    |       - Lost state: extension-managed data, webview panels
    |
    +---> Option 2: Graceful degradation
            - Show reconnection notification in UI
            - Queue extension API calls
            - Reconnect when Cocoon restarts (user manually)

Mountain-Air Connection

Mountain starts
    |
    v
Mountain spawns Air binary
    |
    v
Air connects gRPC to 127.0.0.1:50053
    |
    +---> Sends Connect { services: [updater, indexer, crypto] }
    |
    v
Mountain registers Air services in AppState
    |
    v
Normal operation:
    - Mountain dispatches background work via PerformAction
    - Air responds with action results
    - Both sides maintain activity tracking
    - Staleness check every 30 seconds

Health Monitoring 💓

Heartbeat Protocol

Both gRPC connections (Mountain-Cocoon, Mountain-Air) implement a health monitoring protocol. Health is tracked via a per-connection ConnectionMetadata struct in Vine/Source/Client/Shared.rs:

ParameterValue
Staleness check interval30 seconds (HEALTH_CHECK_INTERVAL_MS)
Max retry attempts10 (MAX_RETRY_ATTEMPTS)
Retry base delay200 ms (RETRY_BASE_DELAY_MS)
Connection timeout30 seconds (CONNECTION_TIMEOUT)

Health is determined by three conditions in Vine/Source/Client/CheckSideCarHealth.rs: the connection must be marked IsHealthy, the LastActivity timestamp must not be older than HEALTH_CHECK_INTERVAL_MS (30 seconds), and the FailureCount must not exceed MAX_RETRY_ATTEMPTS (10). Failed connections are recorded via RecordSideCarFailure which increments the counter and sets IsHealthy to false; successful activity resets both via UpdateSideCarActivity.

Diagnostic Logging

All connection state changes are logged via the dev_log! system at Mountain/Source/IPC/DevLog/:

[DEV:Vine] gRPC server listening on [::1]:50051
[DEV:Vine] Cocoon connected, handshake received
[DEV:Vine] Heartbeat OK (seq=142, latency=3ms)
[DEV:Vine] Heartbeat TIMEOUT (last: seq=147, 18s ago)
[DEV:Vine] Cocoon disconnected, restarting (attempt 1/3)

Protocol Buffer Definitions 📁

Current Location

Protocol definitions currently reside in consuming components:

FileLocationPurpose
Vine.protoElement/Vine/Proto/Vine.protoCore Mountain<->Cocoon gRPC services
Grove.protoElement/Grove/Proto/Grove.protoGrove-specific WASM hosting extensions
Server implElement/Mountain/Source/Vine/Rust gRPC server (tonic, consumes Vine stubs)
Client implElement/Cocoon/Source/Services/Mountain/gRPC/Client.tsTypeScript gRPC client
RouteManifestElement/Cocoon/Source/Generated/RouteManifest.tsAuto-generated routing tier enumeration

Code Generation

Rust types are generated from .proto files using prost and tonic-build at compile time:

// Mountain/build.rs  (references Vine element's proto)
fn main() {
    tonic_build::configure()
        .compile(&["../Vine/Proto/Vine.proto"], &["../Vine/Proto"])
        .expect("Failed to compile protos");
}

TypeScript types are generated using protoc-gen-ts and checked into the Cocoon source tree as generated artifacts.


Security 🛡️

All gRPC connections are restricted to localhost only ([::1] / 127.0.0.1). No remote connections are accepted.

AspectImplementation
TransportTCP loopback only
AuthNone required (localhost-only)
EncryptionNone (localhost-only, no network exposure)
Port binding[::1] only, not 0.0.0.0
DNS isolationAll non-localhost traffic blocked by Mist
Timeout30-second staleness check
BackpressuregRPC flow control + bounded channels


Project Maintainers: Source Open (Source/[email protected]) | GitHub Repository | Report an Issue