Plugin SDK Overview
The plugin SDK is @vibecontrols/plugin-sdk. Plugins are NPM packages that export createPlugin: VibePluginFactory. There is no separate JSON manifest — everything is in code.
What you'll learn
- The factory pattern
- The
VibePluginshape - Lifecycle hooks
- Providers (registering capabilities for the agent and other plugins)
The factory
// src/index.ts (your plugin)
import type {
HostServices,
ProfileContext,
VibePlugin,
VibePluginFactory,
} from "@vibecontrols/plugin-sdk/contract";
import {createLifecycleHooks} from "@vibecontrols/plugin-sdk/lifecycle";
export const createPlugin: VibePluginFactory = (ctx: ProfileContext): VibePlugin => {
const plugin: VibePlugin = {
name: "my-plugin",
version: "0.1.0",
description: "What it does",
tags: ["backend", "provider"],
capabilities: {
storage: "rw", // "ro" | "rw" — read or read/write persistent storage
secrets: "read", // "read" — fetch secrets the user granted access to
subprocess: true, // spawn child processes
audit: true, // emit audit events
telemetry: true, // emit telemetry
gateway: false, // proxy outbound HTTP through the agent's gateway
},
// optional: lifecycle wiring on server start/stop
onServerStart: undefined,
onServerStop: undefined,
};
createLifecycleHooks({
name: "my-plugin",
onInit: async (hostServices: HostServices) => {
// Register providers, schedule background tasks, etc.
},
});
return plugin;
};
The agent calls createPlugin(ctx) once per profile when loading plugins.
VibePluginFactory + VibePlugin
Exactly what's exported by @vibecontrols/plugin-sdk/contract:
| Type | Purpose |
|---|---|
VibePluginFactory | (ctx: ProfileContext) => VibePlugin |
VibePlugin | Plugin metadata + capabilities + optional hooks |
ProfileContext | Per-profile context (config dir, profile name, etc.) |
HostServices | Services the agent exposes to plugins (logger, storage, subprocess, telemetry, providers registry) |
Capabilities
Each plugin declares what runtime features it needs:
storage: "ro"|"rw"|false— access to the plugin's TypedStore (per-namespace persistent store)subprocess: true|false— allowed to spawn child processestelemetry: true|false— allowed to emit telemetry
The agent enforces these at runtime — if a plugin tries to use a capability it didn't declare, the call is denied.
Providers
A plugin registers as a provider of a typed interface. The agent has registries for:
- Session providers (
vibe-plugin-session-tmux,vibe-plugin-session-wezterm,vibe-plugin-session-zellij) - Tunnel providers (
vibe-plugin-tunnel-cloudflare,vibe-plugin-tunnel-vibetunnels) - AI providers (within the AI plugin)
createLifecycleHooks({
name: "my-session-plugin",
onInit: async (hostServices) => {
const provider = new MySessionProvider(hostServices);
hostServices.providers.register("session", provider);
},
});
Storage
Plugins get a typed key-value store namespaced to the plugin name:
const STORAGE_NS = "my-plugin";
const KEY_STATE = "state";
const store = hostServices.storage.namespace(STORAGE_NS);
await store.set(KEY_STATE, {foo: "bar"});
const value = await store.get(KEY_STATE);
Persisted on disk in the agent's data directory.
Telemetry + logging
import {TelemetryEmitter} from "@vibecontrols/plugin-sdk/telemetry";
import {BoundLogger} from "@vibecontrols/plugin-sdk/log";
const telemetry = new TelemetryEmitter("my-plugin", "0.1.0");
const log = hostServices.logger.bind({plugin: "my-plugin"});
log.info("something happened");
telemetry.emit("my-event", {duration: 42});
Next steps
- Plugin tags & lifecycle
- Building a custom plugin
- Agent plugins — the built-in ones to learn from