Documentation/omnitron/Overview
In this section

Omnitron

Omnitron is opt-in. Titan apps run perfectly well without it as plain Node processes — see Titan vs Omnitron for the precise boundary. This page describes what you gain by adding the Omnitron supervisor on top.

Omnitron is the supervisor, control plane, and operator surface for Titan applications. One long-running daemon manages many processes across many apps across many projects, exposes a typed RPC plane for inspection, ships a CLI and a web console, and provisions the infrastructure your apps need.

It's itself a Titan app — supervising other Titan apps. Built on the same primitives the apps it supervises use.

pnpm add -g @omnitron-dev/omnitron
omnitron up                          # start daemon + all configured apps
omnitron status                      # see what's running
omnitron logs --grep error           # tail filtered logs
omnitron webapp open                 # open the web console

What you get

LayerResponsibility
CLIOne omnitron entry point for applications, stacks, deployments, infrastructure, diagnostics and backend updates.
DaemonTyped Netron control plane with durable local state. Coupled mode owns applications directly; resident mode keeps them in an independent owner.
OrchestratorPer-app launch pipeline: TS compile / module load / fork process / wire DI / start lifecycle / watch files in dev
Process treeOne OS process per IProcessEntry you declare; ≥ 1 instances per process; auto-restart with exponential backoff
ServicesRole-protected daemon RPC for authentication, deployment, fleet inventory, secrets, infrastructure and diagnostics. Availability depends on daemon role.
WebappReact + Vite single-page console — same RPC surface; lives at apps/omnitron/webapp/
InfrastructureProvisions Postgres / Redis / S3-compatible / custom containers via Docker (dev) or bare-metal hooks (prod)
MCPBuilt-in Model Context Protocol surface — let agents (IDE assistants, CI bots) read state and trigger operations

When you reach for Omnitron

  • You have ≥ 2 Titan apps and want one place to start, watch, inspect, and shut them down together.

  • You need a typed control plane, not bash scripts. Every operator action goes through Netron RPC with auth, RBAC, and audit.

  • You want dev / staging / prod parity with declarative infra — the same omnitron.config.ts boots Docker locally and bare-metal remote, with secrets resolved per environment.

  • You operate a fleet — multiple nodes, leader election, remote daemons addressed by alias, cross-node health and metrics.

  • You want the console UI for free — omnitron webapp open serves the React console talking to the same daemon.

If you only ever run one Titan app on one machine, node my-app.js may be enough. Omnitron starts to pay back at two apps or two machines.

The mental model

flowchart TB
  CLI["CLI"] -->|Unix socket| RPC
  Console["Console"] -->|Netron over HTTP / WebSocket| RPC
  Agent["Agent via MCP"] -->|MCP adapter and local RPC| RPC

  subgraph Instance["Omnitron instance (one per node)"]
    RPC["Backend: Netron RPC services"]
    State[("SQLite state and registries")]
    Guardian["Resident backend guardian"]
    Owner["Application owner"]
    RPC --> State
    Guardian -->|Supervise backend| RPC
    RPC -->|Lifecycle commands| Owner
  end

  Owner -->|Supervise| AppA["Application: API"]
  Owner -->|Supervise| AppB["Application: ingestion"]
  RPC -->|Provision declared resources| Infra
  subgraph Infra["Infrastructure (Docker / bare-metal)"]
    PG[("PostgreSQL")]
    Redis[("Redis")]
    S3[("S3-compatible storage")]
  end
  AppA -. Uses .-> PG
  AppA -. Uses .-> Redis
  AppB -. Uses .-> PG
  AppB -. Uses .-> S3

The diagram shows resident mode: the owner retains applications while the guardian replaces the backend. In default coupled mode, the backend also owns the application lifecycle. Moving from coupled to resident mode requires an initial application restart; later compatible backend handoffs can preserve those processes. See backend replacement.

Ordinary CLI invocations are short-lived RPC clients. Follow and watch commands keep their connection or polling loop for as long as the operator needs it.

Filesystem layout

By default, Omnitron stores its control-plane files in ~/.omnitron/. OMNITRON_HOME selects another instance directory. This is a selected layout:

~/.omnitron/
  • daemon.sock — Private management socket
  • daemon.pid — Backend process identity
  • data/
    • daemon-state.db — Registries, execution intent and persisted state
    • application-logs.sqlite — Application log delivery journal
    • backend-logs.sqlite — Backend log delivery journal
  • runtime/
    • releases/ — Verified, installed backend runtimes
  • execution/ — Resident owner and guardian control files
  • secrets.enc — Encrypted file-provider secrets
  • logs/
    • omnitron.log — Backend log
    • omnitron.error.log — Backend errors
  • projects/ — Project and stack state, including application log archives
  • backups/ — Database dumps and captured resource archives

The current state store is SQLite; state.json is only an import source for older installations. Backups use backups/ under the selected OMNITRON_HOME; there is no separate backup-directory setting. Project builds, container volumes and native service definitions have their own locations. The observability guide distinguishes query storage from delivery journals and log archives.

Default endpoints

PlaneEndpointPurpose
Managementunix://~/.omnitron/daemon.sock (mode 0o600, owner-only)CLI ↔ daemon — OmnitronDaemon service + the rest of the built-in services
TCPtcp://127.0.0.1:9700 by defaultAuthenticated daemon RPC; configure the bind address for remote access
Consolehttp://localhost:9800 by defaultBrowser interface; publication and backend endpoints follow the configured gateway

The Unix socket is the trust boundary — owner-only file permissions make local CLI calls implicit-auth. TCP and HTTP require JWT.

A minimal omnitron.config.ts

The single configuration file at the repo root:

import { defineEcosystem } from '@omnitron-dev/omnitron';
import { fileURLToPath } from 'node:url';
import path from 'node:path';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

export default defineEcosystem({
  apps: [
    {
      name:        'api',
      bootstrap:   path.join(__dirname, 'apps/api/dist/bootstrap.js'),
      cwd:         path.join(__dirname, 'apps/api'),
      env:         { NODE_ENV: 'production' },
      watch:       { enabled: true, paths: ['src/**/*.ts'] },
    },
    {
      name:        'worker',
      bootstrap:   path.join(__dirname, 'apps/worker/dist/bootstrap.js'),
      cwd:         path.join(__dirname, 'apps/worker'),
    },
  ],
  supervision: {
    strategy: 'one_for_one',
    maxRestarts: 5,
    window: 60_000,
    backoff: { type: 'exponential', initial: 1_000, max: 30_000, factor: 2 },
  },
});

Each app's bootstrap.ts exports a defineSystem(...) that declares the processes (one OS process per IProcessEntry).

How an app launches

sequenceDiagram
  participant Op as Operator (CLI)
  participant D  as Daemon
  participant Orch as Orchestrator
  participant Boot as bootstrap.js
  participant Child as Child process

  Op->>D: start api
  D->>Orch: launch(app: 'api')
  Orch->>Orch: locate bootstrap.js
  Orch->>Boot: import('bootstrap.js')
  Boot-->>Orch: defineSystem({processes: [...]})
  loop per process
    Orch->>Child: fork(module-worker-process.js)
    Child->>Child: Application.create(module)
    Child->>Child: onInit → onStart
    Child-->>Orch: ready handshake
  end
  Orch-->>D: ProcessInfoDto
  D-->>Op: { status: 'running', pid: 1234, ... }

Each IProcessEntry declared in defineSystem(...) becomes exactly one fork (or a pool when instances > 1). The child imports only that module's file — no full bootstrap re-load — so dependencies stay process-isolated.

Multi-project / multi-stack

A project owns one or more stacks. Each stack selects application configuration, infrastructure and placement for an environment:

ProjectStackApplications
monorepo-Adevapi, worker
monorepo-Astagingapi, worker, batch
monorepo-Aprodapi, worker, batch, scheduler
monorepo-Bprodgateway, events

Stack-aware commands (omnitron stack status <project> <stack>) operate on that stack. Environments can share a node or target different nodes; they remain configurations of the same project. See projects and stacks for placement and lifecycle commands.

Built-in observability

The supervisor captures process state and output. Additional signals depend on application instrumentation and configured collectors:

SignalWhere
Application output and structured logsDurable capture and rotated per-application files; see logs
Per-process metricsaggregated by daemon, exposed via RPC + Prometheus text
Health probesApplication-provided checks and declared readiness probes
Crash trackingRestart count, last error, backoff state
Distributed tracesConfigured application tracing and collectors

Both the CLI and webapp read these through the daemon — there's no separate metrics agent to deploy.

Webapp (Omnitron Console)

The console is a React + Vite + MUI SPA that lives at apps/omnitron/webapp/ and talks to the daemon via the @omnitron-dev/netron-react integration and browser client. It gives you:

  • Project + stack view with per-app status cards

  • Live log streams with filtering

  • Metric charts (CPU / RSS / event-loop lag / RPC latency)

  • Health probes and restart history

  • Infrastructure inventory (Docker containers)

  • Secret editor (against the daemon's encrypted store)

  • Fleet view across remote daemons

The published package includes Console assets. omnitron webapp start reconciles the serving gateway; omnitron webapp open opens the configured address. omnitron webapp build is for a source checkout. For development, run pnpm dev in apps/omnitron/webapp/ for a Vite dev server with HMR.

→ Full webapp reference: console.

Compatibility

ComponentRequirement
Node.jsUse a supported runtime from the compatibility reference; native dependencies are qualified for the target Node and OS
OSmacOS, Linux. Windows works for CLI + non-supervisor commands; daemon assumes Unix sockets
DockerRequired for infra commands (provisioning Postgres / Redis / etc.)
Bun / DenoApps may run on Bun/Deno individually, but the daemon expects Node

Where to go next

  • Architecture deep-dive: Architecture — every component, every plane, every data flow.

  • CLI reference: CLI — every command, every flag.

  • Daemon internals: Daemon — PID, state-store, scheduler, lifecycle.

  • Orchestrator: Orchestrator — bootstrap, file watcher, dependency resolver.

  • RPC services: Services reference — all built-in services and their methods.

  • Console UI: Console.