Documentation Index Fetch the complete documentation index at: https://mintlify.com/asundar43/simpleclaw/llms.txt
Use this file to discover all available pages before exploring further.
Plugin SDK
The SimpleClaw Plugin SDK enables you to extend the Gateway with custom channels, providers, and tools.
Plugin Types
SimpleClaw supports two plugin categories:
Channel Plugins - Messaging platform integrations (WhatsApp, Telegram, etc.)
Provider Plugins - LLM providers, memory systems, task runners
Installation
The Plugin SDK is included with SimpleClaw:
import {
// Channel plugin types
type ChannelPlugin ,
type ChannelConfigAdapter ,
type ChannelOutboundAdapter ,
// Provider plugin types
type SimpleClawPluginApi ,
type ProviderAuthContext ,
// Utilities
buildMediaPayload ,
normalizeWebhookPath ,
registerWebhookTarget ,
} from "simpleclaw/plugin-sdk" ;
Channel Plugin Structure
Basic Example
import type { ChannelPlugin } from "simpleclaw/plugin-sdk" ;
export const customChannel : ChannelPlugin = {
id: "custom" ,
meta: {
label: "Custom Chat" ,
detailLabel: "Custom messaging platform" ,
systemImage: "message.circle" ,
},
capabilities: {
outbound: true ,
groups: true ,
threads: false ,
media: [ "image" , "video" , "audio" ],
},
config: {
// Configuration adapter
resolveDefaultAccountId : ( config ) => "default" ,
resolveAccount : ( config , accountId ) => ({
accountId ,
enabled: true ,
}),
},
outbound: {
// Message sending
async send ( ctx , message ) {
// Send message to platform API
await fetch ( `https://api.example.com/send` , {
method: "POST" ,
body: JSON . stringify ({
to: message . to ,
text: message . text ,
}),
});
},
},
status: {
// Health checks
async buildAccountSnapshot ( ctx , accountId ) {
return {
accountId ,
configured: true ,
connected: true ,
running: true ,
};
},
},
};
Plugin SDK Exports
The SDK provides helpers for common plugin tasks:
import { buildMediaPayload , type MediaPayload } from "simpleclaw/plugin-sdk" ;
// Convert media to standard format
const media : MediaPayload = buildMediaPayload ({
url: "https://example.com/image.jpg" ,
mime: "image/jpeg" ,
size: 12345 ,
filename: "photo.jpg" ,
});
Webhook Registration
import {
registerWebhookTarget ,
normalizeWebhookPath ,
} from "simpleclaw/plugin-sdk" ;
// Register webhook endpoint
registerWebhookTarget ({
channelId: "custom" ,
accountId: "default" ,
path: normalizeWebhookPath ( "/webhooks/custom" ),
handler : async ( req , res ) => {
const body = await req . json ();
// Process webhook
res . json ({ ok: true });
},
});
Account Helpers
import { createAccountListHelpers } from "simpleclaw/plugin-sdk" ;
const helpers = createAccountListHelpers ({
configPrefix: "channels.custom" ,
accountSchema: AccountConfigSchema ,
});
// List all configured accounts
const accountIds = helpers . listAccountIds ( config );
Status Helpers
import {
buildBaseAccountStatusSnapshot ,
collectStatusIssuesFromLastError ,
} from "simpleclaw/plugin-sdk" ;
// Build standard account snapshot
const snapshot = buildBaseAccountStatusSnapshot ({
accountId: "default" ,
enabled: true ,
configured: true ,
connected: state . connected ,
lastError: state . error ?. message ,
});
Configuration Schema
Define config schema with Zod:
import { z } from "zod" ;
import { buildChannelConfigSchema } from "simpleclaw/plugin-sdk" ;
const AccountConfigSchema = z . object ({
apiKey: z . string (),
webhookUrl: z . string (). optional (),
});
const CustomConfigSchema = z . object ({
enabled: z . boolean (). default ( false ),
accounts: z . record ( AccountConfigSchema ),
});
export const configSchema = buildChannelConfigSchema ({
schema: CustomConfigSchema . shape ,
uiHints: {
"accounts.*.apiKey" : {
label: "API Key" ,
sensitive: true ,
help: "Get this from Custom Chat dashboard" ,
},
},
});
Outbound Message Delivery
import type { ChannelOutboundAdapter } from "simpleclaw/plugin-sdk" ;
export const outbound : ChannelOutboundAdapter = {
async send ( ctx , message ) {
const { to , text , media } = message ;
const account = ctx . account ;
// Send text message
if ( text ) {
await api . sendText ({
apiKey: account . apiKey ,
recipient: to ,
message: text ,
});
}
// Send media attachments
if ( media ?. length ) {
for ( const item of media ) {
await api . sendMedia ({
apiKey: account . apiKey ,
recipient: to ,
url: item . url ,
caption: item . caption ,
});
}
}
},
async sendReaction ( ctx , params ) {
await api . react ({
apiKey: ctx . account . apiKey ,
messageId: params . messageId ,
emoji: params . emoji ,
});
},
};
Security Adapter
Implement allowlist and DM policy:
import type { ChannelSecurityAdapter } from "simpleclaw/plugin-sdk" ;
import { isNormalizedSenderAllowed } from "simpleclaw/plugin-sdk" ;
export const security : ChannelSecurityAdapter = {
resolveSenderAllowed : ( ctx , sender ) => {
const allowFrom = ctx . account . allowFrom || [];
return isNormalizedSenderAllowed ({
senderId: sender . id ,
allowFrom ,
});
},
resolveDmPolicy : ( ctx ) => {
return ctx . account . dmPolicy || "pairing" ;
},
};
Gateway Adapter
Handle incoming messages:
import type { ChannelGatewayAdapter } from "simpleclaw/plugin-sdk" ;
export const gateway : ChannelGatewayAdapter = {
async start ( ctx ) {
const account = ctx . account ;
// Connect to platform API
const client = await connect ( account . apiKey );
// Listen for incoming messages
client . on ( "message" , async ( msg ) => {
await ctx . handleInbound ({
from: msg . sender . id ,
text: msg . text ,
timestamp: msg . timestamp ,
});
});
},
async stop ( ctx ) {
// Cleanup
await client ?. disconnect ();
},
};
Plugin Packaging
Create a plugin package:
{
"name" : "@simpleclaw/channel-custom" ,
"version" : "1.0.0" ,
"main" : "dist/index.js" ,
"simpleclaw" : {
"extensions" : [
{
"type" : "channel" ,
"id" : "custom" ,
"entry" : "./dist/index.js"
}
]
},
"dependencies" : {
"simpleclaw" : "^2026.3.0"
}
}
Provider Plugin Example
import type {
SimpleClawPluginService ,
SimpleClawPluginServiceContext ,
} from "simpleclaw/plugin-sdk" ;
export const customProvider : SimpleClawPluginService = {
id: "custom-llm" ,
async init ( ctx : SimpleClawPluginServiceContext ) {
// Initialize provider
},
async auth ( ctx ) {
// OAuth flow or API key validation
return {
success: true ,
profile: {
id: "user-123" ,
name: "User Name" ,
},
};
},
async invoke ( ctx , request ) {
// Handle LLM request
const response = await fetch ( "https://api.example.com/chat" , {
method: "POST" ,
body: JSON . stringify ( request ),
});
return response . json ();
},
};
Testing Plugins
import { describe , test , expect } from "vitest" ;
import { customChannel } from "./index.js" ;
describe ( "custom channel" , () => {
test ( "sends messages" , async () => {
const ctx = createMockContext ();
await customChannel . outbound . send ( ctx , {
to: "user-123" ,
text: "Hello!" ,
});
expect ( mockApi . sendText ). toHaveBeenCalledWith ({
recipient: "user-123" ,
message: "Hello!" ,
});
});
});
Next Steps
Channel Plugins Deep dive into channel plugin development
Provider Plugins Build custom LLM and tool providers