# How the Local Inference Client Interacts with the Electron Main Process in Open-Generative-AI

> Discover how the local inference client connects with the Electron main process in Open-Generative-AI. Learn about IPC bridge, ipcRenderer invoke and ipcRenderer on.

- Repository: [Anil Chandra Naidu Matcha/Open-Generative-AI](https://github.com/Anil-matcha/Open-Generative-AI)
- Tags: internals
- Published: 2026-04-24

---

**The local inference client communicates with the Electron main process through a secure IPC bridge that exposes `window.localAI` to the renderer, using `ipcRenderer.invoke` for request-response patterns and `ipcRenderer.on` for streaming progress events.**

The Open-Generative-AI repository implements a three-layer architecture that separates the React frontend from privileged Node.js operations. This design allows the same UI code to run in web-only mode while enabling powerful local inference when wrapped in Electron.

## Architecture Overview

The IPC stack consists of three distinct layers that handle communication between the renderer and main process:

- **Preload Bridge** ([`electron/preload.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/electron/preload.js)): Exposes a safe `window.localAI` API using `contextBridge`
- **Renderer Client** ([`src/lib/localInferenceClient.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/src/lib/localInferenceClient.js)): Wraps bridge calls with availability checks and callbacks
- **Main Process Handlers** ([`electron/lib/localInference.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/electron/lib/localInference.js)): Implements filesystem operations, binary management, and generation logic

This structure ensures that the renderer process never accesses Node.js APIs directly, maintaining Electron's security model while enabling complex operations like downloading the `sd-cli` binary and spawning image generation tasks.

## The Preload Bridge

The [`electron/preload.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/electron/preload.js) file creates the secure connection point between frontend and backend. It uses `contextBridge.exposeInMainWorld` to inject a `localAI` object containing methods that wrap `ipcRenderer`.

```javascript
// electron/preload.js
onDownloadProgress: (callback) => {
  const listener = (_, data) => callback(data);
  ipcRenderer.on('local-ai:download-progress', listener);
  return () => ipcRenderer.removeListener('local-ai:download-progress', listener);
},

```

The bridge exposes functions like `listModels()`, `downloadModel()`, and `generate()`, each mapping to specific IPC channels prefixed with `local-ai:`.

## The Renderer Client

The [`src/lib/localInferenceClient.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/src/lib/localInferenceClient.js) file provides the frontend interface. It first checks for the bridge's presence to determine if the app is running in Electron or web mode.

```javascript
// src/lib/localInferenceClient.js
export const isLocalAIAvailable = () =>
  typeof window !== 'undefined' && !!window.localAI?.isElectron;

```

When available, the client forwards method calls to `window.localAI`, which then triggers the underlying IPC mechanisms. This abstraction allows components to call `localAI.listModels()` without knowing the implementation details.

## Main Process Handlers

The [`electron/lib/localInference.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/electron/lib/localInference.js) file registers IPC handlers using `ipcMain.handle` and manages the actual execution of local inference tasks. The `register()` function sets up listeners for all supported operations.

```javascript
// electron/lib/localInference.js
function register() {
  ipcMain.handle('local-ai:list-models', () => listModels());
}

```

For long-running operations, the main process pushes progress updates to the renderer using `webContents.send`. During binary downloads, it emits events on the `local-ai:download-progress` channel with payload containing `id`, `phase`, and `progress` fields.

## Communication Flows

### Request-Response Pattern

Synchronous operations follow a standard invoke/handle cycle:

1. Renderer calls `window.localAI.listModels()`
2. Preload bridge executes `ipcRenderer.invoke('local-ai:list-models')`
3. Main process handler executes `listModels()` and returns the array
4. Promise resolves in the renderer with available model data

### Event-Driven Updates

For asynchronous progress tracking, the system uses one-way event emission:

- Main process calls `mainWindow?.webContents.send('local-ai:download-progress', data)`
- Preload bridge receives via `ipcRenderer.on` and forwards to the registered callback
- Renderer client unsubscribes using the cleanup function returned during subscription

## Implementation Example

Here is a complete React component demonstrating the client usage:

```javascript
import { localAI } from '@/lib/localInferenceClient';

// Check that the Electron bridge is present
if (!localAI) {
  console.warn('Running in web-only mode – local inference unavailable.');
}

// Load the model list on mount
useEffect(() => {
  async function load() {
    const models = await localAI.listModels();
    setModels(models);
  }
  load();
}, []);

// Subscribe to download progress
useEffect(() => {
  const unsub = localAI.onDownloadProgress((data) => {
    console.log('Download progress:', data);
    // data: { id, phase, progress }
  });
  return unsub;
}, []);

// Trigger a generation
async function generateImage(prompt) {
  const result = await localAI.generate({
    model: 'z-image-1',
    prompt,
    steps: 30,
    guidance_scale: 7.5,
    aspect_ratio: '1:1',
  });
  // result: { url: 'data:image/png;base64,...', seed }
  setImageSrc(result.url);
}

```

## Summary

- **The local inference client** relies on [`electron/preload.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/electron/preload.js) to safely expose IPC capabilities to the renderer process.
- **Availability detection** via `isLocalAIAvailable()` ensures graceful degradation in web-only environments.
- **Request handling** uses `ipcMain.handle` in [`electron/lib/localInference.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/electron/lib/localInference.js) for operations like `listModels()` and `generate()`.
- **Progress streaming** employs `webContents.send` from the main process to push real-time updates through the preload bridge.
- **Binary management** occurs entirely in the main process, which downloads the `sd-cli` executable and manages model files via [`electron/lib/modelCatalog.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/electron/lib/modelCatalog.js).

## Frequently Asked Questions

### How does the renderer know if local inference is available?

The renderer checks `window.localAI?.isElectron` via the `isLocalAIAvailable()` function in [`src/lib/localInferenceClient.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/src/lib/localInferenceClient.js). This boolean indicates whether the preload bridge injected the API, confirming the app is running inside Electron rather than a standard browser.

### Can the frontend directly access the filesystem or spawn processes?

No. According to Electron's security architecture implemented in this repository, the renderer process cannot access Node.js APIs directly. All filesystem operations and binary spawning occur in [`electron/lib/localInference.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/electron/lib/localInference.js) within the main process, which receives sanitized parameters through IPC channels and returns results via promises.

### What happens if a user downloads a model while generating an image?

The main process handles both operations concurrently. Download progress events stream via `local-ai:download-progress` while generation updates use `local-ai:progress`. Both channels operate independently, allowing the UI to display multiple progress indicators simultaneously without blocking the main thread.

### Where is the sd-cli binary actually downloaded and executed?

The [`electron/lib/localInference.js`](https://github.com/Anil-matcha/Open-Generative-AI/blob/main/electron/lib/localInference.js) file manages the binary lifecycle. It downloads the `sd-cli` executable to the application's data directory, verifies its presence, and spawns it as a child process when `generate()` is called, capturing stdout to stream progress back to the renderer.