# Best Practices for Developing with the Motrix Codebase: A Complete Guide

> Master Motrix development with this guide. Learn to route window creation, isolate logic, secure IPC, and extend functionality via QuickJS plugins for efficient and secure Motrix codebase development.

- Repository: [Dr_rOot/Motrix](https://github.com/agalwood/Motrix)
- Tags: best-practices
- Published: 2026-08-20

---

**To develop efficiently with the Motrix codebase, always route window creation through the centralized `WindowManager` class, isolate business logic within the `src/core/` directory, enforce renderer URL policies for IPC security, and extend functionality via the sandboxed QuickJS plugin system using the MDXP protocol bridge.**

Motrix is a full-featured download manager built on Electron that cleanly separates concerns across main, renderer, and server processes. Whether you are contributing to the [agalwood/Motrix](https://github.com/agalwood/Motrix) repository or building plugins for the ecosystem, understanding these architectural boundaries is essential for writing secure, maintainable code.

## Understanding the Multi-Process Architecture

Motrix follows Electron's multi-process model with strict separation between native window management, UI rendering, and download engine logic.

### Main Process and Window Management

The main process handles all native OS interactions and window lifecycle events. According to the source code, you must never instantiate `BrowserWindow` directly; instead, use the centralized [`WindowManager`](https://github.com/agalwood/Motrix/blob/main/src/main/window/window-manager.ts) class.

- **Obtain windows via `WindowManager.open()`** — This ensures consistent creation, restoration, and bounds persistence across sessions.
- **Apply platform-specific options** — Use `buildPlatformOptions()` from [`src/main/window/platform-options.ts`](https://github.com/agalwood/Motrix/blob/main/src/main/window/platform-options.ts) to isolate OS-specific UI decisions from business logic.
- **Enforce security policies** — Pass a `rendererUrlPolicy` obtained from `getRendererUrlPolicy()` in [[`src/main/window/renderer-url-policy.ts`](https://github.com/agalwood/Motrix/blob/main/src/main/window/renderer-url-policy.ts)](https://github.com/agalwood/Motrix/blob/main/src/main/window/renderer-url-policy.ts) to every new window to prevent injection attacks.

### Renderer Process and Localization

The renderer process contains the React-based UI and must remain sandboxed from Node.js APIs.

- **Type-safe internationalization** — Import the `i18n` module from [[`src/renderer/lib/i18n.ts`](https://github.com/agalwood/Motrix/blob/main/src/renderer/lib/i18n.ts)](https://github.com/agalwood/Motrix/blob/main/src/renderer/lib/i18n.ts), which provides Zod-derived schemas guaranteeing UI strings are validated at compile-time.
- **Centralized formatting** — Use [`src/renderer/lib/format.ts`](https://github.com/agalwood/Motrix/blob/main/src/renderer/lib/format.ts) for number, size, and time formatting to avoid duplicating locale logic across components.

### Server and Core Logic

All download engine functionality lives outside the Electron main process, enabling Docker-ready headless deployment.

- **HTTP and RPC layer** — Express-style routing lives in [[`src/server/http/app.ts`](https://github.com/agalwood/Motrix/blob/main/src/server/http/app.ts)](https://github.com/agalwood/Motrix/blob/main/src/server/http/app.ts). This is the sole entry point for external communications, including web UI and MDXP clients.
- **Business logic isolation** — Keep all download-related business logic in the `src/core/` tree. For example, tracker health checks and automatic updates are coordinated by [[`src/core/tracker/tracker-manager.ts`](https://github.com/agalwood/Motrix/blob/main/src/core/tracker/tracker-manager.ts)](https://github.com/agalwood/Motrix/blob/main/src/core/tracker/tracker-manager.ts).
- **Task persistence** — The [`task-persistence.ts`](https://github.com/agalwood/Motrix/blob/main/task-persistence.ts) module provides a SQLite-backed store that survives application restarts.

## Secure Development Guidelines

Security in Motrix relies on strict validation at process boundaries.

- **Validate IPC channels** — Any IPC communication crossing process boundaries must be validated against the `rendererUrlPolicy`. This enforcement is implemented in [[`src/shared/protocol/bridge.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/bridge.ts)](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/bridge.ts).
- **Restrict renderer capabilities** — Never expose Node.js APIs directly to the renderer. All privileged operations must go through the preload script and the MDXP bridge.
- **Use type-safe schemas** — Motrix leverages **Zod** for runtime validation (see [`src/renderer/lib/json-schema-to-zod.ts`](https://github.com/agalwood/Motrix/blob/main/src/renderer/lib/json-schema-to-zod.ts)). Extend existing schemas rather than creating ad-hoc type definitions.

## Extending Functionality via the Plugin System

Motrix supports sandboxed plugins running in a QuickJS environment without Node.js access.

### MDXP Protocol and Aria2 Wrapper

- **Bridge layer** — The [[`src/shared/protocol/bridge.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/bridge.ts)](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/bridge.ts) converts MDXP JSON-RPC messages into internal commands. This is the only location where external JSON-RPC is parsed, making it the natural spot for validation.
- **Download engine abstraction** — Plugins must interact with the aria2 wrapper in [[`src/shared/platform/aria2.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/platform/aria2.ts)](https://github.com/agalwood/Motrix/blob/main/src/shared/platform/aria2.ts) rather than invoking aria2 directly.
- **Type definitions** — When adding capabilities, extend the TypeScript definitions in [[`src/shared/types/plugin.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/types/plugin.ts)](https://github.com/agalwood/Motrix/blob/main/src/shared/types/plugin.ts) and update [`src/shared/protocol/commands.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/commands.ts) so the bridge can forward new commands.

### Plugin Sandboxing

Plugins run in isolated QuickJS contexts. Declare required capabilities in [`motrix-plugin.json`](https://github.com/agalwood/Motrix/blob/main/motrix-plugin.json); Motrix will prompt users before granting them. Use the official `motrix-plugin` scaffolder (`pnpm create motrix-plugin`) to ensure manifests conform to the SDK specifications.

## Development Workflow and Testing

Efficient development requires understanding the build pipeline and testing hierarchy.

### Environment Setup

```bash

# Install prerequisites (Node ≥22, pnpm)

curl -fsSL https://get.pnpm.io/install.sh | sh
pnpm install

```

### Running and Debugging

```bash

# Development mode with hot-reloading for main and renderer processes

pnpm dev

# Unit tests with Vitest

pnpm test

# Integration and E2E tests with Playwright

pnpm test:e2e

```

### Code Quality

```bash

# Linting and formatting

pnpm lint

# Type checking without emission

pnpm typecheck

```

**Best practice:** Write unit tests against core modules (e.g., [`src/core/tracker/tracker-manager.test.ts`](https://github.com/agalwood/Motrix/blob/main/src/core/tracker/tracker-manager.test.ts)) before exposing new HTTP endpoints. Keep the CI pipeline fast by running only affected tests locally via `pnpm test:watch`.

## Practical Implementation Examples

### Adding a New Window Type

```typescript
// src/main/window/custom-window.ts
import { WindowManager } from './window-manager';
import { WINDOW_CONFIGS } from './window-configs';

export function createStatsWindow(manager: WindowManager) {
  // Register configuration in src/main/window/window-configs.ts first
  manager.open('stats', { show: true });
}

```

Always register new window configurations in `WINDOW_CONFIGS` before calling `manager.open()`.

### Extending the MDXP Bridge

```typescript
// src/shared/protocol/commands.ts
export const Commands = {
  ...ExistingCommands,
  GetServerHealth: 'getServerHealth',
};

```

```typescript
// src/server/http/app.ts
router.post('/rpc', async (req, res) => {
  const { method, params } = req.body;
  if (method === Commands.GetServerHealth) {
    const health = await getServerHealth(); // core function from src/core/
    return res.json({ result: health });
  }
  // Fallback to existing bridge handler
});

```

### Implementing a Simple Plugin

```typescript
// my-plugin/src/index.ts
import { definePlugin } from '@motrix/plugin-api';

export default definePlugin({
  id: 'hello-world',
  version: '0.1.0',
  manifest: {
    name: 'Hello World',
    capabilities: ['readNetwork'],
    activationEvents: ['onAddTask'],
  },
  async onAddTask(context) {
    console.log('New task added:', context.task);
    // Modify task before processing
    context.task.url = context.task.url.replace('http://', 'https://');
  },
});

```

## Summary

- **Centralize window management** — Always use `WindowManager.open()` from [[`src/main/window/window-manager.ts`](https://github.com/agalwood/Motrix/blob/main/src/main/window/window-manager.ts)](https://github.com/agalwood/Motrix/blob/main/src/main/window/window-manager.ts) rather than instantiating `BrowserWindow` directly.
- **Isolate business logic** — Keep download engine code in `src/core/` and HTTP routing in [[`src/server/http/app.ts`](https://github.com/agalwood/Motrix/blob/main/src/server/http/app.ts)](https://github.com/agalwood/Motrix/blob/main/src/server/http/app.ts).
- **Enforce security policies** — Validate all IPC against the `rendererUrlPolicy` defined in [[`src/main/window/renderer-url-policy.ts`](https://github.com/agalwood/Motrix/blob/main/src/main/window/renderer-url-policy.ts)](https://github.com/agalwood/Motrix/blob/main/src/main/window/renderer-url-policy.ts).
- **Use type-safe i18n** — Import formatting utilities from [[`src/renderer/lib/i18n.ts`](https://github.com/agalwood/Motrix/blob/main/src/renderer/lib/i18n.ts)](https://github.com/agalwood/Motrix/blob/main/src/renderer/lib/i18n.ts) to handle localization.
- **Develop plugins safely** — Extend functionality via the MDXP bridge in [[`src/shared/protocol/bridge.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/bridge.ts)](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/bridge.ts) and the aria2 wrapper in [[`src/shared/platform/aria2.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/platform/aria2.ts)](https://github.com/agalwood/Motrix/blob/main/src/shared/platform/aria2.ts), respecting QuickJS sandbox limitations.

## Frequently Asked Questions

### How do I add a new window type to Motrix?

Register the window configuration in [`src/main/window/window-configs.ts`](https://github.com/agalwood/Motrix/blob/main/src/main/window/window-configs.ts), then obtain an instance via `WindowManager.open('yourWindowId')` in [[`src/main/window/window-manager.ts`](https://github.com/agalwood/Motrix/blob/main/src/main/window/window-manager.ts)](https://github.com/agalwood/Motrix/blob/main/src/main/window/window-manager.ts). Never instantiate `BrowserWindow` directly to ensure proper lifecycle management and security policy enforcement.

### What is the correct way to add a new RPC command?

Add the command string to [`src/shared/protocol/commands.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/commands.ts), then implement the handler in [[`src/server/http/app.ts`](https://github.com/agalwood/Motrix/blob/main/src/server/http/app.ts)](https://github.com/agalwood/Motrix/blob/main/src/server/http/app.ts). Delegate to functions in `src/core/` for business logic rather than implementing logic directly in the HTTP layer.

### Can I access Node.js APIs from a Motrix plugin?

No. Plugins run in a sandboxed QuickJS environment with no Node.js APIs available. You must declare required capabilities in [`motrix-plugin.json`](https://github.com/agalwood/Motrix/blob/main/motrix-plugin.json) and interact with the system through the MDXP bridge defined in [[`src/shared/protocol/bridge.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/bridge.ts)](https://github.com/agalwood/Motrix/blob/main/src/shared/protocol/bridge.ts) and the type definitions in [[`src/shared/types/plugin.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/types/plugin.ts)](https://github.com/agalwood/Motrix/blob/main/src/shared/types/plugin.ts).

### How does Motrix handle tracker management?

Tracker health checks and updates are coordinated by [[`src/core/tracker/tracker-manager.ts`](https://github.com/agalwood/Motrix/blob/main/src/core/tracker/tracker-manager.ts)](https://github.com/agalwood/Motrix/blob/main/src/core/tracker/tracker-manager.ts). This module runs in the server process, separate from the Electron main process, and persists state via the SQLite-backed task persistence layer.