Skip to content

Alma Plugin API Reference

Complete reference for all APIs available to Alma plugins.

PluginContext

The PluginContext object is passed to your plugin's activate function and provides access to all Alma APIs.

typescript
interface PluginContext {
    // Plugin info
    readonly id: string;
    readonly extensionPath: string;
    readonly storagePath: string;
    readonly globalStoragePath: string;

    // APIs
    readonly logger: Logger;
    readonly storage: StorageAPIs;
    readonly tools: ToolsAPI;
    readonly commands: CommandsAPI;
    readonly events: EventsAPI;
    readonly ui: UIAPI;
    readonly chat: ChatAPI;
    readonly providers: ProvidersAPI;
    readonly workspace: WorkspaceAPI;
    readonly settings: SettingsAPI;
    readonly i18n: I18nAPI;
}

Context Properties

PropertyTypeDescription
idstringUnique plugin identifier
extensionPathstringAbsolute path to plugin directory
storagePathstringPath for plugin-specific local storage
globalStoragePathstringPath for global plugin storage

Logger API

Logging utilities for debugging and monitoring.

typescript
interface Logger {
    info(message: string, ...args: unknown[]): void;
    warn(message: string, ...args: unknown[]): void;
    error(message: string, ...args: unknown[]): void;
    debug(message: string, ...args: unknown[]): void;
}

Usage

typescript
const { logger } = context;

logger.info('Plugin started');
logger.debug('Processing data:', { key: 'value' });
logger.warn('Deprecated API used');
logger.error('Failed to connect:', error);

Storage API

Persistent key-value storage for plugin data.

Local Storage

typescript
interface Storage {
    get<T>(key: string): Promise<T | undefined>;
    get<T>(key: string, defaultValue: T): Promise<T>;
    set(key: string, value: unknown): Promise<void>;
    delete(key: string): Promise<void>;
    keys(): Promise<string[]>;
    clear(): Promise<void>;
}

Secret Storage

For sensitive data like API keys:

typescript
interface SecretStorage {
    get(key: string): Promise<string | undefined>;
    set(key: string, value: string): Promise<void>;
    delete(key: string): Promise<void>;
}

Usage

typescript
const { storage } = context;

// Local storage
await storage.local.set('lastRun', Date.now());
const lastRun = await storage.local.get<number>('lastRun', 0);

// Workspace storage (per-project)
await storage.workspace.set('projectConfig', { theme: 'dark' });

// Secret storage (encrypted)
await storage.secrets.set('apiKey', 'sk-xxx...');
const apiKey = await storage.secrets.get('apiKey');

Tools API

Register tools that the AI assistant can use.

typescript
interface ToolsAPI {
    register<TParams extends z.ZodType>(
        id: string,
        definition: ToolDefinition<TParams>
    ): Disposable;
    unregister(id: string): void;
}

interface ToolDefinition<TParams extends z.ZodType> {
    description: string;
    parameters: TParams;
    execute: (params: z.infer<TParams>, context: ToolContext) => Promise<unknown>;
}

interface ToolContext {
    threadId: string;
    messageId: string;
    abortSignal?: AbortSignal;
}

Usage

typescript
import { z } from 'zod';

const { tools, logger } = context;

const disposable = tools.register('weather', {
    description: 'Get current weather for a location',
    parameters: z.object({
        city: z.string().describe('City name'),
        units: z.enum(['celsius', 'fahrenheit']).default('celsius'),
    }),
    execute: async (params, ctx) => {
        logger.info(`Getting weather for ${params.city}`);

        // Check for cancellation
        if (ctx.abortSignal?.aborted) {
            throw new Error('Request cancelled');
        }

        // Fetch weather data...
        return {
            city: params.city,
            temperature: 22,
            units: params.units,
            condition: 'sunny',
        };
    },
});

// Remember to dispose when plugin deactivates
disposable.dispose();

Commands API

Register commands that users can invoke from the command palette.

typescript
interface CommandsAPI {
    register(
        id: string,
        handler: (...args: unknown[]) => Promise<unknown> | unknown
    ): Disposable;
    execute<T>(id: string, ...args: unknown[]): Promise<T>;
}

Usage

typescript
const { commands, ui } = context;

// Register a command
const disposable = commands.register('myPlugin.sayHello', async () => {
    ui.showNotification('Hello!');
});

// Execute another command
await commands.execute('alma.openSettings');

Events API

Subscribe to lifecycle events and hooks.

typescript
interface EventsAPI {
    on<T extends HookName>(
        hookName: T,
        handler: HookHandler<T>,
        options?: { priority?: number }
    ): Disposable;
    once<T extends HookName>(
        hookName: T,
        handler: HookHandler<T>
    ): Disposable;
}

See Hooks & Events Guide for detailed documentation.


UI API

User interface utilities.

typescript
interface UIAPI {
    showNotification(message: string, options?: NotificationOptions): void;
    showError(message: string): void;
    showWarning(message: string): void;
    showQuickPick<T>(items: QuickPickItem<T>[], options?: QuickPickOptions): Promise<T | undefined>;
    showInputBox(options?: InputBoxOptions): Promise<string | undefined>;
    showConfirmDialog(message: string, options?: ConfirmOptions): Promise<boolean>;
    withProgress<T>(options: ProgressOptions, task: ProgressTask<T>): Promise<T>;
    createStatusBarItem(options: StatusBarItemOptions): StatusBarItem;
    readonly theme: {
        current: Theme;
        onChange: Event<Theme>;
    };
}

See UI API Guide for detailed documentation.


Chat API

Access chat threads and messages.

typescript
interface ChatAPI {
    getThread(id: string): Promise<Thread | undefined>;
    getActiveThread(): Promise<Thread | undefined>;
    createThread(options?: { title?: string; model?: string }): Promise<Thread>;
    getMessages(threadId: string): Promise<Message[]>;
}

interface Thread {
    id: string;
    title: string;
    model?: string;
    createdAt: string;
    updatedAt: string;
}

interface Message {
    id: string;
    role: 'user' | 'assistant' | 'system';
    content: string;
    createdAt: string;
}

Usage

typescript
const { chat, logger } = context;

// Get the current thread
const activeThread = await chat.getActiveThread();
if (activeThread) {
    logger.info(`Current thread: ${activeThread.title}`);

    // Get all messages
    const messages = await chat.getMessages(activeThread.id);
    logger.info(`Thread has ${messages.length} messages`);
}

// Create a new thread
const newThread = await chat.createThread({
    title: 'New Conversation',
    model: 'claude-3-opus',
});

Providers API

Access and register AI providers.

typescript
interface ProvidersAPI {
    list(): Promise<Provider[]>;
    get(id: string): Promise<Provider | undefined>;
    register(provider: ProviderDefinition): Disposable;
}

interface Provider {
    id: string;
    name: string;
    type: string;
    enabled: boolean;
}

interface ProviderDefinition {
    id: string;
    name: string;
    icon?: string;
    getModels(): Promise<Array<{ id: string; name: string }>>;
    createChatCompletion(request: {
        model: string;
        messages: Message[];
        stream?: boolean;
    }): Promise<ReadableStream | { content: string }>;
}

Usage

typescript
const { providers, logger } = context;

// List all providers
const allProviders = await providers.list();
for (const provider of allProviders) {
    logger.info(`Provider: ${provider.name} (${provider.enabled ? 'enabled' : 'disabled'})`);
}

// Register a custom provider
const disposable = providers.register({
    id: 'my-provider',
    name: 'My Custom Provider',
    async getModels() {
        return [
            { id: 'model-1', name: 'Model One' },
            { id: 'model-2', name: 'Model Two' },
        ];
    },
    async createChatCompletion(request) {
        // Implement chat completion...
        return { content: 'Response from my provider' };
    },
});

Workspace API

File system operations (requires appropriate permissions).

typescript
interface WorkspaceAPI {
    readonly rootPath: string | undefined;
    readonly workspaceFolders: WorkspaceFolder[];
    readFile(filePath: string): Promise<Uint8Array>;
    writeFile(filePath: string, content: Uint8Array): Promise<void>;
    stat(filePath: string): Promise<FileStat>;
    readDirectory(dirPath: string): Promise<[string, FileType][]>;
    createFileSystemWatcher(pattern: string): FileSystemWatcher;
}

interface WorkspaceFolder {
    id: string;
    path: string;
    name: string;
}

interface FileStat {
    type: 'file' | 'directory' | 'symlink';
    size: number;
    mtime: number;
    ctime: number;
}

type FileType = 'file' | 'directory' | 'symlink' | 'unknown';

interface FileSystemWatcher extends Disposable {
    onDidCreate: Event<string>;
    onDidChange: Event<string>;
    onDidDelete: Event<string>;
}

Usage

typescript
const { workspace, logger } = context;

// Read a file
const content = await workspace.readFile('/path/to/file.txt');
const text = new TextDecoder().decode(content);

// Write a file
const data = new TextEncoder().encode('Hello, World!');
await workspace.writeFile('/path/to/output.txt', data);

// Watch for file changes
const watcher = workspace.createFileSystemWatcher('**/*.ts');
watcher.onDidChange((path) => {
    logger.info(`File changed: ${path}`);
});

Settings API

Read and write plugin settings.

typescript
interface SettingsAPI {
    get<T>(key: string): T | undefined;
    get<T>(key: string, defaultValue: T): T;
    update(key: string, value: unknown): Promise<void>;
    onDidChange: Event<SettingsChangeEvent>;
}

interface SettingsChangeEvent {
    key: string;
    oldValue: unknown;
    newValue: unknown;
}

Usage

typescript
const { settings, logger } = context;

// Read a setting with default value
const enabled = settings.get<boolean>('myPlugin.enabled', true);
const threshold = settings.get<number>('myPlugin.threshold', 100);

// Update a setting
await settings.update('myPlugin.lastRun', Date.now());

// React to setting changes
const disposable = settings.onDidChange((event) => {
    if (event.key === 'myPlugin.enabled') {
        logger.info(`Plugin ${event.newValue ? 'enabled' : 'disabled'}`);
    }
});

I18n API

Internationalization support.

typescript
interface I18nAPI {
    t(key: string, params?: Record<string, unknown>): string;
    locale: string;
    onDidChangeLocale: Event<string>;
}

Usage

typescript
const { i18n, logger } = context;

// Get current locale
logger.info(`Current locale: ${i18n.locale}`);

// Translate a string
const greeting = i18n.t('hello', { name: 'World' });

// React to locale changes
i18n.onDidChangeLocale((newLocale) => {
    logger.info(`Locale changed to: ${newLocale}`);
});

Disposable Pattern

Many API methods return a Disposable object. Always dispose of resources when your plugin deactivates:

typescript
interface Disposable {
    dispose(): void;
}

Best Practice

typescript
export async function activate(context: PluginContext): Promise<PluginActivation> {
    const disposables: Disposable[] = [];

    // Collect all disposables
    disposables.push(
        context.commands.register('myCommand', () => {}),
        context.events.on('app.ready', () => {}),
        context.settings.onDidChange(() => {})
    );

    return {
        dispose: () => {
            // Dispose all at once
            disposables.forEach(d => d.dispose());
        },
    };
}

Type Definitions

Install the type definitions package for full TypeScript support:

bash
npm install alma-plugin-api

Then import types:

typescript
import type {
    PluginContext,
    PluginActivation,
    Disposable,
    Logger,
    Storage,
    SecretStorage,
    ToolsAPI,
    ToolDefinition,
    ToolContext,
    CommandsAPI,
    EventsAPI,
    HookName,
    HookHandler,
    HookInput,
    HookOutput,
    UIAPI,
    NotificationOptions,
    StatusBarItem,
    ChatAPI,
    Thread,
    Message,
    ProvidersAPI,
    Provider,
    WorkspaceAPI,
    SettingsAPI,
    I18nAPI,
} from 'alma-plugin-api';