Plugin System
Plugins are the execution units of KB Labs. Every workflow step calls a plugin handler. Plugins are isolated, versioned, and independently deployable.
Architecture
Workflow step
↓
Plugin manifest (declares handlers, permissions)
↓
Execution backend (in-process / subprocess / worker-pool)
↓
Handler function (your TypeScript code)
The execution backend is pluggable. In development you typically run in-process. In production you can run handlers in isolated subprocesses or worker threads.
Plugin structure
my-plugin/
├── manifest.json # Plugin metadata and handler registry
├── src/
│ ├── index.ts # Handler exports
│ └── handlers/
│ └── my-handler.ts
├── package.json
└── tsconfig.json
manifest.json
{
"name": "@my-org/my-plugin",
"version": "1.0.0",
"handlers": {
"my-handler": {
"entry": "./dist/handlers/my-handler.js",
"description": "Does something useful"
}
},
"permissions": {
"network": false,
"fs": ["read"]
}
}
The permissions block is used when running in sandboxed mode. It's ignored in in-process mode.
Writing a handler
import type { HandlerContext } from '@kb-labs/sdk';
type Input = {
url: string;
};
type Output = {
status: number;
body: string;
};
export async function handler(input: Input, ctx: HandlerContext): Promise<Output> {
const res = await fetch(input.url);
const body = await res.text();
ctx.logger.info(`Fetched ${input.url} → ${res.status}`);
return { status: res.status, body };
}
HandlerContext API
| Property | Type | Description |
|----------|------|-------------|
| logger | Logger | Structured logger scoped to the step |
| cache | ICache \| null | Platform cache (in-memory or Redis) |
| state | IStateClient | State Broker client |
| runId | string | Current workflow run ID |
| stepId | string | Current step ID |
Build and register
# Build the plugin
pnpm --filter my-plugin build
# Register with KB Labs CLI
kb plugins register ./my-plugin
# Clear discovery cache (required after every build!)
kb plugins clear-cache
Always run kb plugins clear-cache after building a plugin. The CLI caches plugin manifests for performance. Stale cache = stale commands.
Execution modes
| Mode | Use case | Isolation |
|------|----------|-----------|
| in-process | Development, low-latency | None |
| subprocess | Production, untrusted code | Process boundary |
| worker-pool | High-throughput, CPU-bound | Thread boundary |
Configure in kb.config.json:
{
"execution": {
"mode": "subprocess"
}
}