This document describes the Electron desktop application implementation of Prompt Optimizer, detailing how the shared codebase is adapted to run as a native desktop application across Windows, macOS, and Linux platforms. The desktop architecture provides full Node.js capabilities, bypassing CORS restrictions and enabling local file storage.
For information about the shared UI components, see User Interface Layer. For deployment and release workflow, see Desktop Distribution. For environment configuration, see Environment Configuration and API Keys.
The Electron desktop application implements a secure three-tier architecture that separates concerns while enabling efficient communication between the Vue.js UI and Node.js services.
Sources: packages/desktop/main.js1-100 packages/desktop/preload.js1-100 packages/core/src/services/prompt/electron-proxy.ts1-126
| Process | Responsibility | Security Level | Storage Access |
|---|---|---|---|
| Main Process | Core services initialization, IPC handling, file I/O, network requests | Full Node.js privileges | Direct filesystem access via FileStorageProvider |
| Preload Script | Secure IPC bridge, API exposure via contextBridge, error normalization | Restricted context with access to both Node.js and DOM APIs | None (acts as pure bridge) |
| Renderer Process | Vue UI rendering, user interaction, proxy-based service access | Sandboxed Chromium environment | None (communicates via IPC) |
Sources: packages/desktop/main.js405-526 packages/desktop/preload.js88-239
The main process (main.js) is responsible for initializing all core services with the FileStorageProvider and exposing them via IPC handlers.
Sources: packages/desktop/main.js528-649 packages/desktop/main.js54-73
The desktop application uses FileStorageProvider to persist data in the Electron userData directory, which is platform-specific:
| Platform | Default userData Path |
|---|---|
| Windows | %APPDATA%\PromptOptimizer |
| macOS | ~/Library/Application Support/PromptOptimizer |
| Linux | ~/.config/PromptOptimizer |
Each manager (ModelManager, TemplateManager, etc.) stores its data in separate JSON files within this directory, with automatic backup files (.backup suffix) for data recovery.
Sources: packages/desktop/main.js589-594 packages/core/src/services/storage/file-storage-provider.ts
The desktop application scans environment variables at startup to inject runtime configuration into the renderer process:
The function buildRuntimeConfigScriptFromEnv() scans for all VITE_* environment variables and creates both prefixed and unprefixed keys in window.runtime_config, ensuring compatibility with both the web build (which expects VITE_ prefix via Vite) and the desktop runtime.
Sources: packages/desktop/main.js355-378 packages/desktop/main.js533-587
The desktop application uses Electron's IPC (Inter-Process Communication) mechanism to enable the renderer process to access core services running in the main process.
Sources: packages/desktop/preload.js242-340 packages/desktop/main.js753-845
All IPC handlers follow a consistent response pattern to enable structured error handling:
This pattern ensures that:
code and params for i18n translationSources: packages/desktop/main.js652-689 packages/desktop/preload.js43-78
Streaming responses (e.g., LLM text generation) use a unique pattern with per-stream event channels:
Each streaming request generates a unique streamId (e.g., stream_1234567890_abc123def) to multiplex multiple concurrent streams without channel conflicts.
Sources: packages/desktop/preload.js135-180 packages/desktop/main.js1004-1092
The renderer process uses proxy classes to access main process services. These proxies implement the same interfaces as the core services but delegate calls via IPC.
The proxy classes automatically serialize Vue reactive objects before sending them over IPC:
This prevents IPC serialization errors that would occur if Vue reactive proxies were transmitted directly.
Sources: packages/core/src/services/prompt/electron-proxy.ts1-126 packages/core/src/utils/ipc-serialization.ts packages/desktop/main.js76-99
The UI package uses conditional service factories to create either native or proxy instances based on the runtime environment:
Sources: packages/ui/src/composables/system/useServiceInitialization.ts packages/core/src/services/prompt/electron-proxy.ts12-15
The desktop application uses FileStorageProvider for persistent storage, implementing atomic writes and backup recovery mechanisms.
The desktop application implements a multi-layered shutdown strategy to ensure data integrity:
This layered approach ensures:
Sources: packages/desktop/main.js171-189 packages/desktop/main.js472-519
The desktop application exposes storage diagnostics via IPC:
This API is used by DataManager.vue to display storage statistics and provide a "Open Directory" button for manual file inspection.
Sources: packages/ui/src/types/electron.d.ts177-194 packages/ui/src/components/DataManager.vue299-324
The desktop application solves CORS restrictions by running network requests in the main process with full Node.js privileges.
The proxy setup occurs in the setupGlobalProxyDispatcherFromSystem() function, which:
undici ProxyAgent or direct AgentThis ensures that LLM SDK requests (OpenAI, Gemini, Anthropic) automatically respect system proxy settings without requiring user configuration.
Sources: packages/desktop/main.js190-276 packages/desktop/main.js622
Unlike the web version, the desktop application has no CORS restrictions because:
Origin: headers that trigger CORS preflightlocalhost:11434) work without CORS headersSources: packages/desktop/main.js624-630 Diagram 4 from high-level architecture
The desktop application uses electron-builder for packaging and distribution across multiple platforms.
| Configuration | Value | Description |
|---|---|---|
| appId | com.promptoptimizer.desktop | Unique application identifier |
| productName | PromptOptimizer | Display name in OS |
| directories.output | dist | Build output directory |
| publish.provider | github | Auto-update provider |
| files | main.js, preload.js, config/**/*, web-dist/**/*, node_modules/**/* | Included files |
Windows:
macOS:
Linux:
Sources: packages/desktop/package.json32-91 packages/desktop/package.json11-16
The desktop build process integrates with GitHub Actions for automated releases:
Sources: .github/workflows/release.yml packages/desktop/package.json45-50
The desktop application implements Electron security best practices with context isolation and limited API exposure.
The main window is created with secure defaults:
This configuration ensures:
require(), fs, etc.contextBridge are accessibleSources: packages/desktop/main.js405-414 packages/desktop/preload.js88
Environment variables are safely injected into the renderer via webContents.executeJavaScript() rather than exposing process.env directly:
This approach:
VITE_* prefixed variables onlySources: packages/desktop/main.js355-378
All IPC calls in the preload script are wrapped with timeout protection to prevent indefinite hanging:
This ensures that renderer-side calls fail fast rather than blocking the UI indefinitely if the main process encounters issues.
Sources: packages/desktop/preload.js24-36
Electron does not provide native-like context menus by default. The desktop application implements localized right-click menus for text inputs:
The menu labels are dynamically generated based on the current UI locale:
The UI locale is synchronized from the renderer process via IPC:
Sources: packages/desktop/main.js107-170 packages/desktop/main.js419-452 packages/ui/src/plugins/i18n.ts42-63
This desktop application architecture provides a robust, secure, and high-performance implementation of Prompt Optimizer as a native desktop application, leveraging Electron's capabilities while maintaining the shared UI and core logic from the monorepo.
Refresh this wiki