Process model
Key architectural decisions
Electron multi-process isolation
Each window runs in a sandboxed renderer process. ThecontextBridge in the preload script exposes only a typed window.api surface — raw Node.js APIs are not accessible from renderer code.
Python subprocess engines
Both reasoning engines are Python programs launched as child processes. They communicate with the Electron main process via bridge scripts (nae-bridge.py, rlm-bridge.py) using a JSON-Lines protocol (newline-delimited JSON) over stdin/stdout. Each JSON object written to stdout by the bridge script is one message; each JSON object sent on stdin is one command. This isolates engine crashes from the UI process.
SQLite for local persistence
better-sqlite3 is used synchronously in the main process. The database lives in the OS-specific app data directory and stores sessions, skills, workflows, eval data, and non-secret settings.
OS encryption for secrets
Electron’s built-insafeStorage API encrypts all API keys and credentials. Encrypted blobs are stored in credentials.json in the OS-specific app data directory (not directly in the OS keychain as named entries). The underlying encryption uses the OS native mechanism — macOS Keychain, Windows DPAPI, or libsecret on Linux. The renderer process never receives raw key values — only masked versions for display.
Zustand for UI state
React state is managed with Zustand stores covering every major domain:chatStore, settingsStore, skillStore, workflowStore, evalStore, documentStore, mcpStore, activityStore, nativeAgentStore, rlmStore, and credentialStore. Each store communicates with the main process exclusively via the window.api IPC bridge.
Data flow for a chat message
Edit this page — Open a pull
request