Skip to main content

Plugin Tags & Lifecycle

Tags

Each plugin's tags: string[] field categorizes its role. From observed usage:

TagMeaning
backendWraps a backend / system service the agent talks to
frontendWraps a frontend dev tool
cliAdds CLI subcommands
providerProvides a capability (session, tunnel, AI) that the agent and other plugins can use
adapterAdapts an external API into a plugin capability
integrationConnects to a third-party service

A plugin can have multiple tags. The web app filters by tag in the Plugin Catalog UI.

Lifecycle

Use createLifecycleHooks from @vibecontrols/plugin-sdk/lifecycle:

import {createLifecycleHooks} from "@vibecontrols/plugin-sdk/lifecycle";

createLifecycleHooks({
name: "my-plugin",
onInit: async (hostServices) => {
// Called once when the agent loads your plugin.
// Register providers, restore persisted state, etc.
},
});

The plugin object itself can also declare:

const plugin: VibePlugin = {
// ...
onServerStart: async () => {
// Called when the agent's HTTP server is about to start listening
},
onServerStop: async () => {
// Called when the agent's HTTP server is shutting down
},
};

onInit runs once per profile at plugin load. onServerStart/onServerStop run on each restart of the agent's REST server.

Capability vs hook

Use a capability whenUse a hook when
You need to react on-demand (agent invokes you when X happens)You need to react at a specific lifecycle moment
You want pluggability (another plugin can call you)You want one-shot setup/teardown

Most plugins use both: onInit to register providers, and providers expose capabilities the agent calls.

Hot-reload + idempotency

Plugins may be reloaded when the agent picks up updated versions. Make your onInit and provider creation idempotent — e.g., don't bind a port twice; use guards like:

let provider: MyProvider | null = null;
createLifecycleHooks({
onInit: async (hostServices) => {
if (!provider) provider = new MyProvider(hostServices);
hostServices.providers.register("my-thing", provider);
},
});

Next steps