Skip to main content

Introduction

The Glass Extension API allows you to write extensions for Glass code editor in Rust. Extensions run in a secure WebAssembly (WASM) sandbox and can:
  • Integrate language servers for code intelligence
  • Add custom slash commands to the AI assistant
  • Provide context servers for AI features
  • Configure debugging adapters (DAP)
  • Index documentation for the /docs command
Extensions are compiled to WebAssembly and run in an isolated environment. This provides security while enabling rich functionality.

Core Concepts

Extension Trait

All extensions implement the Extension trait, which defines lifecycle methods and integration points:
use zed_extension_api::{self as zed, Result, LanguageServerId};

struct MyExtension {
    // Extension state
}

impl zed::Extension for MyExtension {
    fn new() -> Self {
        Self { /* initialize */ }
    }

    fn language_server_command(
        &mut self,
        language_server_id: &LanguageServerId,
        worktree: &zed::Worktree,
    ) -> Result<zed::Command> {
        // Return command to start language server
        Ok(zed::Command {
            command: "language-server".to_string(),
            args: vec!["--stdio".to_string()],
            env: Default::default(),
        })
    }
}

zed::register_extension!(MyExtension);

Extension Registration

Register your extension using the register_extension! macro at the end of your main module:
zed::register_extension!(MyExtension);
This macro generates the WebAssembly exports needed for Glass to initialize and communicate with your extension.

Extension Trait Methods

The Extension trait provides many optional methods you can implement:

Language Server Integration

language_server_command
fn
Returns the command to start a language server process.Parameters:
  • language_server_id: &LanguageServerId - ID of the language server
  • worktree: &Worktree - The project worktree
Returns: Result<Command> - Command to execute
language_server_initialization_options
fn
Returns initialization options passed to the language server on startup.Parameters:
  • language_server_id: &LanguageServerId
  • worktree: &Worktree
Returns: Result<Option<serde_json::Value>> - JSON initialization options
language_server_workspace_configuration
fn
Returns workspace configuration options for the language server.Parameters:
  • language_server_id: &LanguageServerId
  • worktree: &Worktree
Returns: Result<Option<serde_json::Value>> - JSON configuration

Completion and Symbol Labels

label_for_completion
fn
Customizes how code completions are displayed.Parameters:
  • language_server_id: &LanguageServerId
  • completion: Completion - The completion item
Returns: Option<CodeLabel> - Custom label or None for default
label_for_symbol
fn
Customizes how symbols are displayed in symbol search.Parameters:
  • language_server_id: &LanguageServerId
  • symbol: Symbol - The symbol
Returns: Option<CodeLabel> - Custom label or None

Slash Commands

complete_slash_command_argument
fn
Provides completions for slash command arguments.Parameters:
  • command: SlashCommand - The slash command being completed
  • args: Vec<String> - Current arguments
Returns: Result<Vec<SlashCommandArgumentCompletion>>
run_slash_command
fn
Executes a slash command.Parameters:
  • command: SlashCommand
  • args: Vec<String> - Command arguments
  • worktree: Option<&Worktree>
Returns: Result<SlashCommandOutput> - Command output for the AI assistant

Context Servers

context_server_command
fn
Returns command to start a Model Context Protocol (MCP) server.Parameters:
  • context_server_id: &ContextServerId
  • project: &Project
Returns: Result<Command>
context_server_configuration
fn
Returns configuration for a context server.Parameters:
  • context_server_id: &ContextServerId
  • project: &Project
Returns: Result<Option<ContextServerConfiguration>>

Documentation Indexing

suggest_docs_packages
fn
Suggests package names for /docs command completions.Parameters:
  • provider: String - Documentation provider name
Returns: Result<Vec<String>> - List of package names
index_docs
fn
Indexes documentation for a specific package.Parameters:
  • provider: String
  • package: String - Package name to index
  • database: &KeyValueStore - Storage for indexed data
Returns: Result<()>

Debug Adapter Protocol (DAP)

get_dap_binary
fn
Returns the debug adapter binary path.Parameters:
  • adapter_name: String
  • config: DebugTaskDefinition
  • user_provided_debug_adapter_path: Option<String>
  • worktree: &Worktree
Returns: Result<DebugAdapterBinary>
dap_request_kind
fn
Determines if debug request is launch or attach.Parameters:
  • adapter_name: String
  • config: serde_json::Value
Returns: Result<StartDebuggingRequestArgumentsRequest>
dap_config_to_scenario
fn
Converts high-level debug config to adapter-specific scenario.Parameters:
  • config: DebugConfig
Returns: Result<DebugScenario>

Resources

The Extension API provides several resource types representing editor state:

Worktree

Represents a project worktree (folder):
let root = worktree.root_path();
let id = worktree.id();
let contents = worktree.read_text_file("path/to/file.txt")?;
let node_path = worktree.which("node");
let env = worktree.shell_env();
id
u64
Returns the unique ID of this worktree
root_path
String
Returns the absolute path to the worktree root
read_text_file
Result<String>
Reads a text file from the worktree
which
Option<String>
Finds a binary in PATH, returns absolute path if found
shell_env
EnvVars
Returns the current shell environment variables

Project

Represents the entire project:
let worktree_ids = project.worktree_ids();
worktree_ids
Vec<u64>
Returns IDs of all worktrees in the project

KeyValueStore

Simple key-value storage for extension data:
database.insert("key", "value")?;
insert
Result<()>
Stores a key-value pair. Both key and value must be strings.

Helper Functions

Language Server Status

zed::set_language_server_installation_status(
    &language_server_id,
    &zed::LanguageServerInstallationStatus::Downloading,
);
Status values:
  • None - No status
  • Downloading - Downloading language server
  • CheckingForUpdate - Checking for updates
  • Failed(String) - Installation failed with reason

File Downloads

use zed::DownloadedFileType;

zed::download_file(
    "https://example.com/server.tar.gz",
    "language-server/server",
    DownloadedFileType::GzipTar,
)?;

zed::make_file_executable("language-server/server")?;
Downloads are saved relative to the extension’s working directory, not the project root.

Node.js Integration

// Get node binary path
let node = zed::node_binary_path()?;

// Install npm package
let version = zed::npm_package_latest_version("typescript-language-server")?;
zed::npm_install_package("typescript-language-server", &version)?;

// Check installed version
let installed = zed::npm_package_installed_version("typescript-language-server")?;

GitHub Releases

use zed::{latest_github_release, GithubReleaseOptions};

let release = latest_github_release(
    "rust-lang/rust-analyzer",
    GithubReleaseOptions {
        require_assets: true,
        pre_release: false,
    },
)?;

for asset in release.assets {
    if asset.name.contains("linux") {
        // Download this asset
    }
}

Platform Detection

use zed::{current_platform, Os, Architecture};

let platform = current_platform();
match platform.os {
    Os::Mac => { /* macOS-specific logic */ }
    Os::Linux => { /* Linux-specific logic */ }
    Os::Windows => { /* Windows-specific logic */ }
}

match platform.arch {
    Architecture::Aarch64 => { /* ARM64 */ }
    Architecture::X8664 => { /* x86_64 */ }
    Architecture::X86 => { /* x86 */ }
}

Complete Example

Here’s a complete extension that integrates a Node.js-based language server:
use zed_extension_api::{self as zed, LanguageServerId, Result};
use std::fs;

const SERVER_PATH: &str = "node_modules/.bin/typescript-language-server";
const PACKAGE_NAME: &str = "typescript-language-server";

struct TypeScriptExtension {
    cached_binary_path: Option<String>,
}

impl zed::Extension for TypeScriptExtension {
    fn new() -> Self {
        Self {
            cached_binary_path: None,
        }
    }

    fn language_server_command(
        &mut self,
        language_server_id: &LanguageServerId,
        worktree: &zed::Worktree,
    ) -> Result<zed::Command> {
        // Check if server exists in PATH first
        if let Some(path) = worktree.which("typescript-language-server") {
            return Ok(zed::Command {
                command: path,
                args: vec!["--stdio".to_string()],
                env: Default::default(),
            });
        }

        // Otherwise install via npm
        if !fs::metadata(SERVER_PATH).is_ok() {
            zed::set_language_server_installation_status(
                language_server_id,
                &zed::LanguageServerInstallationStatus::CheckingForUpdate,
            );

            let version = zed::npm_package_latest_version(PACKAGE_NAME)?;

            zed::set_language_server_installation_status(
                language_server_id,
                &zed::LanguageServerInstallationStatus::Downloading,
            );

            zed::npm_install_package(PACKAGE_NAME, &version)?;
        }

        let node_path = zed::node_binary_path()?;
        Ok(zed::Command {
            command: node_path,
            args: vec![SERVER_PATH.to_string(), "--stdio".to_string()],
            env: Default::default(),
        })
    }

    fn language_server_initialization_options(
        &mut self,
        _server_id: &LanguageServerId,
        _worktree: &zed::Worktree,
    ) -> Result<Option<zed::serde_json::Value>> {
        Ok(Some(zed::serde_json::json!({
            "preferences": {
                "includeInlayParameterNameHints": "all",
                "includeInlayFunctionParameterTypeHints": true,
            }
        })))
    }
}

zed::register_extension!(TypeScriptExtension);

Next Steps

Language Server Integration

Learn how to integrate language servers with LSP

Commands API

Execute commands and manage processes

Configuration

Access and use extension settings

Language Extensions

See complete working examples

Build docs developers (and LLMs) love