Plugin API Reference
This is a reference doc. It covers the Plugin interface contract and how to write workspace bus plugins.
See also: explanation/plugin-lifecycle.md for how plugins register, subscribe, and reload.
Plugin interface
Section titled “Plugin interface”All workspace bus plugins must implement:
interface Plugin { readonly name: string; readonly description: string; readonly capabilities: string[]; install(bus: EventBus): void; uninstall(): void;}install(bus: EventBus)
Section titled “install(bus: EventBus)”Called once on container startup after the bus is created. Subscribe to topics and set up HTTP servers here.
install(bus: EventBus): void { bus.subscribe("message.inbound.#", this.name, (msg: BusMessage) => { // handle message });}uninstall()
Section titled “uninstall()”Called on graceful shutdown. Clean up timers, close HTTP servers, release resources.
EventBus interface
Section titled “EventBus interface”interface EventBus { subscribe(topic: string, subscriberId: string, handler: (msg: BusMessage) => void): void; publish(topic: string, message: BusMessage): void; unsubscribe(subscriberId: string): void;}Topic patterns use # as a wildcard matching any number of segments (MQTT-style):
message.inbound.# matches message.inbound.github.owner.repo.event.123message.inbound.discord.# matches message.inbound.discord.channelIdBusMessage shape
Section titled “BusMessage shape”interface BusMessage { id: string; // UUID topic: string; // the topic this message was published on timestamp: number; // Unix milliseconds correlationId?: string; // links request → response → chain payload: { sender?: string; content?: string; channel?: string; skillHint?: string; reply?: string; [key: string]: unknown; }; reply?: string; // outbound topic for responses source?: { interface: string; // "discord" | "github" | "plane" | "cron" | ... channelId: string; userId: string; };}Writing a workspace bus plugin
Section titled “Writing a workspace bus plugin”import type { Plugin, EventBus, BusMessage } from "../../lib/types";
export default { name: "my-plugin", description: "Does something useful on the bus", capabilities: ["custom"],
install(bus: EventBus) { bus.subscribe("message.inbound.#", "my-plugin", (msg: BusMessage) => { bus.publish("message.outbound.custom", { id: msg.id, topic: "message.outbound.custom", timestamp: Date.now(), payload: { content: "Custom response" }, }); }); },
uninstall() {},} satisfies Plugin;Capabilities
Section titled “Capabilities”- Subscribe to any bus topic
- Publish messages to any topic
- Bridge external services (APIs, webhooks, databases)
- Transform or route messages between channels
- Implement custom command handlers
Limitations
Section titled “Limitations”- Cannot modify the agent’s system prompt directly
- Cannot intercept tool calls at the LLM layer
- Hot reload requires a container restart (
docker restart workstacean)