Skip to content
VibeKit is in alpha. The packages are unstable and not ready to build on — APIs will break without notice.

Create a VibeKit plugin

A VibeKit plugin is a workspace package that returns a ToolPlugin: a name, a tool array, and optionally a service or trusted Explorer view schemas. The host puts the plugin service at ctx.services[plugin.name] and sends every call through the same tool contract as VibeKit’s built-in capabilities.

This minimal plugin makes the shape concrete. In a real package, name the tool for the capability it performs and give its parameters and output meaningful schemas.

import { defineTool, type ToolPlugin } from '@initlabs/vibekit'
import { z } from 'zod'
const echoTool = defineTool({
name: 'example_echo',
description: 'Echo a value. Use only when testing the example plugin.',
parameters: z.object({
value: z.string().describe('The value to echo.'),
}),
output: z.object({ value: z.string() }),
view: 'json',
async handler(_ctx, { value }) {
return { value }
},
})
export function examplePlugin(): ToolPlugin {
return {
name: 'example',
description: 'A minimal example capability.',
tools: [echoTool],
}
}

Use defineTool() for every tool. Its output schema describes the wire result after VibeKit has made it JSON-safe: bytes are base64 and large integers may be decimal strings. Throw ToolError from a handler for a user-safe failure; never return an { error } result.

Add a service when the capability needs state

Section titled “Add a service when the capability needs state”

Remote clients, credentials, and caches belong behind a service built by the plugin factory. Do not create them at module import time. A typed accessor should read the service from ctx.services and throw ToolError('PLUGIN_NOT_CONFIGURED', ...) when the plugin is absent.

Plugin packages declare @initlabs/vibekit, zod, and algosdk as peer dependencies. Keep the plugin’s own SDKs in regular dependencies. A factory is the configuration boundary: importing a plugin must not read environment variables, perform a network request, or mutate global state.

Set requiresSigner on a tool that spends user funds. Set mutatesState for a state change that does not spend funds. These flags tell the host when to ask for approval. In a compose deployment, actions return an unsigned group; an execute deployment requires a signer and is responsible for its approval boundary.

Use a coarse view such as json or table unless your result conforms to an Explorer semantic view that already exists. A new trusted semantic view is a protocol change, not a decorative plugin feature.

Instantiate the factory in a deployment’s plugins array. Do not spread a plugin’s tools into the base tool list. Test the factory, schemas, flags, missing-plugin error, and the service’s edge cases with fakes rather than live network calls.

The first-party plugins in packages/vibekit/src/plugins/pera, packages/vibekit/src/plugins/nfd, and packages/vibekit/src/plugins/alpha-arcade are the current implementation patterns.