# Understanding the Extension System Architecture in Modly: A Technical Deep Dive

> Explore Modly's extension system architecture, a four-layer security model for safe JavaScript and Python plugin execution in Electron. Learn about manifest validation, sandboxing, IPC, and runtime.

- Repository: [lightningpixel/modly](https://github.com/lightningpixel/modly)
- Tags: deep-dive
- Published: 2026-08-19

---

**Modly’s extension system architecture implements a four-layer security model comprising manifest validation, sandboxed filesystem isolation, type-safe IPC bridging, and workflow runtime execution, enabling JavaScript and Python plugins to run safely within an Electron environment.**

Modly is an open-source Electron-based application designed for extensible content generation workflows. The extension system architecture in Modly centers on a strict separation between **discovery/validation**, **state management**, **secure filesystem handling**, and **runtime execution**, ensuring that third-party plugins operate within controlled boundaries while maintaining seamless integration with the React frontend.

## Extension Types and Manifest Structure

All Modly extensions are defined by a JSON [`manifest.json`](https://github.com/lightningpixel/modly/blob/main/manifest.json) file and conform to one of two TypeScript interfaces defined in **[`src/shared/types/electron.d.ts`](https://github.com/lightningpixel/modly/blob/main/src/shared/types/electron.d.ts)**.

**ModelExtensions** expose one or more nodes that generate content (images, meshes, or other assets). **ProcessExtensions** provide a single entry point—either [`processor.js`](https://github.com/lightningpixel/modly/blob/main/processor.js) or a Python script—that executes custom logic on supplied inputs. This dichotomy allows Modly to support both generative AI models and utility processors within the same architectural framework.

The manifest must declare the extension `id`, `type` (model or process), and entry files. These definitions serve as the contract that the rest of the system uses to discover and load capabilities.

## Manifest Validation and Security Verification

Before any extension becomes active, Modly validates its integrity through **[`electron/main/extension-install-utils.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/extension-install-utils.ts)**. The `validateInstallManifest` function checks for required fields, verifies the presence of entry scripts, and ensures the declared extension type matches the actual filesystem structure.

This validation layer prevents malformed or incomplete extensions from entering the system. It also acts as the first gate in the security model, rejecting manifests that attempt to reference files outside the extension directory or declare invalid metadata.

## Secure Path Resolution and Filesystem Isolation

To prevent path-traversal attacks, Modly implements strict path guards in **[`electron/main/extension-path-guard.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/extension-path-guard.ts)**. The system uses `assertSafeExtensionId` and `resolvePathWithinRoot` to ensure all filesystem operations remain confined to the configurable `extensionsDir`.

The architecture maintains isolation through two mechanisms:
- **Extension ID sanitization** – User-provided IDs are validated to prevent directory traversal sequences
- **Root-relative resolution** – All paths are resolved relative to the extensions root, guaranteeing containment

During installation, Modly creates hidden staging directories (`.modly-staging-…`) and backup directories (`.modly-backup-…`) to facilitate atomic swaps and safe rollbacks if validation fails partway through.

## The IPC Bridge: Frontend-to-Main Communication

The React frontend communicates with the Electron main process through a preload-exposed API defined in **[`electron/preload/electron-api.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/electron-api.ts)** and typed in **[`src/shared/types/electron.d.ts`](https://github.com/lightningpixel/modly/blob/main/src/shared/types/electron.d.ts)**. The API surface exposed at `window.electron.extensions` includes:

- `list()` – Enumerate installed extensions
- `installFromGitHub(url)` and `installFromLocal()` – Installation sources
- `uninstall(id)`, `repair(id)`, and `reload()` – Lifecycle management
- `runProcess(id, input, params)` – Runtime invocation
- `onInstallProgress` / `offInstallProgress` – Event registration for progress tracking

This IPC bridge ensures that the renderer process never directly accesses the filesystem, maintaining the security boundary between untrusted extension code and the host system.

## State Management with Zustand

The frontend maintains extension state through a **Zustand** store located in **[`src/shared/stores/extensionsStore.ts`](https://github.com/lightningpixel/modly/blob/main/src/shared/stores/extensionsStore.ts)**. This store tracks:
- `modelExtensions` and `processExtensions` arrays
- Loading states, installation progress, and error conditions
- Helper actions including `loadExtensions`, `installFromGitHub`, `installFromLocal`, `uninstall`, and `reload`

By wrapping the IPC calls in a reactive store, Modly ensures UI components remain synchronized with the filesystem state without requiring manual event handling.

## Runtime Execution and Workflow Integration

When a workflow executes a node of type `extensionNode`, the system retrieves the appropriate extension via `getWorkflowExtension` and invokes `window.electron.extensions.runProcess`. This logic resides in **[`src/areas/workflows/workflowRunStore.ts`](https://github.com/lightningpixel/modly/blob/main/src/areas/workflows/workflowRunStore.ts)**.

The runtime flow follows this sequence:
1. The workflow engine identifies an extension node requiring execution
2. It retrieves the extension metadata from the Zustand store
3. It marshals inputs and parameters across the IPC boundary
4. The main process executes the entry script (JavaScript or Python) in a controlled environment
5. Results (file paths or text outputs) return to the workflow for downstream node consumption

## Atomic Installation and Recovery Mechanisms

Modly guarantees installation consistency through atomic operations. The system stages new extensions in temporary directories before validating contents. Only after successful validation does it perform an atomic move to the active extensions directory, with automatic rollback to backup versions if corruption is detected.

These staging and backup mechanisms, defined alongside the path guards in **[`electron/main/extension-path-guard.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/extension-path-guard.ts)**, ensure that the extension registry never references partially installed or corrupted extensions.

## Code Examples

### Listing and Installing Extensions

```typescript
import { useExtensionsStore } from '@shared/stores/extensionsStore';

// Load all extensions on application start
await useExtensionsStore.getState().loadExtensions();

// Install from GitHub repository
await useExtensionsStore.getState().installFromGitHub('https://github.com/user/my-extension');

// Access installation progress in React components
const { installProgress, installError } = useExtensionsStore();

```

### Executing a Process Extension from Workflow Code

```typescript
import { getWorkflowExtension } from '@shared/stores/extensionsStore';

async function runNode(node: WFNode, allExtensions: AnyExtension[]) {
  if (node.type !== 'extensionNode' || !node.data.enabled) return;
  
  const ext = getWorkflowExtension(node.data.extensionId ?? '', allExtensions);
  if (!ext) throw new Error('Extension not found');

  const input = { filePath: '/tmp/input.png' };
  const result = await window.electron.extensions.runProcess(
    ext.id, 
    input, 
    node.data.params
  );
  
  if (!result.success) throw new Error(result.error ?? 'Process failed');
  // Output available in result.result?.filePath or result.result?.text
}

```

### Validating Extension Paths Securely

```typescript
import { resolveExtensionPathWithinRoot } from '@electron/main/extension-path-guard';

const extensionsRoot = '/Users/me/.modly/extensions';
const safePath = resolveExtensionPathWithinRoot(extensionsRoot, userProvidedId);
// safePath is guaranteed to remain within extensionsRoot

```

## Summary

- **Type-safe contracts**: Extension interfaces (`ModelExtension`, `ProcessExtension`) and IPC definitions live in **[`src/shared/types/electron.d.ts`](https://github.com/lightningpixel/modly/blob/main/src/shared/types/electron.d.ts)**, ensuring compile-time safety across the main/renderer boundary.
- **Defense in depth**: Path traversal protection uses **[`electron/main/extension-path-guard.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/extension-path-guard.ts)** to enforce filesystem containment, while manifest validation in **[`electron/main/extension-install-utils.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/extension-install-utils.ts)** blocks malformed extensions.
- **State synchronization**: The Zustand store in **[`src/shared/stores/extensionsStore.ts`](https://github.com/lightningpixel/modly/blob/main/src/shared/stores/extensionsStore.ts)** provides reactive state management over the IPC bridge exposed through **[`electron/preload/electron-api.ts`](https://github.com/lightningpixel/modly/blob/main/electron/preload/electron-api.ts)**.
- **Workflow integration**: Runtime execution occurs through **[`src/areas/workflows/workflowRunStore.ts`](https://github.com/lightningpixel/modly/blob/main/src/areas/workflows/workflowRunStore.ts)**, which marshals data between extension scripts and the visual node graph.
- **Atomic operations**: Installation uses staging and backup directories to guarantee consistency, with automatic rollback on failure.

## Frequently Asked Questions

### What file defines the TypeScript contracts for Modly extensions?

The file **[`src/shared/types/electron.d.ts`](https://github.com/lightningpixel/modly/blob/main/src/shared/types/electron.d.ts)** contains the `ModelExtension` and `ProcessExtension` interface definitions, along with the `Window.electron.extensions` API surface that governs all IPC communication between the React frontend and Electron main process.

### How does Modly prevent extensions from accessing files outside their directory?

Modly implements path guards in **[`electron/main/extension-path-guard.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/extension-path-guard.ts)** using `assertSafeExtensionId` and `resolvePathWithinRoot`. These functions validate extension IDs and resolve all filesystem paths relative to the configured `extensionsDir`, throwing errors if traversal outside the root is attempted.

### What is the difference between Model Extensions and Process Extensions?

**Model extensions** expose multiple content-generation nodes (e.g., for images or meshes) and are represented by the `ModelExtension` interface. **Process extensions** expose a single entry point ([`processor.js`](https://github.com/lightningpixel/modly/blob/main/processor.js) or Python) that runs custom logic on inputs, represented by the `ProcessExtension` interface. Model extensions integrate with the node graph for generative tasks, while process extensions handle utility transformations.

### How does Modly handle failed or interrupted extension installations?

The system creates hidden `.modly-staging-…` directories during installation and maintains `.modly-backup-…` copies of existing versions. If validation fails or the process interrupts, Modly automatically rolls back to the backup version, ensuring the extensions registry never references corrupted or partial installations.