Skip to content

Architecture

Molf Assistant is a monorepo with 10 packages under packages/, managed by pnpm workspaces. A central oRPC WebSocket server orchestrates LLM interactions while workers execute tool calls locally. Clients connect over WebSocket to drive sessions.

Package Overview

PackageDescription
protocolShared types, Zod schemas, oRPC contract definition, plugin system, credentials, TLS trust, tool definitions, truncation, WebSocket helpers
agent-coreAgent class (manual step loop with streamText), Session, context pruner, provider registry/catalog, system prompts
serverWebSocket server (oRPC), SessionManager, AgentRunner, ServerBus, ToolDispatch, ApprovalGate, ConnectionRegistry, WorkspaceStore, PluginLoader, SubagentRunner
workerToolExecutor, skill/agent loading, server connection with auto-reconnect, StateWatcher, SyncCoordinator, worker plugin loader
client-tuiInk 5 + React 18 terminal client
client-telegramTelegram bot client via grammY framework
plugin-cronDefault server plugin: cron job scheduling with routes and session tool
plugin-mcpDefault worker plugin: MCP client integration (stdio + HTTP transport)
test-utilsShared test helpers: mockStreamText, createTmpDir, createEnvGuard, getFreePort
e2eIntegration and live test suites with server/worker test helpers

Dependency Graph

protocol
  ├──▲── agent-core
  │        ▲
  │        │
  │      server

  ├──▲── worker
  ├──▲── client-tui
  ├──▲── client-telegram
  ├──▲── plugin-cron
  └──▲── plugin-mcp

protocol sits at the base. agent-core builds on protocol to provide the Agent class and provider system. server depends on both protocol and agent-core. All other packages (worker, clients, plugins) depend only on protocol.

Communication

All communication uses oRPC over WebSocket with TLS enabled by default. The server exposes 9 sub-routers:

RouterDomain
sessionSession lifecycle (create, list, load, delete, rename)
agentLLM interaction (prompt, abort, events subscription)
toolTool approval (approve, deny, list)
workerWorker registration, state sync, tool call dispatch
fsFile system reads (tool output retrieval)
providerLLM provider and model listing, API key management, custom provider configuration
workspaceWorkspace management and config
authPairing codes, API key management
pluginPlugin route dispatch

See Protocol for the full oRPC API reference.

Message Flow

Prompt Flow

Client                    Server                     Worker
  │                         │                          │
  ├─ agent.prompt ─────────►│                          │
  │                         ├─ AgentRunner.run()       │
  │                         ├─ streamText (LLM) ──►    │
  │                         │  ◄── tool_call           │
  │                         ├─ ToolDispatch ──────────►│
  │                         │                          ├─ ToolExecutor
  │                         │  ◄── toolResult ─────────┤
  │                         ├─ continue loop           │
  │                         │  ...                     │
  │  ◄── turn_complete ─────┤                          │
  1. Client sends agent.prompt with session ID and text.
  2. AgentRunner resolves the model (prompt-level > workspace config > server default), builds the system prompt, and calls streamText from Vercel AI SDK.
  3. When the LLM emits tool calls, ToolDispatch routes them to the bound worker via promise queuing (120s timeout).
  4. The worker executes the tool via ToolExecutor and returns the result.
  5. The agent loop continues until the LLM produces a final response or maxSteps is reached.

Event Flow

AgentRunner ──► ServerBus (session scope) ──► agent.onEvents subscription ──► Client
ProviderKeyStore ──► ServerBus (global scope) ──► provider_state_changed ──► All Clients

The AgentRunner emits 9 event types per session through the ServerBus session channel: status_change, content_delta, tool_call_start, tool_call_end, turn_complete, error, tool_approval_required, context_compacted, and subagent_event. Clients subscribe via agent.onEvents to receive streaming updates.

Additionally, the ServerBus global channel broadcasts a provider_state_changed event to all connected clients when a provider API key is added or removed at runtime.

Key Abstractions

AgentRunner

Orchestrates LLM interactions. Maintains a cache of Agent instances per session (evicted after 30 minutes idle). Builds system prompts from default instructions, skill hints, task hints, workdir context, media references, and runtime context. Dispatches hooks at turn_start, before_prompt, after_prompt, and turn_end.

ToolDispatch

Routes tool calls from the server to the connected worker. Uses promise queuing with a 120-second timeout. If a worker disconnects, all pending dispatches are rejected immediately.

ServerBus

Scoped publish-subscribe event bus. Supports four channel scopes: global (provider state changes, broadcast to all clients), session (agent events per session), workspace (workspace-scoped events), and worker (worker-scoped events). AgentRunner publishes session events; clients consume them via oRPC subscriptions. Replaces the former EventBus and WorkspaceNotifier.

ConnectionRegistry

Tracks all connected WebSocket clients (workers and clients). Worker state persists across disconnects -- workers are marked offline rather than removed. Dispatches worker_connect and worker_disconnect hooks.

ApprovalGate

Three-layer tool approval evaluation: agent permissions (subagent sessions only), static rules from permissions.jsonc, and runtime "always approve" patterns. See Tool Approval.

PluginLoader

Loads server plugins from config, validates config against plugin schemas, and manages the plugin lifecycle. Tracks worker plugin specifiers to send to workers on connect. See Plugins.

SessionManager

In-memory session cache with JSON file persistence at {dataDir}/sessions/{id}.json. Uses atomic writes (tmp file + rename). Dispatches session_create, session_delete, and session_save hooks.

WorkspaceStore

Groups sessions into workspaces. Each workspace carries a per-workspace model config override. Persisted at {dataDir}/workers/{workerId}/workspaces/{workspaceId}/workspace.json.

Server Module Table

ModuleDescription
main.tsEntry point: CLI parsing, config resolution, LogTape setup, server start
config.tsConfig resolution (JSONC + CLI + env), defaults; JSONC in-place modification (modifyConfigFile)
server.tsWebSocket server initialization, TLS, component wiring
router.tsoRPC router composition (9 sub-routers)
context.tsoRPC context and middleware (auth)
agent-runner.tsLLM orchestration, system prompt building, model resolution
session-mgr.tsSession persistence and caching
server-bus.tsScoped event bus (global, session, workspace, worker); replaces EventBus and WorkspaceNotifier
secrets.tsUnified secrets persistence (auth tokens + provider keys in secrets.json)
provider-keys.tsProviderKeyStore: per-provider key CRUD backed by secrets.ts
server-state.tsServerState container; provider registry reload without restart
auth.tsToken verification, API key management
tls.tsSelf-signed certificate generation
connection-registry.tsWebSocket client tracking
worker-store.tsWorker state persistence
worker-dispatch.tsTool call, upload, and FS read dispatch to workers
workspace-store.tsWorkspace config and session grouping
plugin-loader.tsServer plugin loading and lifecycle
plugin-api.tsServerPluginApi implementation
plugin-routes.tsPlugin route oRPC integration
summarization.tsContext summarization
subagent-runner.tsSubagent session lifecycle
subagent-types.tsBuilt-in agent definitions (explore, general)
pairing.tsPairing code store
approval/approval-gate.tsThree-layer tool approval
approval/evaluate.tsPattern matching and rule evaluation
approval/ruleset-storage.tspermissions.jsonc persistence
approval/shell-parser.tsShell command parsing for approval

Worker Module Table

ModuleDescription
index.tsEntry point: CLI, identity, TLS, connection, plugin loading
cli.tsCLI argument parsing
identity.tsPersistent worker UUID
connection.tsServer connection with auto-reconnect
tool-executor.tsTool registration and execution
skills.tsSkill and AGENTS.md loading
agents.tsAgent definition loading
state-watcher.tsFile system watching for skills/agents changes
sync-coordinator.tsSerialized state sync to server
plugin-loader.tsWorker plugin loading
plugin-api.tsWorkerPluginApi implementation
pair.tsTOFU + pairing code exchange
truncation.tsTool output truncation and storage

See also

  • Protocol -- full oRPC API reference
  • Plugins -- plugin and hook system
  • Logging -- structured logging configuration