Skip to content

Plugin API Reference

The PluginContext object is passed to your plugin’s entry function. It provides access to KinBot services.

interface PluginContext {
config: Record<string, any>
log: PluginLogger
storage: PluginStorageAPI
http: PluginHTTPClient
manifest: PluginManifest
}

An object containing resolved configuration values. Secret values are decrypted automatically. Defaults from plugin.json are applied for unset fields.

const { apiKey, units = 'metric' } = ctx.config

A scoped logger tagged with your plugin name. Supports structured logging:

ctx.log.info('Processing request')
ctx.log.error({ err, userId }, 'Failed to fetch data')
ctx.log.debug({ response }, 'API response received')
ctx.log.warn('Deprecated feature used')
interface PluginLogger {
debug(msg: string): void
debug(obj: Record<string, any>, msg: string): void
info(msg: string): void
info(obj: Record<string, any>, msg: string): void
warn(msg: string): void
warn(obj: Record<string, any>, msg: string): void
error(msg: string): void
error(obj: Record<string, any>, msg: string): void
}

Persistent key-value store scoped to your plugin. Values are JSON-serialized. Backed by SQLite.

interface PluginStorage {
get<T = unknown>(key: string): Promise<T | null>
set<T = unknown>(key: string, value: T): Promise<void>
delete(key: string): Promise<void>
list(prefix?: string): Promise<string[]>
clear(): Promise<void>
}
// Examples
await ctx.storage.set('lastSync', Date.now())
const lastSync = await ctx.storage.get<number>('lastSync')
await ctx.storage.delete('lastSync')
const keys = await ctx.storage.list('cache:')
await ctx.storage.clear()

A sandboxed HTTP client. Only URLs matching declared permissions (http:*.example.com) are allowed. Attempts to access undeclared hosts throw a PermissionDeniedError.

interface PluginHTTPClient {
fetch(url: string, init?: RequestInit): Promise<Response>
}
// Must declare "http:api.example.com" in permissions
const res = await ctx.http.fetch('https://api.example.com/data', {
headers: { 'Authorization': `Bearer ${ctx.config.apiKey}` },
})
const data = await res.json()

The parsed plugin.json manifest object, read-only.

interface PluginExports {
tools?: Record<string, ToolRegistration>
providers?: Record<string, PluginProviderRegistration>
channels?: Record<string, ChannelAdapter>
hooks?: Partial<Record<HookName, HookHandler>>
activate?(): Promise<void>
deactivate?(): Promise<void>
}
interface ToolRegistration {
availability: Array<'main' | 'sub-kin'>
defaultDisabled?: boolean
create: (execCtx: ToolExecutionContext) => Tool
}

Tools use the Vercel AI SDK tool() function with Zod schemas for parameters.

type HookName =
| 'beforeChat'
| 'afterChat'
| 'beforeToolCall'
| 'afterToolCall'
| 'beforeCompacting'
| 'afterCompacting'
| 'onTaskSpawn'
| 'onCronTrigger'
interface PluginManifest {
name: string
version: string
description: string
author?: string
homepage?: string
license?: string
kinbot?: string
main: string
icon?: string
permissions?: string[]
config?: Record<string, PluginConfigField>
}
interface PluginConfigField {
type: 'string' | 'number' | 'boolean' | 'select' | 'text' | 'password'
label: string
description?: string
required?: boolean
default?: any
secret?: boolean
options?: string[] // select only
min?: number // number only
max?: number // number only
step?: number // number only
placeholder?: string // string, text
pattern?: string // string only
rows?: number // text only
}

Plugin management is also available via the REST API:

Plugin management:

MethodEndpointDescription
GET/api/pluginsList all installed plugins with status
POST/api/plugins/:name/enableEnable a plugin
POST/api/plugins/:name/disableDisable a plugin
GET/api/plugins/:name/configGet plugin config (secrets masked)
PUT/api/plugins/:name/configUpdate plugin config
POST/api/plugins/installInstall from git or npm ({ source, url/package })
DELETE/api/plugins/:nameUninstall a plugin
POST/api/plugins/:name/updateUpdate an installed plugin
POST/api/plugins/reloadReload all plugins
GET/api/plugins/updatesCheck for available plugin updates
POST/api/plugins/:name/updateUpdate a plugin to latest version
POST/api/plugins/:name/health/resetReset plugin health stats

Built-in store:

MethodEndpointDescription
GET/api/plugins/storeList available store plugins
GET/api/plugins/store/:nameGet store plugin details + README
POST/api/plugins/store/:name/installInstall a store plugin

Community registry:

MethodEndpointDescription
GET/api/plugins/registryBrowse the community registry (add ?refresh=true to force)
GET/api/plugins/registry/searchSearch registry (?q=...&tag=...)
GET/api/plugins/registry/readmeFetch a plugin’s README (?repo=<github-url>)
GET/api/plugins/versionGet KinBot version for compatibility checks

KinBot tracks error statistics for each plugin. If a plugin’s hooks or tools throw errors repeatedly, it is automatically disabled to protect system stability.

Health stats are included in every plugin summary (GET /api/plugins):

interface PluginHealthStats {
totalErrors: number // Total errors since last reset
consecutiveErrors: number // Errors in a row (resets on success)
lastError?: string // Last error message with source
lastErrorAt?: string // ISO timestamp
autoDisabled: boolean // Whether circuit breaker triggered
autoDisabledAt?: string // When it was auto-disabled
}

Circuit breaker: After 10 consecutive hook errors, the plugin is automatically disabled and a plugin:autoDisabled SSE event is broadcast. To re-enable, use the UI toggle or POST /api/plugins/:name/enable (this resets health stats).

Reset health stats without disabling/re-enabling:

Terminal window
curl -X POST http://localhost:3000/api/plugins/my-plugin/health/reset
Terminal window
curl -X POST http://localhost:3000/api/plugins/install \
-H 'Content-Type: application/json' \
-d '{"source": "git", "url": "https://github.com/user/kinbot-plugin-weather"}'
Terminal window
curl -X POST http://localhost:3000/api/plugins/install \
-H 'Content-Type: application/json' \
-d '{"source": "npm", "package": "kinbot-plugin-weather"}'
Terminal window
curl -X POST http://localhost:3000/api/plugins/store/weather/install