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
| Tier | Name | Description | Execution Model |
|---|---|---|---|
| 1 | InProcess | UI-only (themes, keymaps, color schemes) | Loaded in main process |
| 2 | PluginHost | Editor access, filesystem reads, UI elements | Shared plugin host process |
| 3 | IsolatedProcess | Network, filesystem writes, process spawning, terminal, webviews | Own 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: truefilesystem.write: trueprocess.spawn: [...](non-empty array)terminal: trueui.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.decorationsfilesystem.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
| Capability | Type | Description |
|---|---|---|
editor.read | boolean | Read buffer text, selections, language ID, line count |
editor.write | boolean | Submit edits (routed through the Changes Queue) |
editor.decorations | boolean | Underlines, highlights, gutter icons |
filesystem.read | string[] | Read files matching declared glob patterns |
filesystem.write | boolean | Write and delete files and directories |
network | boolean | HTTP requests to external services |
process.spawn | string[] | Spawn allowlisted external binaries |
terminal | boolean | Interactive terminal access |
ui.panel | boolean | Create side panels with structured content |
ui.statusbar | boolean | Add and update status bar items |
ui.gutter | boolean | Gutter icons next to line numbers |
ui.commandPalette | boolean | Register commands in the command palette |
ui.contextMenu | boolean | Add items to right-click context menus |
ui.notifications | boolean | Toast notifications |
ui.webview | boolean | Embedded 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:
| Platform | Mechanism |
|---|---|
| macOS | sandbox-exec profiles |
| Linux | seccomp-bpf filters |
| Windows | Job 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)