Concise reference for AI coding agents working in this repository.
Electron + Vue.js desktop app for AI inference on Intel GPUs. Multi-process architecture:
Electron main process orchestrates Vue.js frontend and multiple Python/native backend services
(AI Backend, ComfyUI, LlamaCPP, OpenVINO, Ollama). Frontend code lives in WebUI/.
- Use composition over inheritance — never introduce new class hierarchies.
- Do not use classes unless extending an existing set of classes of the same type.
- Use
typeinstead ofinterface, unless an interface is strictly necessary for implementation.
All commands run from the WebUI/ directory.
# Install dependencies
npm install
# Start dev server + Electron
npm run dev
# Run all tests once
npm test
# Run tests in watch mode
npm run test:watch
# Run a single test file
npx vitest run electron/test/subprocesses/deviceArch.test.ts
# Run tests matching a name pattern
npx vitest run --testNamePattern "getDeviceArch"
# Lint (ESLint with auto-fix)
npm run lint
# Lint without auto-fix (CI mode)
npm run lint:ci
# Format (Prettier)
npm run format
# Format check only (CI mode)
npm run format:ci
# TypeScript type-check (no emit)
npx vue-tsc --noEmit
# Full production build (Windows installer)
npm run fetch-external-resources
npm run buildPython backend (service/) uses Ruff for linting (runs in CI via GitHub Actions).
- Framework: Vitest 3.2+ with
nodeenvironment. - Test file pattern:
**/*.test.ts(not.spec.ts). - Path aliases:
@→./src,electron→./electron. - Tests use
describe/it/expect. Mock Electron withvi.mock('electron', ...). - Tests live alongside source in
electron/test/(currently unit tests for Electron main process only).
- No semicolons
- Single quotes
- 2-space indentation (spaces, not tabs)
- 100-character line width
- LF line endings
- Trailing whitespace trimmed, final newline inserted
- Target: ES2023, module: ESNext with bundler resolution.
- Strict mode enabled.
- Prefix unused variables/parameters with
_(e.g.,_event,_unused). Variables ending inSchemaare also exempt from unused-var checks. - Use
typeoverinterface(see Mandatory Rules above).
- Always use
<script setup lang="ts">with Composition API. - Define props with
defineProps<{ ... }>()using TypeScript generics. - Define emits with
defineEmits<{ ... }>()using TypeScript generics. - File naming: PascalCase (
MyComponent.vue). - Single-word component names are allowed (
vue/multi-word-component-namesis off).
- Use setup syntax:
defineStore('name', () => { ... }). - Enable persistence with
{ persist: true }option where needed. Properties picked for persistence need to be returned, even if they are not used externally. - Add HMR support:
if (import.meta.hot) import.meta.hot.accept(acceptHMRUpdate(...)). - Store files: camelCase in
WebUI/src/assets/js/store/(e.g.,backendServices.ts). - Store hooks use
useprefix:useBackendServices,useTextInference. - Stores may import other stores for composition.
No strict enforcement, but follow the prevailing convention:
- External packages (
vue,pinia,zod,@ai-sdk/*) - Internal stores (
@/assets/js/store/...) - Components (
@/components/...) - Utilities (
@/lib/utils,@/assets/js/toast)
| Element | Convention | Example |
|---|---|---|
| Vue components/files | PascalCase | ModelSelector.vue |
| Store files | camelCase | backendServices.ts |
| Functions/variables | camelCase | startService, currentStatus |
| Types | PascalCase | BackendStatus, ModelPaths |
| Store composables | use prefix |
useBackendServices() |
| Backend service names | kebab-case | 'ai-backend', 'comfyui-backend' |
| Python modules | snake_case | web_api.py, llm_biz.py |
- Wrap async operations in
try/catch. - Log errors with
console.error(). - Show user-facing errors via toast:
import * as toast from '@/assets/js/toast'thentoast.error(msg). - IPC handlers return
{ success: boolean, error?: string }pattern for error propagation. - Python backends: return
{"code": 0, "data": ...}on success,{"code": -1, "message": ...}on error.
vue/multi-word-component-names: offvue/require-v-for-key: warnvue/no-use-v-if-with-v-for: warn@typescript-eslint/no-this-alias: warn@typescript-eslint/no-unused-vars: error (unused prefixed with_are ignored)
WebUI/ # Electron + Vue.js frontend (all npm commands here)
electron/ # Electron main process (IPC, service registry, preload)
subprocesses/ # Backend service classes + langchain utility process
src/ # Vue.js app (components, views, stores, utils)
assets/js/store/ # Pinia stores (domain + implementation)
components/ # Reusable Vue components
views/ # Page-level Vue components (Chat, PromptArea, WorkflowResult)
external/ # Presets, workflows, external resources
service/ # Python Flask backend (model download/management, NOT inference)
LlamaCPP/ # LlamaCPP inference backend
OpenVINO/ # OpenVINO inference backend
Every new IPC command requires changes to exactly three files:
WebUI/electron/main.ts— addipcMain.handle()oripcMain.on()handlerWebUI/electron/preload.ts— expose viacontextBridge.exposeInMainWorld()WebUI/src/env.d.ts— add TypeScript type definition toelectronAPI
- ESLint + Prettier: runs on every push/PR (
eslint-prettier.yml) - Ruff: Python linting on
service/directory (ruff.yml) - Bandit: Python security scanning (
bandit.yml) - Trivy: Vulnerability scanning (
trivy.yml)
This section eliminates the need for codebase exploration at the start of each session.
There is no Vue Router. Navigation is state-driven:
App.vuechecksglobalSetup.loadingState(verifyBackend→manageInstallations→loading→running/failed)- Once running,
promptStore.currentModecontrols which view renders:chat→Chat.vue,imageGen/imageEdit/video→WorkflowResult.vue PromptArea.vueis the shared prompt input bar across all modes
Managed by electron/subprocesses/apiServiceRegistry.ts. Each service spawns a child process and exposes an OpenAI-compatible HTTP API:
| Service | Ports | Binary/Entry | Health Endpoint | Purpose |
|---|---|---|---|---|
ai-backend |
59000-59999 | service/web_api.py (Python Flask) |
/healthy |
Model downloading/management only — NOT inference |
llamacpp-backend |
39000-39999 | llama-server (native) |
/health |
GGUF model inference (LLM + embedding sub-servers) |
openvino-backend |
29000-29999 | ovms (native) |
/v2/health/ready |
OpenVINO inference (LLM + embedding + transcription sub-servers) |
comfyui-backend |
49000-49999 | ComfyUI main.py (Python) |
/queue |
Image/video/3D generation via workflows |
ollama-backend |
40000-41000 | ollama (native) |
/api/version |
Ollama inference (preview feature) |
-
Electron IPC (renderer ↔ main): ALL service lifecycle — start, stop, setup, device selection,
ensureBackendReadiness. Renderer callswindow.electronAPI.*, main handles viaipcMain.handle(). Main pushes events viawin.webContents.send(). -
Direct HTTP (renderer → backend): For actual AI operations after service is ready:
- Chat inference: Vercel AI SDK
streamText()→{backendUrl}/v1/chat/completions(LlamaCpp/OpenVINO/Ollama) - Model management:
fetch()→ Flask ai-backend/api/*(download, check, size) - Image generation:
fetch()→ ComfyUI/prompt,/upload/image,/interrupt,/free
- Chat inference: Vercel AI SDK
-
Utility process (main ↔ langchain worker):
electron/subprocesses/langchain.tsfor RAG document processing viaprocess.parentPortmessaging.
User sends message → textInference.ensureReadyForInference() → IPC ensureBackendReadiness (loads model on-demand) → openAiCompatibleChat uses Vercel AI SDK streamText() → direct HTTP to backend's /v1/chat/completions → streamed response.
Service lifecycle: getServices, startService, stopService, setUpService, serviceSetUpProgress (M→R), serviceInfoUpdate (M→R), uninstall, updateServiceSettings, detectDevices, selectDevice, ensureBackendReadiness
Models: loadModels, updateModelPaths, restorePathsSettings, getDownloadedGGUFLLMs, getDownloadedOpenVINOLLMModels, getDownloadedEmbeddingModels
Settings/config: getInitSetting, updateLocalSettings, getThemeSettings, getLocaleSettings, getInitialPage, getDemoModeSettings
Presets: reloadPresets, loadUserPresets, saveUserPreset, updatePresetsFromIntelRepo, getUserPresetsPath
RAG: addDocumentToRAGList, embedInputUsingRag, getEmbeddingServerUrl
ComfyUI tools: comfyui:isGitInstalled, comfyui:isComfyUIInstalled, comfyui:downloadCustomNode, comfyui:uninstallCustomNode, comfyui:installPypiPackage, comfyui:isPackageInstalled, comfyui:listInstalledCustomNodes
Transcription: startTranscriptionServer, stopTranscriptionServer, getTranscriptionServerUrl
Dialogs/files: showOpenDialog, showSaveDialog, showMessageBox, existsPath, saveImage
Window: getWinSize, setWinSize, miniWindow, setFullScreen, exitApp, zoomIn, zoomOut
Domain stores (core business logic):
textInference— LLM backend/model selection, RAG config, system prompt, context size, per-preset settings. Deps:backendServices,models,dialogs,presetsopenAiCompatibleChat— Vercel AI SDK chat instances, message streaming, tool calling, vision, token tracking. Deps:textInference,conversationsimageGenerationPresets— Image/video generation state (prompt, seed, dimensions, batch), ComfyUI dynamic inputs. Deps:presets,comfyUiPresets,backendServices,ui,dialogs,i18ncomfyUiPresets— ComfyUI WebSocket + REST communication, workflow execution, custom node management. Deps:imageGenerationPresets,i18n,backendServices,promptAreamodels— Model discovery, download checking, HuggingFace integration, path management. Deps:backendServicespresets— Unified preset system with Zod schemas (chat+comfytypes), variants, file I/O. Deps:backendServicesconversations— Conversation CRUD and persistence. No store deps.
Orchestration stores:
backendServices— Service lifecycle, device selection, version management. No store deps. Heavy IPC usage.presetSwitching— UnifiedswitchPreset(),switchVariant()across modes. Deps:presets,promptArea,backendServices,dialogs,globalSetup,i18n+ lazytextInference,imageGenerationPresetsglobalSetup— App initialization, loading state machine. Deps:modelspromptArea— Current UI mode (chat/imageGen/imageEdit/video), prompt submit/cancel callbacks. Deps:presetSwitching
Infrastructure stores (UI state, no business logic):
dialogs— Dialog visibility state (download, warning, requirements, installation progress, mask editor). No deps.ui— History panel visibility. No deps.theme— Theme selection. IPC:getThemeSettings. No deps.i18n— Locale/translations. IPC:getLocaleSettings. No deps.demoMode— Demo mode overlay + auto-reset timer. IPC:getDemoModeSettings. No deps.speechToText— STT enabled state, initialization. Deps:backendServices,models,dialogs,globalSetupaudioRecorder— Browser MediaRecorder, transcription via AI SDK. Deps:backendServices(lazy)ollama— Ollama model pull progress. Deps:textInferencedeveloperSettings— Dev console on startup toggle. No deps.
Chat/LLM: views/Chat.vue → stores: openAiCompatibleChat, textInference, conversations, presets → electron: ensureBackendReadiness IPC → backend: llamacpp/openvino/ollama via Vercel AI SDK
Image/Video Generation: views/WorkflowResult.vue → stores: imageGenerationPresets, comfyUiPresets, presets → electron: service lifecycle IPC → backend: comfyui-backend via direct HTTP
Model Management: stores: models → electron: loadModels, getDownloaded* IPC → backend: ai-backend Flask /api/* via HTTP
Settings: components/settings/SideModalAppSettings.vue, components/settings/SideModalSpecificSettings.vue → stores: backendServices, textInference, imageGenerationPresets, theme, i18n
Presets: components/PresetSelector.vue, components/VariantSelector.vue → stores: presets, presetSwitching
Service Management: components/InstallationManagement.vue → store: backendServices → electron: apiServiceRegistry.ts, electron/subprocesses/*.ts
| File | Purpose |
|---|---|
electron/main.ts |
Window creation, all IPC handlers (~68 channels), app lifecycle |
electron/preload.ts |
contextBridge exposing electronAPI to renderer |
electron/pathsManager.ts |
Singleton managing all app/model/service filesystem paths |
electron/remoteUpdates.ts |
Fetching model lists and preset updates from GitHub |
electron/subprocesses/apiServiceRegistry.ts |
Service registration, port allocation, lifecycle orchestration |
electron/subprocesses/service.ts |
Base classes: GenericService, ExecutableService, LongLivedPythonApiService |
electron/subprocesses/aiBackendService.ts |
Python Flask model-management backend |
electron/subprocesses/llamaCppBackendService.ts |
LlamaCPP native server (LLM + embedding sub-servers) |
electron/subprocesses/openVINOBackendService.ts |
OpenVINO OVMS (LLM + embedding + transcription sub-servers) |
electron/subprocesses/comfyUIBackendService.ts |
ComfyUI Python server |
electron/subprocesses/ollamaBackendService.ts |
Ollama binary (preview) |
electron/subprocesses/langchain.ts |
RAG utility process (document splitting, embedding, vector search) |
electron/subprocesses/deviceDetection.ts |
Intel GPU device detection and env var setup |
electron/logging/logger.ts |
Logging, sends debugLog events to renderer |