DorkOS
Integrations

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 StreamEvent objects
  • Includes X-Client-Id header 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

Next Steps