Extensions
Subscribe to privacy-safe session activity events from a DorkOS extension
Extensions
Extensions let you build custom UI and automation on top of DorkOS session activity, without ever seeing what was said in a session. This page documents the event-subscription surface, api.events, and assumes you already have an extension scaffold (a manifest and an activate() entry point) to build on.
A DorkOS extension is a bundle of JavaScript that runs in the browser alongside the client UI. Its manifest (extension.json) declares identity, version, and capabilities; its entry point exports an activate(api) function that the host calls on load, handing it an ExtensionAPI object:
import type { ExtensionAPI } from '@dorkos/extension-api';
export function activate(api: ExtensionAPI): () => void {
// register UI, read state, subscribe to events...
return () => {
// cleanup, called on deactivate
};
}ExtensionAPI covers UI contributions (registerComponent, registerCommand, registerDialog, registerSettingsTab), UI control (executeCommand, openCanvas, navigate), read-only host state (getState, subscribe), scoped storage (loadData/saveData), notifications (notify), and the event subscription surface this page documents: api.events. See packages/extension-api/src/extension-api.ts for the full interface; this page focuses on api.events.subscribe.
Testing locally
The host discovers extensions from two directories: .dork/extensions/<id>/ in your project for a local extension, or ~/.dork/extensions/<id>/ for a global one available everywhere. Drop your manifest and entry file there, then open Settings → Extensions and click Reload Extensions to pick up the change without restarting the client.
Event subscription
api.events is a small, typed push channel. It is deliberately not the raw session stream. Extensions run untrusted in the browser, so the host exposes only a curated set of lifecycle and activity summaries:
interface ExtensionEventsAPI {
subscribe(kinds: ExtensionEventKind[], handler: (event: ExtensionEvent) => void): () => void;
}Call api.events.subscribe with the event kinds you want and a handler; it returns an unsubscribe function (also called automatically on deactivate).
Privacy guarantee. Events never carry conversation content. Excluded, forever: assistant/user message text, thinking output, tool-call arguments, tool results, and relay message payloads. An extension learns that a tool ran and which tool, never what it did.
Event kinds and payloads
Prop
Type
Manifest declaration
An extension must declare which events it wants to receive in the manifest's capabilities.events array before api.events.subscribe will deliver anything. Each entry is either a specific kind ('turn.completed') or a whole category ('session', 'turn', 'tool', 'relay'): declaring a category authorizes every kind under it:
{
"id": "my-extension",
"name": "My Extension",
"version": "1.0.0",
"capabilities": {
"events": ["session", "tool.activity", "relay.message"]
}
}A subscribe call for a kind the manifest didn't declare is rejected at runtime: the host logs a console warning naming the undeclared kind(s) and silently drops them from the subscription (the rest still deliver). If every requested kind is undeclared, the returned unsubscribe function is a no-op. Open your browser's devtools console while testing to catch these warnings.
Event scoping
Delivery scope differs by event category. This matters when you're deciding whether an event tells you about the whole host or just what the operator is currently looking at.
Prop
Type
If you need turn or tool activity for a session that isn't in the foreground, there is no way to
get it through api.events today; those two categories are gated to whatever session the operator
has attached.
Example
A manifest that declares access to session lifecycle and tool activity, and an activate that logs both:
{
"id": "activity-logger",
"name": "Activity Logger",
"version": "1.0.0",
"description": "Logs session lifecycle and tool activity to the console",
"capabilities": {
"events": ["session", "tool.activity"]
}
}import type { ExtensionAPI, ExtensionEvent } from '@dorkos/extension-api';
export function activate(api: ExtensionAPI): () => void {
const unsubscribe = api.events.subscribe(
['session.started', 'session.ended', 'tool.activity'],
(event: ExtensionEvent) => {
switch (event.kind) {
case 'session.started':
console.log(`[activity-logger] session started: ${event.sessionId}`);
break;
case 'session.ended':
console.log(`[activity-logger] session ended: ${event.sessionId}`);
break;
case 'tool.activity':
console.log(`[activity-logger] ${event.toolName} ${event.status}`);
break;
}
}
);
return () => {
unsubscribe();
};
}