Main Process Design
The main process is the core of Elftia, responsible for all business logic, external API calls, database operations, and security controls. The entry file is packages/desktop/app/main/index.ts.
Service Module Overview
The main process contains 45+ service modules, organized by functional domain under packages/desktop/app/main/services/:
graph LR
subgraph "Core Infrastructure"
Core[core/]
Config[config/]
Settings[settings/]
end
subgraph "Auth & Accounts"
Auth[auth/]
Account[account/]
OAuth[oauth/]
end
subgraph "AI Engines"
Engine[engine/]
Completion[completion/]
LLM[llm/]
Prompt[prompt/]
end
subgraph "Agent Orchestration"
Magi[magi/]
Agent[agent/]
Plugin[plugin/]
end
subgraph "Messaging Channels"
Channel[channel/]
Security[security/]
end
subgraph "Media & Content"
Media[media/]
Project[project/]
Search[search/]
end
Core --> Engine
Core --> Channel
Engine --> Magi
LLM --> Completion
Completion --> Engine
Magi --> Agent
Channel --> Security
Service List by Domain
| Domain | Service | Description |
|---|---|---|
| Core (core/) | LoggerService | Winston + daily-rotate-file logging |
AppPaths | Application path resolution (userData, dbPath, configDir, etc.) | |
RuntimeService | Runtime information (version, channel, platform) | |
CacheService | General-purpose cache (TTL expiry cleanup) | |
ConfigManager | Config file management | |
SecurityService | AES-256-GCM encryption service | |
CryptoService | PBKDF2 key derivation + encrypt/decrypt | |
PerformanceMonitor | Performance monitoring and alerting | |
ErrorHandler | Global error handling | |
PluginManager | Plugin lifecycle management | |
DatabaseOptimizer | SQLite optimization (VACUUM, ANALYZE) | |
CommandService | Command execution service | |
| Auth (auth/) | AuthService | IPC authentication token validation |
AuthSessionService | Login session + Deep Link handling | |
AuthTokenStore | Auth token persistence | |
TokenRefreshService | Automatic token refresh | |
| Account (account/) | AccountService | User credential management |
AccountTokensService | OAuth token management | |
LimitsService | Membership limit checks | |
| LLM (llm/) | LLMConfigService | Provider/model configuration CRUD |
TransformerService | Request format transformation chain | |
| Completion (completion/) | CompletionService | LLM API call entry point |
ApiKeyPoolService | Multi-key round-robin + session affinity | |
| Engine (engine/) | EngineDispatcher | Engine registration and routing |
ApiEngine | Media API engine | |
ChatEngine | General chat engine | |
ClaudeSdkEngine | Claude Agent SDK engine | |
TinyElfEngine | Built-in Agent engine | |
CliRunnerEngine | CLI subprocess engine | |
STChatEngine | RP chat pipeline engine | |
| Magi Orchestration (magi/) | MagiService | Core message-processing service (includes assembleMagiMcps which collects Clawia's MCP set via the services/capabilities/tools/mcp-builtin/ registry; buildTinyElfDirectMcpServers is the TinyElf entry point) |
MagiSessionService | Session persistence management | |
MagiWorkspaceService | Workspace directory management | |
MagiSdkOptionsBuilder | Prompt building (V1-V4) + user MCP injection (setUserMcpServers / getMcpServers(allowedUserMcpNames) / getDirectMcpServers) + Channel probe; built-in MCP assembly migrated out to mcp-providers/ since Phase 5.9 | |
AgentOrchestrator | Agent dispatch and orchestration | |
AgentDiscovery | Schedulable Agent roster | |
MessageRouter | Dual-mode message routing | |
ChannelMagiBridge | Bridge from Channel to Magi | |
SessionEventBus | Session event bus | |
SessionDispatcherImpl | Cross-session dispatch implementation | |
SubagentRegistry | Subagent state tracking | |
| Built-in MCP Registry (mcp-providers/) | McpProviderRegistry | 12 built-in providers + dynamic ScriptPlugin provider factory. All built-in MCP handlers run in-process; SDK calls directly / TinyElf registers as ITool / CLI accesses via the central BuiltinMcpHttpServer HTTP bridge. The DispatchServer / ChannelServer / VisionAssistServer HTTP bridges were removed in cleanup-legacy-mcp (2026-05-19) |
BuiltinMcpHttpServer | Central HTTP MCP bridge (per-session scope); all in-process MCPs are exposed to the CLI engine through it | |
assembleMcpForSession(ctx) | Unified assembly entry (SDK + TinyElf; returns McpAssembly containing sdkServers / tinyElfServers / promptFragments / allowedTools / cleanups) | |
applyAssembly.ts | applyAssemblyToSdkOptions / applyAssemblyToTinyElfConfig — merges McpAssembly into engine options | |
contextBuilders.ts | buildAssemblyContextFor{Clawia,Agent} — constructs AssemblyContext from the caller's perspective | |
registerBuiltinMcpProviders.ts | One-time boot assembly point (includes ScriptPlugin same-name alias handling) | |
builtin/<Name>Provider.ts | One Provider module per built-in MCP (12 static + dynamic ScriptPlugin factory) | |
| Channel (channel/) | ChannelPluginLoader | Plugin discovery and loading |
ChannelPluginRegistry | Plugin registration and instance management | |
ChannelMessageRouter | Message trigger routing | |
ChannelMarketplaceService | Plugin marketplace | |
| Security (security/) | ExecutionFirewall | File path firewall |
GuardianAgent | AI tool call review | |
PromptGuardian | Prompt injection detection | |
RateLimiter | Rate limiting | |
InputSanitizer | Input sanitization | |
UserPermissionService | User permission management | |
ChannelPermissionGate | Channel permission confirmation | |
AuditLogger | Security audit log | |
| Media (media/) | ImageGenerationService | Image generation |
MusicGenerationService | Music generation | |
MediaStorageService | Media file storage | |
MediaResourceService | Content-addressed resource storage | |
MediaConfigService | Media provider configuration | |
AsrService / TtsService | Speech recognition/synthesis | |
| Project (project/) | ProjectService | Project CRUD |
FileIndexService | File index service | |
GitService | Git operations | |
| Search (search/) | WebSearchService | Unified search entry point |
JinaProvider / TavilyProvider / SearxngProvider | Search engine adapters | |
| UI (ui/) | ThemeService | Theme management |
WindowControlsService | Window controls | |
TrayService | System tray | |
NotificationService | Desktop notifications | |
| Config (config/) | ConfigStore | electron-store + fs.watch hot-reload |
| Cron (cron/) | CronService | Cron scheduled task dispatch |
| MCP (mcp/) | McpService | MCP server management |
| Plugins (plugin/) | ScriptPluginLoader | Script plugin loading |
ScriptPluginRegistry | Script plugin registry | |
ScriptPluginBridgeManager | Plugin bridge management |
IPC Router Architecture
All frontend-to-backend communication goes through the IPC Router layer; 68+ router modules are currently registered.
secureHandle Pattern
Each IPC channel is wrapped with secureHandle, enforcing authentication token validation:
{/* packages/desktop/app/main/ipc/safe-handle.ts */}
function secureHandle(
channel: string,
handler: (event: IpcMainInvokeEvent, params: unknown) => Promise<unknown>,
validateToken: (token: string) => boolean,
): void;
Flow:
sequenceDiagram
participant R as Renderer
participant P as Preload
participant S as secureHandle
participant H as Router Handler
R->>P: window.api.someMethod(params)
P->>S: ipcRenderer.invoke(channel, {token, ...params})
S->>S: validateToken(token)
alt token invalid
S-->>P: throw AuthError
else token valid
S->>H: handler(event, params)
H-->>S: result
S-->>P: result
P-->>R: result
end
Route Registration
All routes are centrally registered in registerAllRouters(). Each Router class extends BaseRouter and registers its channels in the register() method:
{/* Simplified Router structure */}
class SomeRouter extends BaseRouter {
register() {
secureHandle('domain:action', async (_event, params) => {
const validated = SomeSchema.parse(params);
return this.service.doSomething(validated);
}, this.validate);
}
}
Route Categories and Counts
| Router Directory/File | Channel Prefix | Main Channel Count |
|---|---|---|
auth/ | auth:* | 5+ |
account/ | accounts:*, accountTokens:* | 8+ |
session/ | sessions:*, sessionOrganizer:* | 10+ |
chat/ | chatMessages:*, chatAssistants:*, chatControl:*, mediaSession:* | 15+ |
completion/ | completion:* | 5+ |
capabilities/llm/ | llmProviders:*, llmModels:*, apiKeys:*, transformers:* | 15+ |
project/ | projects:*, files:*, git:* | 10+ |
media/ | media:*, imageProviders:*, musicProviders:*, videoProviders:*, asr:*, tts:* | 20+ |
settings/ | settings:*, appPreferences:* | 8+ |
ui/ | theme:*, window:* | 6+ |
MagiRouter | magi:* | 10+ |
ChannelPluginRouter | channels:* | 8+ |
sillytavern/ | characterCards:*, worldInfo:*, regexScripts:*, groupChat:*, etc. | 25+ |
| Others | mcp:*, webSearch:*, todo:*, tasks:*, notes:*, tags:*, cron:*, elfi:*, etc. | 30+ |
Worker Thread Pattern
Time-consuming I/O operations run in Worker Threads to avoid blocking the main thread.
DbClient — Database Worker
DbClient is the most critical Worker, encapsulating all interactions with the SQLite database:
sequenceDiagram
participant S as Service
participant C as DbClient
participant W as db.worker.ts
participant D as SQLite (WAL)
S->>C: db.someMethod(params)
C->>C: seq++, create Promise
C->>W: postMessage({id: seq, method, params})
W->>D: Execute SQL query
D-->>W: Result
W-->>C: postMessage({id: seq, result})
C->>C: resolve(pending[seq])
C-->>S: Promise<result>
{/* Simplified DbClient RPC pattern */}
class DbClient extends EventEmitter implements DbRpc {
private worker: Worker;
private seq = 0;
private pending = Map<number, {resolve, reject}>;
async send(method: string, params: unknown): Promise<unknown> {
const id = ++this.seq;
return new Promise((resolve, reject) => {
this.pending.set(id, { resolve, reject });
this.worker.postMessage({ id, method, params });
});
}
async ready(): Promise<void>;
}
Key design points:
- Async RPC: Each call is assigned a unique sequence number; requests are sent via
postMessage - Ready wait:
await db.ready()ensures the Worker has finished initialization (schema creation) before use - Error forwarding: Worker errors bubble up through EventEmitter
Worker Thread List
| Worker File | Purpose | Communication |
|---|---|---|
db.worker.ts | SQLite database read/write (100+ RPC methods) | DbClient RPC |
fileSearch.worker.ts | File search (fuzzy match) | MessagePort |
fileWatcher.worker.ts | Filesystem watching (chokidar) | MessagePort |
mcp.worker.ts | MCP server process management | MessagePort |
diagnostics.worker.ts | System diagnostic data collection | MessagePort |
project.worker.ts | Project file index building | MessagePort |
fileSnapshot.worker.ts | File snapshot diffing | MessagePort |
Key Infrastructure
LoggerService
Based on Winston, supports log level filtering and automatic log file rotation:
{/* Simplified LoggerService interface */}
class LoggerService {
info(message: string, meta?: Record<string, unknown>): void;
warn(message: string, err?: Error, meta?: Record<string, unknown>): void;
error(message: string, err?: unknown, meta?: Record<string, unknown>): void;
debug(message: string, meta?: Record<string, unknown>): void;
}
- Log location:
{userData}/logs/ - Rotation policy: daily-rotate-file, retained for 14 days
- Format: JSON + timestamp
SecurityService / CryptoService
{/* Core encryption service interface */}
class SecurityService {
encrypt(plaintext: string): string;
decrypt(ciphertext: string): string;
}
class CryptoService {
deriveKey(password: string, salt: Buffer): Buffer;
encrypt(data: string, key: Buffer): EncryptedData;
decrypt(data: EncryptedData, key: Buffer): string;
}
AppPaths
Centrally manages all application directory paths:
| Property | Path | Purpose |
|---|---|---|
userData | {appData}/elftia/ | Application data root |
dbPath | {userData}/elftia.db | SQLite database |
configDir | {userData}/config/ | Config file directory |
resourcesDir | {userData}/resources/ | Media resources |
diagnosticsDir | {userData}/diagnostics/ | Diagnostic data |
logsDir | {userData}/logs/ | Log files |
Related Files
| File | Description |
|---|---|
packages/desktop/app/main/index.ts | Main process entry; all service creation and startup |
packages/desktop/app/main/services/routers/index.ts | Route registration center, registerAllRouters() |
packages/desktop/app/main/services/routers/BaseRouter.ts | Router base class |
packages/desktop/app/main/ipc/safe-handle.ts | secureHandle IPC security wrapper |
packages/desktop/app/main/workers/DbClient.ts | Database Worker client |
packages/desktop/app/main/workers/db.worker.ts | Database Worker implementation |
packages/desktop/app/main/workers/types.ts | Worker RPC type definitions |
packages/desktop/app/main/services/infra/logger/LoggerService.ts | Logging service |
packages/desktop/app/main/services/platform/security/SecurityService.ts | Encryption service |
packages/desktop/app/main/services/infra/paths/paths.ts | Path management |
packages/desktop/app/main/services/agent-core/engine/EngineDispatcher.ts | Engine dispatcher |