# How to Deploy Embedded Services with OmniRoute: A Complete Guide

> Deploy embedded services like local LLMs or vector stores with OmniRoute. This guide details using the ServiceSupervisor for process management and safe installations. Learn how to run auxiliary binaries effortlessly.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-24

---

**OmniRoute’s embedded-services layer lets you run auxiliary binaries (local LLMs, vector stores, or custom tools) alongside the main proxy using a managed ServiceSupervisor that handles process lifecycle, health checks, and safe npm installations.**

OmniRoute ships with a lightweight embedded-services architecture that enables running auxiliary binaries directly within the application process tree. According to the diegosouzapw/OmniRoute source code, this system uses a ServiceSupervisor to manage child processes, a registry for service discovery, and installer utilities for safe dependency management. This guide explains how to deploy embedded services with OmniRoute using the actual implementation details found in the repository.

## Architecture Overview

The embedded-services system in OmniRoute centers on three core components that work together to isolate, manage, and expose auxiliary binaries.

**ServiceSupervisor** handles process lifecycle management, including startup, monitoring, and graceful shutdown. Located in [`src/lib/services/types.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/types.ts), this class records PID, exit status, and startup errors in the `services` database table while ensuring child processes spawn with minimal environment variables and no shell interpolation (Hard Rule #13).

**Installer utilities** provide a vetted `runNpm` wrapper in [`src/lib/services/installers/utils.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/installers/utils.ts) that executes safe `npm install` operations inside service directories, handling platform-specific quirks and reporting failures without exposing the system to arbitrary shell commands.

**Service registry** maintains the canonical list of available services in [`src/lib/services/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/registry.ts), mapping service IDs to binary paths, default arguments, and health-check endpoints so the router can treat local binaries like external API providers.

## Registering an Embedded Service in the Registry

Before OmniRoute can manage a binary, you must declare it in the service registry. The registry exports an array of service definitions that the router consults to resolve backend plugin IDs.

```typescript
// src/lib/services/registry.ts
export const serviceRegistry = [
  {
    id: "ninerouter",
    name: "9Router",
    binary: "node",
    args: ["-r", "./src/ninerouter/main.js"],
    healthCheck: "http://127.0.0.1:8000/health",
    enabled: true,
  },
];

```

Each entry requires:

- **id**: Unique identifier used in API routes and lookup functions
- **binary**: Executable command (e.g., `node`, `python`, or absolute path)
- **args**: Array of arguments passed directly to spawn without shell interpolation
- **healthCheck**: HTTP endpoint for liveness verification
- **enabled**: Boolean flag controlling whether the supervisor attempts to start the service

## Managing the Service Lifecycle with ServiceSupervisor

The `ServiceSupervisor` class in [`src/lib/services/types.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/types.ts) encapsulates process isolation and teardown guarantees. When a request targets an embedded service, the supervisor ensures the binary is running by spawning it on-demand with a sanitized environment.

```typescript
// src/lib/services/types.ts
export class ServiceSupervisor {
  constructor(private readonly config: ServiceConfig) {}
  
  async start(): Promise<void> {
    // Spawn with safe env, capture stdout/stderr
    this.process = spawn(this.config.binary, this.config.args, {
      env: { ...process.env, NODE_ENV: "production" },
    });
    
    // Hook into exit events and update the DB row
    this.process.on("exit", (code) => updateServiceStatus(this.config.id, code));
  }
  
  async stop(): Promise<void> {
    this.process?.kill("SIGTERM");
    await once(this.process!, "close");
  }
}

```

**Graceful teardown** occurs when the OmniRoute server shuts down: `ServiceSupervisor.stopAll()` sends `SIGTERM` to each child and waits for the `close` event, preventing orphaned processes. The database schema in [`src/lib/db/migrations/071_services.sql`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/migrations/071_services.sql) persists process state across restarts.

## Installing Dependencies Safely

Embedded services often require external npm packages. Rather than running arbitrary install commands, OmniRoute provides a controlled installation pathway through the CLI.

```bash

# From the repo root

npm run service:install -- --name=my-service --repo=https://github.com/example/my-service.git

```

Underlying this command is the `runNpm` utility in [`src/lib/services/installers/utils.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/installers/utils.ts), which performs platform-aware `npm install` operations inside the service's directory while validating paths and capturing errors. This approach prevents command injection and ensures reproducible installations across development and production environments.

## Request Routing and Security Model

When a client requests an embedded service, the flow traverses multiple layers to ensure security and proper translation:

1. **API route capture**: Requests like `GET /v1/providers/<service>/models` hit the generic provider-router in `open-sse/services/`.
2. **Registry resolution**: The router checks [`src/lib/services/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/registry.ts) to resolve the service's backend plugin ID.
3. **Process guarantee**: If the service is marked `enabled`, the `ServiceSupervisor` verifies the binary is running (spawning it if necessary).
4. **Local forwarding**: The request proxies to `http://127.0.0.1:<port>` via the resolved endpoint.
5. **Response translation**: The `open-sse/translator/` layer converts the service's response into the standard OmniRoute API format.

**Security hardening** enforces two critical constraints:

- **Process isolation**: Child processes spawn via `spawn` with explicit argument arrays, never shell strings (Hard Rule #13).
- **Local-only exposure**: [`src/server/authz/routeGuard.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/routeGuard.ts) classifies all `/api/services/*` routes as `isLocalOnlyPath()`, blocking external network access (Hard Rule #17).

## Enabling and Disabling Embedded Services

OmniRoute controls feature availability through the `EMBEDDED_SERVICES_ENABLED` flag defined in [`src/shared/constants/featureFlagDefinitions.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/featureFlagDefinitions.ts). This boolean defaults to `true` but can be toggled to remove the "Embedded Services" entry from the sidebar (configured in [`src/shared/constants/sidebarVisibility/sections.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/sidebarVisibility/sections.ts)) and prevent the supervisor from launching any child processes.

Disabling the flag effectively neuters the service layer without removing registry definitions, allowing for maintenance windows or security lockdowns without code changes.

## Summary

- **ServiceRegistry** in [`src/lib/services/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/registry.ts) defines available binaries, arguments, and health-check endpoints using a declarative configuration array.
- **ServiceSupervisor** in [`src/lib/services/types.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/types.ts) manages process lifecycle, enforces safe spawning without shell interpolation, and guarantees graceful shutdown via `SIGTERM`.
- **Installer utilities** in [`src/lib/services/installers/utils.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/installers/utils.ts) provide a sandboxed `npm install` wrapper accessible via `npm run service:install`.
- **Security model** enforces local-only routing through [`src/server/authz/routeGuard.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/routeGuard.ts) and process isolation through spawn argument arrays.
- **Feature flag** `EMBEDDED_SERVICES_ENABLED` controls global availability and UI visibility without modifying service definitions.

## Frequently Asked Questions

### What types of binaries can OmniRoute manage as embedded services?

OmniRoute can manage any executable that exposes an HTTP endpoint, including local LLM inference engines like llama.cpp, vector stores such as Chroma or Weaviate, or custom Node.js/Python tools. The only requirements are a valid binary path in the registry, a reachable health-check URL, and compatibility with the local operating system.

### How does OmniRoute prevent security risks when running external binaries?

The platform enforces **process isolation** by using Node.js `spawn` with explicit argument arrays rather than shell strings, preventing injection attacks (Hard Rule #13). Additionally, [`src/server/authz/routeGuard.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/routeGuard.ts) classifies all service routes as `isLocalOnlyPath()`, ensuring embedded services respond only to localhost requests and remain inaccessible from external networks (Hard Rule #17).

### Can I install npm dependencies for an embedded service automatically?

Yes. Use the CLI command `npm run service:install -- --name=<service> --repo=<git-url>` to trigger the `runNpm` utility in [`src/lib/services/installers/utils.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/services/installers/utils.ts). This wrapper performs a safe `npm install` inside the service directory, handling platform-specific quirks and validating paths without exposing the system to arbitrary shell execution.

### What happens to embedded services when the OmniRoute server restarts?

On shutdown, `ServiceSupervisor.stopAll()` sends `SIGTERM` to each child process and awaits the `close` event, ensuring clean termination without orphaned processes. On startup, the supervisor checks the `services` table (defined in [`src/lib/db/migrations/071_services.sql`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/migrations/071_services.sql)) and respawns any services marked `enabled` in the registry, restoring the previous runtime state.