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.
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
| Property | Type | Description |
|---|---|---|
id | string | Unique plugin identifier |
extensionPath | string | Absolute path to plugin directory |
storagePath | string | Path for plugin-specific local storage |
globalStoragePath | string | Path for global plugin storage |
Logger API
Logging utilities for debugging and monitoring.
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
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
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:
interface SecretStorage {
get(key: string): Promise<string | undefined>;
set(key: string, value: string): Promise<void>;
delete(key: string): Promise<void>;
}Usage
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.
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
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.
interface CommandsAPI {
register(
id: string,
handler: (...args: unknown[]) => Promise<unknown> | unknown
): Disposable;
execute<T>(id: string, ...args: unknown[]): Promise<T>;
}Usage
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.
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.
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.
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
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.
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
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).
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
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.
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
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.
interface I18nAPI {
t(key: string, params?: Record<string, unknown>): string;
locale: string;
onDidChangeLocale: Event<string>;
}Usage
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:
interface Disposable {
dispose(): void;
}Best Practice
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:
npm install alma-plugin-apiThen import types:
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';