Skip to content

Plugin API Reference

The LokusPluginAPI is the top-level object passed to plugins via context.api. It provides access to all sub-APIs: editor, UI, filesystem, commands, network, storage, clipboard, workspace, languages, themes, configuration, terminal, tasks, debug, and notifications.

Every API method is permission-gated. Calling a method without the required permission throws PermissionDeniedError.

// Inside your plugin
const api = context.api;
api.editor // EditorAPI - editor content and extensions
api.ui // UIAPI - panels, dialogs, status bar, webviews
api.commands // CommandsAPI - register and execute commands
api.fs // FilesystemAPI - file read/write operations
api.network // NetworkAPI - HTTP requests
api.storage // DataAPI - key-value storage
api.clipboard // ClipboardAPI - clipboard read/write
api.workspace // WorkspaceAPI - workspace folders and configuration
api.languages // LanguagesAPI - language feature providers
api.themes // ThemeAPI - theme registration
api.config // ConfigurationAPI - configuration values
api.terminal // TerminalAPI - terminal instances
api.notifications // NotificationsAPI - show/hide notifications
api.tasks // TaskAPI - task providers
api.debug // DebugAPI - debug sessions

Access to the TipTap editor. Read content, insert nodes, register extensions, add slash commands, and listen for updates.

Required permissions: editor:read for read operations, editor:write for modifications.

MethodParametersReturnsPermissionDescription
getText()Promise<string>editor:readGet the full editor text content
getSelection()Promise<Selection>editor:readGet the current selection
replaceSelection(content)content: stringPromise<void>editor:writeReplace the current selection with new content
insertNode(type, attrs, content)type: string, attrs?: object, content?: stringPromise<void>editor:writeInsert a node at the cursor position
onUpdate(callback)callback: FunctionDisposableeditor:readSubscribe to editor content changes
const text = await api.editor.getText();
const sel = await api.editor.getSelection(); // { start, end, isEmpty, isSingleLine }
await api.editor.replaceSelection('New text');
await api.editor.insertNode('heading', { level: 2 }, 'My Heading');
MethodParametersReturnsPermissionDescription
addExtension(options)See belowPromise<string>editor:writeRegister a TipTap extension
removeExtension(extensionId)extensionId: stringvoideditor:writeRemove a registered extension
ParameterTypeRequiredDescription
namestringYesExtension name
typestringNo'extension' (default), 'node', or 'mark'
schemaobjectNoProseMirror schema definition
viewobjectNoNode view definition
commandsobjectNoCommands the extension provides
inputRulesarrayNoInput rules for auto-formatting
keyboardShortcutsobjectNoKeyboard shortcut mappings
const extId = await api.editor.addExtension({
name: 'highlight',
type: 'mark',
schema: {
attrs: { color: { default: 'yellow' } },
parseDOM: [{ tag: 'mark' }],
toDOM: (node) => ['mark', { style: `background: ${node.attrs.color}` }, 0]
}
});
MethodParametersReturnsPermissionDescription
addSlashCommand(options)See belowPromise<string>editor:writeAdd a slash command to the editor
ParameterTypeRequiredDescription
namestringYesCommand name (what users type after /)
descriptionstringYesDescription shown in the slash menu
iconstringNoIcon identifier
aliasesstring[]NoAlternative names
executeFunctionYesHandler called when the command is selected
await api.editor.addSlashCommand({
name: 'callout',
description: 'Insert a callout box',
icon: 'info',
aliases: ['note', 'tip'],
execute: () => {
api.editor.insertNode('callout', { type: 'info' }, 'Your note here');
}
});
MethodParametersReturnsPermissionDescription
addContextMenuItem(options){ id, name, icon, condition, execute }stringeditor:writeAdd a context menu item
addToolbarItem(options){ id, title, icon, group, handler, isActive, isDisabled }stringeditor:writeAdd a toolbar button
addKeyboardShortcut(options){ key, handler, description }stringeditor:writeAdd a keyboard shortcut
addDropHandler(options){ accept, handler }stringeditor:writeHandle drag-and-drop events
api.editor.addContextMenuItem({
id: 'myPlugin.format', name: 'Format', icon: 'format',
condition: () => true, execute: () => { /* ... */ }
});
api.editor.addToolbarItem({
id: 'myPlugin.bold', title: 'Bold', icon: 'bold',
group: 'formatting', handler: () => { /* ... */ }
});
api.editor.addKeyboardShortcut({
key: 'Mod-Shift-H', description: 'Highlight', handler: () => { /* ... */ }
});
api.editor.addDropHandler({
accept: ['image/png', 'image/jpeg'], handler: (files) => { /* ... */ }
});
EventDataDescription
extension_added{ name, extensionId, type }Extension registered
extension_removed{ extensionId }Extension removed
slash_command_added{ name, commandId }Slash command registered
toolbar_item_added{ id, itemId }Toolbar item added
context_menu_item_added{ id, itemId }Context menu item added

Create panels, show notifications, display dialogs, register status bar items, create webview panels, and manage output channels.

Required permissions: ui:create, ui:notifications, ui:dialogs, ui:menus, ui:toolbars depending on the method.

MethodParametersReturnsPermissionDescription
showInformationMessage(message, ...items)message: stringPromise<void>ui:notificationsShow an info message
showWarningMessage(message, ...items)message: stringPromise<void>ui:notificationsShow a warning message
showErrorMessage(message, ...items)message: stringPromise<void>ui:notificationsShow an error message
showNotification(message, type, actions)message: string, type?: string, actions?: arrayPromise<string|undefined>ui:notificationsShow a notification with optional action buttons
api.ui.showInformationMessage('Operation complete');
api.ui.showErrorMessage('Connection failed');
const action = await api.ui.showNotification('Unsaved changes', 'warning', [
{ id: 'save', label: 'Save' }, { id: 'discard', label: 'Discard' }
]);
MethodParametersReturnsPermissionDescription
showInputBox(options){ title, prompt, placeholder, value, validateInput }Promise<string|null>ui:dialogsShow a text input dialog
showQuickPick(items, options)items: array, options?: objectPromise<item|undefined>ui:dialogsShow a selection list
showConfirm(options){ title, message, confirmText, cancelText }Promise<boolean>ui:dialogsShow a confirmation dialog
showDialog(options){ title, message, type, buttons, detail }Promise<{ buttonId }>ui:dialogsShow a modal dialog with custom buttons
showOpenDialog(options){ canSelectMany, canSelectFolders, filters, title }Promise<string[]|undefined>ui:dialogsShow a file open dialog
showSaveDialog(options){ filters, defaultUri, title }Promise<string|undefined>ui:dialogsShow a file save dialog
const name = await api.ui.showInputBox({ title: 'Name', prompt: 'Project name?' });
const choice = await api.ui.showQuickPick(
[{ label: 'Option A' }, { label: 'Option B' }],
{ title: 'Pick one' }
);
const confirmed = await api.ui.showConfirm({ title: 'Delete?', message: 'Are you sure?' });
MethodParametersReturnsPermissionDescription
addPanel(options){ id, title, position, icon, component, props }Panelui:createAdd a UI panel
registerPanel(options){ id, title, location, icon, initialState }Disposableui:createRegister a panel (SDK alias)
removePanel(id)id: stringbooleanRemove a panel
updatePanel(id, props)id: string, props: objectPanelUpdate panel properties

Panel positions: 'sidebar-left', 'sidebar-right', 'bottom', 'modal'.

api.ui.addPanel({
id: 'myPlugin.explorer',
title: 'My Explorer',
position: 'sidebar-left',
icon: 'folder',
props: { rootPath: '/workspace' }
});
MethodParametersReturnsPermissionDescription
registerStatusBarItem(definition)See belowStatusBarItemui:createAdd a status bar item
ParameterTypeRequiredDescription
idstringYesUnique identifier
textstringYesDisplay text
tooltipstringNoHover tooltip
commandstring|objectNoCommand to execute on click
alignmentnumberNo1 = left, 2 = right (default)
prioritynumberNoSort order (higher = closer to edge)
colorstringNoText color
backgroundColorstringNoBackground color

Returns a StatusBarItem with show(), hide(), and dispose() methods.

const item = api.ui.registerStatusBarItem({
id: 'myPlugin.status',
text: 'Ready',
tooltip: 'Plugin status',
alignment: 2,
priority: 100
});
// Update text later
item.text = 'Processing...';
// Hide when not needed
item.hide();
MethodParametersReturnsPermissionDescription
registerWebviewPanel(panel){ id, title, html }WebviewPanelui:createCreate a webview panel with custom HTML

The returned WebviewPanel has:

Property/MethodTypeDescription
idstringPanel ID
titlestringPanel title
htmlstringHTML content
postMessage(message)FunctionSend a message to the webview
onDidReceiveMessage(handler)FunctionListen for messages from the webview. Returns Disposable
dispose()FunctionClose and clean up the webview
const panel = api.ui.registerWebviewPanel({
id: 'myPlugin.preview', title: 'Preview',
html: '<html><body><h1>Hello</h1></body></html>'
});
panel.onDidReceiveMessage((msg) => console.log(msg));
panel.postMessage({ type: 'update', data: 'new content' });
MethodParametersReturnsPermissionDescription
registerTreeDataProvider(viewId, provider, options)viewId: string, provider: TreeDataProvider, options?: { title }Disposableui:createRegister a tree view

The provider must implement:

{
getTreeItem(element: any): TreeItem;
getChildren(element?: any): any[];
onDidChangeTreeData?: Event;
}
api.ui.registerTreeDataProvider('myPlugin.files', {
getTreeItem: (el) => ({ label: el.name, collapsibleState: el.isDir ? 1 : 0 }),
getChildren: (el) => el ? getChildItems(el) : getRootItems()
}, { title: 'My Files' });
MethodParametersReturnsPermissionDescription
registerMenu(menu){ id, label, group, order, when, command, icon }Disposableui:menusRegister a menu item
registerToolbar(toolbar){ id, title, location, group, items, when }Disposableui:toolbarsRegister a toolbar
const menuDisposable = api.ui.registerMenu({
id: 'myPlugin.action',
label: 'My Action',
group: 'navigation',
command: 'myPlugin.doAction',
icon: 'zap'
});
MethodParametersReturnsPermissionDescription
createOutputChannel(name)name: stringOutputChannelui:createCreate an output channel for logging

The returned OutputChannel has:

MethodDescription
append(value)Append text without a newline
appendLine(value)Append text with a newline
replace(value)Replace all content
clear()Clear the channel
show(preserveFocus?)Show the channel
hide()Hide the channel
dispose()Dispose the channel
const output = api.ui.createOutputChannel('My Plugin');
output.appendLine('Plugin started');
output.show();
MethodParametersReturnsPermissionDescription
createTerminal(options){ name, shellPath, shellArgs, cwd, env }Terminalterminal:createCreate a terminal instance

The returned Terminal has:

MethodDescription
sendText(text, addNewLine?)Send text to the terminal
show(preserveFocus?)Show the terminal
hide()Hide the terminal
dispose()Close and dispose the terminal
const terminal = api.ui.createTerminal({
name: 'Build',
cwd: '/workspace'
});
terminal.show();
terminal.sendText('npm run build');
MethodParametersReturnsPermissionDescription
withProgress(options, task)options: { location, title, cancellable }, task: FunctionPromise<any>ui:createShow progress while running a task
await api.ui.withProgress({ title: 'Building...', cancellable: true }, async (progress) => {
progress.report({ message: 'Compiling...', increment: 50 });
await compile();
progress.report({ message: 'Done', increment: 100 });
});

Register, execute, and query commands.

Required permissions: commands:register, commands:execute, commands:list.

MethodParametersReturnsPermissionDescription
register(command)command: object | object[]Disposablecommands:registerRegister one or more commands
register(id, options)id: string, options: objectDisposablecommands:registerRegister a command by ID
execute(commandId, ...args)commandId: stringPromise<any>commands:executeExecute a registered command
getAll()Array<CommandInfo>commands:listList all registered commands
getByCategory(category)category: stringArray<CommandInfo>commands:listList commands in a category
exists(commandId)commandId: stringbooleanCheck if a command exists
registerWithPalette(command)command: objectDisposablecommands:registerRegister and show in command palette
registerTextEditorCommand(command)command: objectDisposablecommands:registerRegister a command requiring an active editor
unregister(commandIds)commandIds: string | string[]ArrayUnregister commands
FieldTypeRequiredDescription
idstringYesUnique command identifier
titlestringNoDisplay title
namestringNoAlternative to title
handlerFunctionYesFunction to execute (also accepts execute or callback)
descriptionstringNoCommand description
categorystringNoCategory for grouping
iconstringNoIcon identifier
shortcutstringNoKeyboard shortcut
showInPalettebooleanNoShow in command palette
requiresEditorbooleanNoRequires active editor
const disposable = api.commands.register({
id: 'myPlugin.greet', title: 'Greet', category: 'My Plugin',
handler: () => api.ui.showInformationMessage('Hello!')
});
await api.commands.execute('myPlugin.greet');
disposable.dispose(); // Unregister

Read and write files within the plugin’s scoped directory. All paths are relative to the plugin directory and validated against the workspace boundary.

Required permissions: filesystem:read, filesystem:write.

MethodParametersReturnsPermissionDescription
readFile(relativePath)relativePath: stringPromise<Buffer>filesystem:readRead file contents
writeFile(relativePath, content)relativePath: string, content: stringPromise<void>filesystem:writeWrite content to a file
exists(relativePath)relativePath: stringPromise<boolean>filesystem:readCheck if a path exists
readdir(relativePath)relativePath: stringPromise<Array>filesystem:readList directory contents
mkdir(relativePath)relativePath: stringPromise<void>filesystem:writeCreate a directory
ensureDir(relativePath)relativePath: stringPromise<void>filesystem:writeCreate directory if it does not exist
delete(relativePath)relativePath: stringPromise<void>filesystem:writeDelete a file or directory
rename(oldPath, newPath)oldPath: string, newPath: stringPromise<void>filesystem:writeRename or move a file
copy(source, destination)source: string, dest: stringPromise<void>filesystem:writeCopy a file
stat(path)path: stringPromise<FileStat>filesystem:readGet file metadata
openFileDialog(options){ accept, multiple, title }Promise<Array>filesystem:readShow a file picker dialog
const content = await api.fs.readFile('data/config.json');
await api.fs.writeFile('output/result.txt', 'Hello World');
const entries = await api.fs.readdir('data');

Security: Paths containing .. are rejected. All paths are scoped to the plugin’s directory within the workspace.


Make HTTP requests from your plugin.

Required permissions: network:http.

MethodParametersReturnsPermissionDescription
fetch(url, options)url: string, options?: RequestInitPromise<Response>network:httpMake an HTTP request
const resp = await api.network.fetch('https://api.example.com/data', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: 'test' })
});

Persistent key-value storage scoped to your plugin. Backed by a database when available, with localStorage fallback.

Required permissions: storage:read, storage:write.

MethodParametersReturnsPermissionDescription
get(key)key: stringPromise<any>storage:readGet a stored value
set(key, value)key: string, value: anyPromise<void>storage:writeStore a value
delete(key)key: stringPromise<void>storage:writeDelete a stored value
keys()Promise<string[]>storage:readList all stored keys
clear()Promise<void>storage:writeDelete all stored values
getDatabase(name)name: stringPromise<Database>storage:readGet a named database instance
await api.storage.set('lastSync', Date.now());
const lastSync = await api.storage.get('lastSync');
const keys = await api.storage.keys();

Read and write system clipboard content.

Required permissions: clipboard:read, clipboard:write.

MethodParametersReturnsPermissionDescription
read()Promise<ClipboardItems>clipboard:readRead clipboard content
writeText(text)text: stringPromise<void>clipboard:writeWrite text to clipboard
await api.clipboard.writeText('Copied from plugin');
const content = await api.clipboard.read();

Access workspace folders, root path, and workspace-level configuration.

Required permissions: workspace:read, workspace:write.

Property/MethodTypePermissionDescription
rootPathstringworkspace:readWorkspace root directory path
workspaceFoldersArrayworkspace:readList of workspace folders
getConfiguration(section)Functionworkspace:readGet workspace configuration for a section
const root = api.workspace.rootPath;
const folders = api.workspace.workspaceFolders;
const config = api.workspace.getConfiguration('editor');

Read and write configuration values. Changes emit events that other plugins can listen to.

Required permissions: config:read, config:write.

MethodParametersReturnsPermissionDescription
get(key, defaultValue)key: string, defaultValue?: anyPromise<any>config:readGet a configuration value
set(key, value)key: string, value: anyPromise<void>config:writeSet a configuration value
update(key, value)key: string, value: anyPromise<void>config:writeUpdate a configuration value (alias for set)
has(key)key: stringPromise<boolean>config:readCheck if a key exists
inspect(key)key: stringPromise<object>config:readGet detailed config info including defaults and overrides
onDidChange(callback)callback: FunctionDisposableconfig:readListen for configuration changes
const fontSize = await api.config.get('editor.fontSize', 14);
await api.config.set('myPlugin.autoSave', true);
api.config.onDidChange((event) => {
console.log(`Config changed: ${event.key}`);
});

Register language feature providers: completions, hover, definitions, references, formatting, and more.

Required permissions: languages:register, languages:read.

MethodParametersReturnsPermissionDescription
registerCompletionProvider(selector, provider, ...triggers)selector: string, provider: object, ...triggers: string[]Disposablelanguages:registerRegister autocomplete provider
registerHoverProvider(selector, provider)selector: string, provider: objectDisposablelanguages:registerRegister hover information
registerDefinitionProvider(selector, provider)selector: string, provider: objectDisposablelanguages:registerRegister go-to-definition
registerReferenceProvider(selector, provider)selector: string, provider: objectDisposablelanguages:registerRegister find references
registerDocumentSymbolProvider(selector, provider)selector: string, provider: objectDisposablelanguages:registerRegister document symbol outline
registerCodeActionProvider(selector, provider)selector: string, provider: objectDisposablelanguages:registerRegister code actions (quick fixes)
registerCodeLensProvider(selector, provider)selector: string, provider: objectDisposablelanguages:registerRegister code lens annotations
registerFormattingProvider(selector, provider)selector: string, provider: objectDisposablelanguages:registerRegister document formatter
registerSignatureHelpProvider(selector, provider)selector: string, provider: objectDisposablelanguages:registerRegister signature help
registerDiagnosticProvider(selector, provider)selector: string, provider: objectDisposablelanguages:registerRegister diagnostics/linting
registerLanguage(definition)definition: objectDisposablelanguages:registerRegister a new language
getLanguages()Arraylanguages:readList registered languages
// Completion provider
api.languages.registerCompletionProvider('markdown', {
provideCompletionItems(document, position) {
return [{ label: 'mySnippet', kind: 1, insertText: 'Inserted text' }];
}
}, '@');
// Hover provider
api.languages.registerHoverProvider('markdown', {
provideHover(document, position) {
return { contents: ['**Hover info**', 'Details here'] };
}
});

Register and manage color themes.

Required permissions: themes:register, themes:read, themes:set.

MethodParametersReturnsPermissionDescription
registerTheme(theme)See belowDisposablethemes:registerRegister a color theme
getActiveTheme()Themethemes:readGet the currently active theme
getThemes()Array<Theme>themes:readList all available themes
setActiveTheme(themeId)themeId: stringvoidthemes:setSwitch to a theme
onDidChangeTheme(callback)callback: FunctionDisposablethemes:readListen for theme changes
ParameterTypeRequiredDescription
idstringYesUnique theme identifier
labelstringYesDisplay name
uiThemestringYesBase theme: 'vs', 'vs-dark', 'hc-black', 'hc-light'
pathstringNoPath to theme JSON file
colorsobjectNoColor customizations (key-value pairs)
tokenColorsarrayNoToken color rules for syntax highlighting
api.themes.registerTheme({
id: 'myPlugin.oceanDark', label: 'Ocean Dark', uiTheme: 'vs-dark',
colors: { 'editor.background': '#1a2b3c', 'editor.foreground': '#c0d0e0' },
tokenColors: [{ scope: 'keyword', settings: { foreground: '#ff7b72' } }]
});

Create and manage terminal instances.

Required permissions: terminal:create, terminal:write, terminal:read.

MethodParametersReturnsPermissionDescription
createTerminal(options){ name, shellPath, shellArgs, cwd, env }Terminalterminal:createCreate a new terminal
getActiveTerminal()Terminal|nullterminal:readGet the active terminal
EventDataDescription
terminal-openedTerminalTerminal was created
terminal-closed{ terminalId }Terminal was closed
active-terminal-changedTerminalActive terminal changed
const term = api.terminal.createTerminal({
name: 'Build Runner',
cwd: api.workspace.rootPath
});
term.sendText('npm run build');
term.show();

Show, update, and hide notifications.

MethodParametersReturnsDescription
show(options){ type, message, title, duration, persistent, progress }string (notification ID)Show a notification
update(id, updates)id: string, updates: objectNotificationUpdate an existing notification
hide(id)id: stringbooleanHide a notification

Notification types: 'info', 'success', 'warning', 'error', 'loading', 'progress'.

const id = api.notifications.show({ type: 'loading', message: 'Building...', persistent: true });
api.notifications.update(id, { message: 'Done!', type: 'success' });
setTimeout(() => api.notifications.hide(id), 3000);

Register and manage task providers for build, test, and other project tasks.

Required permissions: tasks:register, tasks:execute.

Task providers define discoverable tasks that users can run from the command palette or task runner.


Start debug sessions, manage breakpoints, and register debug adapters.

Required permissions: debug:session, debug:register.

MethodParametersReturnsPermissionDescription
startDebugging(config)config: objectPromise<boolean>debug:sessionStart a debug session
stopDebugging()Promise<void>debug:sessionStop the current session
registerDebugAdapterProvider(type, provider)type: string, provider: objectDisposabledebug:registerRegister a debug adapter
registerDebugConfigurationProvider(type, provider)type: string, provider: objectDisposabledebug:registerRegister debug configurations
addBreakpoints(breakpoints)breakpoints: arrayvoiddebug:sessionAdd breakpoints
removeBreakpoints(breakpoints)breakpoints: arrayvoiddebug:sessionRemove breakpoints

The LokusPluginAPI and all sub-APIs extend EventEmitter. Subscribe to events with on(), once(), and off().

api.on('plugin_cleanup', ({ pluginId }) => { /* ... */ });
api.editor.once('extension_added', (data) => { /* ... */ });
APIEventDescription
editorextension_addedExtension registered
editorextension_removedExtension unregistered
editorslash_command_addedSlash command registered
editortoolbar_item_addedToolbar item added
commandscommand_registeredCommand registered
commandscommand_unregisteredCommand unregistered
commandscommand_errorCommand execution failed
uipanel_addedPanel created
uipanel_removedPanel removed
uiwebview-registeredWebview panel created
uiwebview-disposedWebview panel closed
notificationsnotification_shownNotification displayed
notificationsnotification_hiddenNotification dismissed
config(key change)Configuration value changed
themes(theme change)Active theme changed
terminalterminal-openedTerminal created
terminalterminal-closedTerminal disposed

Many API methods return a Disposable object. Call dispose() to clean up the registration:

const disposable = api.commands.register({
id: 'myPlugin.cmd',
handler: () => {}
});
// Later, unregister:
disposable.dispose();

Resources registered through the API are automatically disposed when your plugin deactivates. For manual cleanup, call dispose() explicitly.


Permissions follow the category:action format. Each API section above lists the required permission per method. Here is the summary by category:

CategoryPermissions
editoreditor:read, editor:write
uiui:create, ui:notifications, ui:dialogs, ui:menus, ui:toolbars
commandscommands:register, commands:execute, commands:list
filesystemfilesystem:read, filesystem:write
workspaceworkspace:read, workspace:write
storagestorage:read, storage:write
networknetwork:http
clipboardclipboard:read, clipboard:write
terminalterminal:create, terminal:read, terminal:write
languageslanguages:register, languages:read
configconfig:read, config:write
themesthemes:register, themes:read, themes:set
debugdebug:session, debug:register
eventsevents:listen, events:emit

Calling any method without its required permission throws PermissionDeniedError with the plugin ID, required permission, and API method name.