Building Integrations
Create custom clients using the DorkOS Transport interface
Building Integrations
DorkOS uses a hexagonal (ports & adapters) architecture centered on the Transport interface. Build custom clients by implementing this interface or by calling the REST/SSE API directly.
The Transport Interface
The Transport interface (packages/shared/src/transport.ts) defines all client-server communication:
interface Transport {
// Sessions
createSession(opts: CreateSessionRequest): Promise<Session>;
listSessions(cwd?: string): Promise<Session[]>;
getSession(id: string, cwd?: string): Promise<Session>;
updateSession(id: string, opts: UpdateSessionRequest, cwd?: string): Promise<Session>;
getMessages(sessionId: string, cwd?: string): Promise<{ messages: HistoryMessage[] }>;
sendMessage(sessionId, content, onEvent, signal?, cwd?, options?): Promise<void>;
// options: { clientMessageId?: string; uiState?: UiState }
// Tool interaction
approveTool(sessionId: string, toolCallId: string): Promise<{ ok: boolean }>;
denyTool(sessionId: string, toolCallId: string): Promise<{ ok: boolean }>;
submitAnswers(sessionId, toolCallId, answers): Promise<{ ok: boolean }>;
stopTask(sessionId: string, taskId: string): Promise<{ success: boolean; taskId: string }>;
interruptSession(sessionId: string): Promise<{ ok: boolean }>;
getTasks(sessionId: string, cwd?: string): Promise<{ tasks: TaskItem[] }>;
// Filesystem & git
browseDirectory(dirPath?, showHidden?): Promise<BrowseDirectoryResponse>;
getDefaultCwd(): Promise<{ path: string }>;
listFiles(cwd: string): Promise<FileListResponse>;
getGitStatus(cwd?: string): Promise<GitStatusResponse | GitStatusError>;
// Commands & config
getCommands(refresh?: boolean, cwd?: string): Promise<CommandRegistry>;
health(): Promise<HealthResponse>;
getConfig(): Promise<ServerConfig>;
updateConfig(patch: Record<string, unknown>): Promise<void>;
// Runtime
getModels(): Promise<ModelOption[]>;
getCapabilities(): Promise<{
capabilities: Record<string, RuntimeCapabilities>;
defaultRuntime: string;
}>;
// File uploads
uploadFiles(files: UploadFile[], cwd: string, onProgress?): Promise<UploadResult[]>;
// Tunnel
startTunnel(): Promise<{ url: string }>;
stopTunnel(): Promise<void>;
// Directory operations
createDirectory(parentPath: string, folderName: string): Promise<{ path: string }>;
// Templates
getTemplates(): Promise<TemplateEntry[]>;
// Default agent
setDefaultAgent(agentName: string): Promise<void>;
// Admin
resetAllData(confirm: string): Promise<{ message: string }>;
restartServer(): Promise<{ message: string }>;
}The full interface also covers Tasks, Relay, Mesh, and agent identity operations. See packages/shared/src/transport.ts for the complete definition.
Built-in Implementations
HttpTransport is used by the standalone web client and communicates with the Express server over HTTP and SSE:
- Standard
fetch()for CRUD operations - Server-Sent Events for streaming in
sendMessage() - Parses SSE events into
StreamEventobjects - Includes
X-Client-Idheader for session write coordination
DirectTransport is used by the Obsidian plugin and calls service instances directly in the same process:
- No HTTP, no port binding, no network serialization
- Iterates
AsyncGenerator<StreamEvent>from the Claude Agent SDK - Lower latency, ideal for embedded contexts
Building a Custom Client
Use the REST API directly for any language or platform:
# List sessions
GET /api/sessions
# Create a session
POST /api/sessions
Content-Type: application/json
{ "cwd": "/path/to/project" }
# Send a message (returns SSE stream)
POST /api/sessions/:id/messages
Content-Type: application/json
{ "content": "Hello", "cwd": "/path/to/project" }
# Approve a tool call
POST /api/sessions/:id/approve
Content-Type: application/json
{ "toolCallId": "tc_123" }The full REST API is documented interactively at /api/docs (Scalar UI) when the server is running, or see the API Reference.
Implement the Transport interface for deeper integration:
import type { Transport } from '@dorkos/shared/transport';
class MyCustomTransport implements Transport {
async listSessions() {
// Your implementation
}
async sendMessage(sessionId, content, onEvent, signal, cwd) {
// Call onEvent() for each StreamEvent
}
// ... implement remaining methods
}All methods in the Transport interface must be implemented. TypeScript will report compile-time errors for any missing methods. The interface is large — see the source for the complete list.
Inject your Transport via context:
import { TransportProvider } from '@dorkos/shared';
const transport = new MyCustomTransport();
function App() {
return (
<TransportProvider transport={transport}>
<YourApp />
</TransportProvider>
);
}All DorkOS hooks (useSessions, useChatSession, etc.) consume the Transport from context, so your implementation powers the entire UI automatically.
StreamEvent Types
Events emitted during message streaming:
Prop
Type