Purpose
ManyAI Desktop is an Electron-based desktop application providing a unified, multi-tab AI chat interface that routes user requests to multiple free and paid AI providers based on task type, provider health, and user configuration. It extends the ManyAI mobile concept with a richer workflow system, integrated built-in modules (IRC, terminal, RSS, programming), smart routing with health-aware scoring, MCP client integration for external tool servers, and SQLite-backed persistence for chat history and audit logs.
Tech Stack
| Component | Technology |
|---|---|
| Runtime | Electron |
| UI Framework | React 18 + TypeScript |
| Build system | electron-vite (Vite-based HMR) |
| Packaging | electron-builder |
| Internationalization | i18next (27 locales) |
| Local database | better-sqlite3 (WAL mode) — chat history, routing log, agent audit |
| MCP client | @modelcontextprotocol/sdk@1.29.0 |
Application Architecture (3 Layers)
Layer 1: Main Process (src/main/)
Node.js / Electron process with full OS access.
- Window management: Creates BrowserWindow with persisted state (
userData/window-state.json). Saves/restores x, y, width, height, isMaximized. Clamps to minimum 600×500. Corrects off-screen positions by checking nearest display bounds. - IPC registration:
registerAllIpc()wires all IPC handler modules at startup. - MCP startup:
mcpManager.connectAll()reconnects all saved MCP server configs after IPC registration. - Security:
webSecurity: false(CORS bypass — acceptable for a desktop app calling user-owned APIs).autoHideMenuBar: true. - Theme:
backgroundColor: '#1a1a2e'prevents white flash before React renders. - macOS: Handles
activateevent to re-create window when dock icon clicked with no windows open.
IPC modules in src/main/ipc/:
| Module | Handles |
|---|---|
fileIpc.ts | File system read/write/list/rename/delete operations |
imageIpc.ts | Image fetching and local image reading (CORS bypass + base64 encode) |
ircIpc.ts | IRC client connection, channel join, message send/receive |
terminalIpc.ts | Terminal command execution |
dbIpc.ts | SQLite operations — messages, routing log, agent audit (7 channels) |
mcpIpc.ts | MCP server management — list/add/remove/reconnect/list-tools/call-tool (6 channels) |
index.ts | registerAllIpc() — calls all module register functions |
Layer 2: Preload (src/preload/)
Secure bridge using contextBridge — raw ipcRenderer is never exposed to the renderer. Exposes window.api:
| API Group | Module | Purpose |
|---|---|---|
| file ops | api/files.ts | File CRUD, rename, delete, directory list |
| image ops | api/images.ts | Image fetching (CORS-safe via main) + local image reading |
| IRC | api/irc.ts | IRC client actions |
| terminal | api/terminal.ts | Terminal commands |
| database | api/db.ts | SQLite — addMessage, getMessages, clearMessages, logRouting, getRoutingStats, logAgent, getAgentLog |
| MCP | api/mcp.ts | MCP server management — listServers, addServer, removeServer, reconnect, listTools, callTool |
| config | index.ts | Durable config file (workingDir etc.) via api.getConfig() / api.setConfig() |
TypeScript definitions in src/preload/index.d.ts. Shared MCP types in src/preload/types/mcp.ts.
Layer 3: Renderer (src/renderer/src/)
React application. No direct Node/Electron access — all system calls go through window.api. Feature modules in features/:
| Feature | Description |
|---|---|
chat/ChatScreen.tsx | Main chat interface, multi-provider routing, file attachment, SQLite message persistence |
chat/fileHandler.ts | File drag-drop and attachment logic |
editor/SavedScreen.tsx | Saved responses viewer and editor |
irc/IrcScreen.tsx | IRC client UI (built-in module, loaded via Settings → Built-in) |
rss/RssScreen.tsx | RSS feed reader (built-in module) |
terminal/TerminalScreen.tsx | Integrated terminal (built-in module) |
programming/ProgrammingScreen.tsx | Autonomous coding agent with file tree, Browse + Refresh buttons (built-in module) |
settings/SettingsScreen.tsx | Settings hub — tabs: General / Providers / Built-in / MCP / Workflows / Smart Routing / Health / Backup / About |
settings/McpScreen.tsx | MCP server config UI — add/edit/remove/reconnect, tool list viewer |
Provider Registry
Providers defined in providers/*.json (one file per provider): anthropic, cerebras, cloudflare, cohere, fireworks, gemini, groq, huggingface, laptop (local Ollama), mistral, openai, openrouter, pollinations, sambanova.
Each provider JSON defines: name, baseUrl, models (each with id, name, capabilities[]), apiFormat, and systemPromptStyle. capabilities drives workflow routing. systemPromptStyle declares how system prompts are sent to the provider's API:
| Value | Behavior | Providers |
|---|---|---|
system-role | Prepend { role: "system", content } to messages array (default) | OpenAI, Groq, Mistral, etc. |
system-field | Top-level system string field in request body | Anthropic |
system-instruction | Top-level systemInstruction: { parts: [{ text }] } in request body | Gemini |
The application is a generic executor — it reads systemPromptStyle from JSON and applies the correct API shape. All provider-specific behaviour is declared in the JSON file, not hardcoded by provider name. The add/edit provider form exposes this field as a dropdown.
Built-in Modules (4) — opt-in via Settings → Built-in tab
IRC, RSS, Terminal, and Programming are modular built-ins. They are not workflow-picker items. Each has a checkbox in Settings → Built-in; checking it opens a tab, unchecking closes all tabs of that type. Toggle state is derived from tabs.some(t => t.workflowType === type) — no separate enabled flag.
| Type | Label | Use case |
|---|---|---|
irc | IRC 💬 | IRC client — raw TCP via main process, publishes to workflowBus |
rss | RSS 📰 | RSS feed reader — publishes to workflowBus |
terminal | Terminal 🖥️ | SSH/Telnet/SFTP/FTP client — xterm.js + ssh2 + basic-ftp |
programming | Programming ⚙️ | Autonomous coding agent — agentLoop with 9 native tools + dynamic MCP tools; file tree with Browse + Refresh |
Workflow System (6 file-backed)
File-backed workflows are seeded to {workingDir}/workflows/*.json on first run and user-editable. They appear in the New Tab picker (enabledUserWorkflows() excludes built-in types).
| Type | Label | Use case |
|---|---|---|
image | Image | Image generation |
coding | Code | Code generation and explanation |
reasoning | Reasoning | Deep analysis and logic |
creative | Creative | Writing, brainstorming |
summarization | Summarize | Long text compression |
translation | Translate | Language translation |
MCP Subsystem
McpClientManager (singleton in main process) manages connections to external MCP servers. Configs persisted to userData/mcp-servers.json. All servers reconnect on app start. Tools are discovered dynamically at agent run time and merged into the tool list sent to the model. See MCP Tools blueprint for full details.
Routing System
Manual routing (default): Per-workflow RouteEntry chain (provider + model + enabled + instanceId). Built-in routes stored in localStorage. Custom workflow routes stored in their JSON files.
Smart Routing (opt-in): Scores providers 0–1 using success rate, speed, and health penalty. Three modes: best-first, serial, parallel.
Health System
lib/healthCheck.ts polls provider endpoints on a configurable interval. Records uptime percentage and average latency per provider. getPenalty(provider) returns a 0–1 penalty used by smartRouter.scoreProvider(). Continuous monitoring runs on a timer in App.tsx re-reading config each tick so interval changes take effect without restart.
Persistence
| Storage | Contents |
|---|---|
localStorage | Tabs, active tab, continuous mode, routing prefs, smart routing config+log, provider order, enabled state, selected models, theme, zoom, font |
localStorage (encrypted via safeStorage) | API keys |
userData/manyai.db (SQLite) | Chat messages per tab, routing log, agent audit log |
userData/window-state.json | Window position and size |
userData/config.json | workingDir and other durable settings |
userData/mcp-servers.json | MCP server configurations |
providers/*.json | Provider + model registry (in repo) |
{workingDir}/workflows/*.json | Custom workflow definitions + routes |
Internationalization
27 locale files in src/renderer/src/i18n/locales/. Includes RTL locales (Arabic, Hebrew). scripts/gen-translations.py generates/updates locale files.
Tab System
- Tabs:
ChatTab[]withid,label,workflowType. Persisted tolocalStorage(manyai_chat_tabs,manyai_active_tab). - Old tabs without
workflowTypeare migrated to'coding'on load. - Default first tab:
{ workflowType: 'coding', label: 'Code' }. workflowBuspub/sub: non-chat features can inject content into any tab by tab ID or'active'.continuousMap: per-workflow flag for agent continuous mode.- Built-in tabs (IRC, terminal, RSS, programming) are toggled via Settings → Built-in checkboxes, not the New Tab picker.
- Settings panel slides in as an overlay — not a tab, toggled by
panelstate inApp.tsx.