WOPR's plugin system enables extending functionality through community and official plugins. Plugins can add channels (Discord, Telegram, etc.), providers (AI models), and middleware.
Connect WOPR to external messaging platforms:
| Plugin | Platform | Status | Repository |
|---|---|---|---|
wopr-plugin-discord |
Discord | ✅ Ready | wopr-network/wopr-plugin-discord |
wopr-plugin-slack |
Slack | ✅ Ready | wopr-network/wopr-plugin-slack |
wopr-plugin-telegram |
Telegram | ✅ Ready | wopr-network/wopr-plugin-telegram |
wopr-plugin-whatsapp |
✅ Ready | wopr-network/wopr-plugin-whatsapp | |
wopr-plugin-signal |
Signal | ✅ Ready | wopr-network/wopr-plugin-signal |
wopr-plugin-imessage |
iMessage | ✅ Ready (macOS) | wopr-network/wopr-plugin-imessage |
wopr-plugin-msteams |
Microsoft Teams | ✅ Ready | wopr-network/wopr-plugin-msteams |
AI model provider integrations. Note that anthropic and codex providers are built-in.
| Plugin | Provider | Status | Repository |
|---|---|---|---|
wopr-plugin-provider-kimi |
Moonshot AI Kimi | ✅ Ready | wopr-network/wopr-plugin-provider-kimi |
wopr-plugin-provider-openai |
OpenAI GPT | ✅ Ready | wopr-network/wopr-plugin-provider-openai |
wopr-plugin-provider-anthropic |
Anthropic Claude | ✅ Ready | wopr-network/wopr-plugin-provider-anthropic |
| Plugin | Purpose | Status | Repository |
|---|---|---|---|
wopr-plugin-p2p |
P2P networking, identity, invites, discovery | ✅ Ready | wopr-network/wopr-plugin-p2p |
The P2P plugin adds:
- Cryptographic identity (Ed25519/X25519 keypairs)
- End-to-end encrypted messaging
- Signed invites bound to recipient public keys
- DHT-based peer discovery (Hyperswarm)
- Forward secrecy with ephemeral keys
Commands added by the P2P plugin:
wopr id init- Generate identitywopr id- Show your IDwopr id rotate- Rotate keyswopr invite <pubkey> <session>- Create invitewopr invite claim <token>- Claim invitewopr access- List access grantswopr revoke <peer>- Revoke accesswopr discover join <topic>- Join discovery topicwopr discover peers- List discovered peerswopr discover connect <peer>- Connect to peerwopr inject <peer>:<session> <message>- Send to peer
| Plugin | Purpose | Status | Repository |
|---|---|---|---|
wopr-plugin-router |
Message routing between sessions | 🔨 Planned | - |
wopr-plugin-memory |
Persistent memory across sessions | 🔨 Planned | - |
# Install from GitHub
wopr plugin install github:wopr-network/wopr-plugin-discord
# Enable the plugin
wopr plugin enable wopr-plugin-discord
# Configure the plugin
wopr config set plugins.data.wopr-plugin-discord '{"botToken": "...", "channelId": "..."}'
# List installed plugins
wopr plugin list
# Disable/remove
wopr plugin disable wopr-plugin-discord
wopr plugin uninstall wopr-plugin-discordFor easy setup of multiple plugins:
wopr onboardThis interactive wizard will:
- Configure AI providers (API keys)
- Set up channel plugins (Discord, Slack, Telegram, etc.)
- Configure P2P networking (requires wopr-plugin-p2p)
- Set up skills and middleware
import type { WOPRPlugin, WOPRPluginContext } from "wopr";
const plugin: WOPRPlugin = {
name: "my-plugin",
version: "1.0.0",
description: "My awesome plugin",
async init(ctx: WOPRPluginContext) {
ctx.log.info("Plugin initialized!");
// Access configuration
const config = ctx.getConfig();
// Register a channel adapter
ctx.registerChannel({
channel: { type: "myplatform", id: "channel-id", name: "My Channel" },
session: "default",
async send(content) {
// Send message to external platform
},
async start(handler) {
// Start listening for messages
},
async stop() {
// Stop listening
},
});
},
async destroy(ctx: WOPRPluginContext) {
ctx.log.info("Plugin destroyed!");
},
};
export default plugin;The ctx object provides:
Session Management:
ctx.inject(session, message, options)- Get AI responsectx.logMessage(session, message, options)- Log without AI responsectx.injectPeer(peer, session, message)- Send to peer
Configuration:
ctx.getConfig()- Get plugin configctx.saveConfig(config)- Save plugin configctx.getMainConfig(key)- Access main WOPR config
Channels:
ctx.registerChannel(adapter)- Register a channelctx.unregisterChannel(channel)- Unregisterctx.getChannels()- List all channels
Events:
ctx.events.on(event, handler)- Subscribe to eventsctx.events.once(event, handler)- Subscribe oncectx.events.emit(event, payload)- Emit custom eventsctx.hooks.on(event, handler)- Mutable lifecycle hooks
See Events Documentation for details.
Context Providers:
ctx.registerContextProvider(provider)- Add context sourcesctx.unregisterContextProvider(name)- Remove
Middleware:
ctx.registerMiddleware(middleware)- Register message middlewarectx.getMiddlewares()- List middlewares
Web UI:
ctx.registerWebUiExtension(extension)- Add nav linksctx.registerUiComponent(extension)- Add SolidJS components
Logging:
ctx.log.info(message, ...args)ctx.log.warn(message, ...args)ctx.log.error(message, ...args)ctx.log.debug(message, ...args)
Define a UI for plugin configuration:
ctx.registerConfigSchema("my-plugin", {
title: "My Plugin Settings",
description: "Configure my plugin",
fields: [
{
name: "apiKey",
type: "string",
label: "API Key",
secret: true,
required: true,
},
{
name: "enabled",
type: "boolean",
label: "Enabled",
default: true,
},
{
name: "mode",
type: "select",
label: "Mode",
options: ["simple", "advanced"],
default: "simple",
},
],
});Add commands to the WOPR CLI:
const plugin: WOPRPlugin = {
// ... init, destroy
commands: {
async status(ctx) {
const config = ctx.getConfig();
return `Plugin is ${config.enabled ? "enabled" : "disabled"}`;
},
async config(ctx, args) {
if (args[0] === "set") {
// Handle set command
return "Config updated";
}
return JSON.stringify(ctx.getConfig(), null, 2);
},
},
};Usage: wopr plugin cmd my-plugin status
The event bus enables reactive plugin composition:
async init(ctx) {
// React to session lifecycle
ctx.events.on("session:create", (event) => {
ctx.log.info(`New session: ${event.session}`);
});
// React to messages
ctx.events.on("session:beforeInject", (event) => {
// Log, analyze, or modify
analytics.track(event.session, event.message);
});
// Inter-plugin communication
ctx.events.on("other-plugin:event", (event) => {
// React to other plugins
});
// Emit custom events
await ctx.events.emitCustom("myplugin:ready", {
timestamp: Date.now()
});
}See Events Documentation for full details.
Publish your plugin:
- Create a GitHub repository
- Add a
package.jsonwith proper metadata - Tag releases with semantic versions
- Users install:
wopr plugin install github:username/repo
- Use semantic versioning - Follow semver for releases
- Handle errors gracefully - Don't crash WOPR on errors
- Clean up in destroy - Stop listeners, close connections
- Use config schemas - Make configuration easy
- Document your plugin - Clear README with examples
- Prefix custom events - Use
pluginname:eventformat - Respect the event loop - Don't block, use async
Contributions welcome! To add your plugin to the list:
- Ensure it follows the plugin API
- Has a clear README with setup instructions
- Submit a PR to update this document
Check logs: wopr daemon logs
Common issues:
- Missing dependencies:
npm installin plugin directory - Syntax errors: Check TypeScript compilation
- Missing config: Use
wopr config set
Plugins can conflict if they:
- Register the same channel ID
- Use conflicting middleware
- Override each other's config
Use descriptive names and check wopr plugin list.
Enable debug logging:
DEBUG=wopr:* wopr daemon startOr in your plugin:
ctx.log.debug("Debug info:", data);