Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Capabilities & Tiers

Every V2 plugin declares its capabilities in the manifest. The declared capabilities determine the plugin’s execution tier, which controls isolation and security boundaries.

Execution Tiers

TierNameDescriptionExecution Model
1InProcessUI-only (themes, keymaps, color schemes)Loaded in main process
2PluginHostEditor access, filesystem reads, UI elementsShared plugin host process
3IsolatedProcessNetwork, filesystem writes, process spawning, terminal, webviewsOwn sandboxed process

Tiers are derived automatically from declared capabilities. You do not choose a tier directly.

Tier Derivation Rules

Tier 3 Triggers

Any of these capabilities forces the plugin into its own sandboxed process:

  • network: true
  • filesystem.write: true
  • process.spawn: [...] (non-empty array)
  • terminal: true
  • ui.webview: true

Tier 2 Triggers

These capabilities place the plugin in the shared plugin host (unless a Tier 3 trigger is also present):

  • editor.read, editor.write, editor.decorations
  • filesystem.read: [...] (non-empty array)
  • Any ui.* capability (panel, statusbar, gutter, commandPalette, contextMenu, notifications)

Tier 1

No code capabilities declared. The plugin is purely declarative data: theme JSON, keymap JSON, or other static contributions. Loaded directly in the main process with no isolation overhead.

All Capabilities

CapabilityTypeDescription
editor.readbooleanRead buffer text, selections, language ID, line count
editor.writebooleanSubmit edits (routed through the Changes Queue)
editor.decorationsbooleanUnderlines, highlights, gutter icons
filesystem.readstring[]Read files matching declared glob patterns
filesystem.writebooleanWrite and delete files and directories
networkbooleanHTTP requests to external services
process.spawnstring[]Spawn allowlisted external binaries
terminalbooleanInteractive terminal access
ui.panelbooleanCreate side panels with structured content
ui.statusbarbooleanAdd and update status bar items
ui.gutterbooleanGutter icons next to line numbers
ui.commandPalettebooleanRegister commands in the command palette
ui.contextMenubooleanAdd items to right-click context menus
ui.notificationsbooleanToast notifications
ui.webviewbooleanEmbedded webviews (Tier 3 only)

Declaring Capabilities

Capabilities are declared in plugin.json:

{
  "id": "com.example.my-formatter",
  "name": "My Formatter",
  "version": "1.0.0",
  "capabilities": {
    "editor": {
      "read": true,
      "write": true,
      "decorations": true
    },
    "filesystem": {
      "read": ["**/*.config.json"]
    },
    "ui": {
      "statusbar": true,
      "commandPalette": true,
      "notifications": true
    }
  }
}

This plugin would be assigned Tier 2: it uses editor and UI capabilities but does not declare network, filesystem write, process spawn, terminal, or webview.

Enforcement Layers

Capabilities are enforced at three independent layers. All three must agree for an API call to succeed.

1. Compile-time (Perry)

Only API functions matching declared capabilities are linked into the plugin binary. Attempting to import an undeclared API causes a compile error. This is the earliest and strictest check.

2. Runtime (OS Sandbox)

OS-level restrictions are applied before the plugin binary loads:

PlatformMechanism
macOSsandbox-exec profiles
Linuxseccomp-bpf filters
WindowsJob Objects + AppContainer

The sandbox profile is generated from the declared capabilities. A Tier 3 plugin with network: true but no filesystem.write will have network access allowed but filesystem writes blocked at the OS level.

3. Host API (Null Pointers)

In the C ABI HoneHostAPI struct, function pointers for undeclared capabilities are set to null. If a plugin somehow bypasses the first two layers and calls an undeclared function pointer, it dereferences null and crashes. This is the final safety net.

Principle of Least Privilege

Declare only the capabilities your plugin actually needs. Fewer capabilities means:

  • Lower tier (less isolation overhead, better performance)
  • Smaller attack surface
  • Easier review for marketplace approval
  • More user trust (users see capability declarations before installing)