Skip to main content

Architecture

Omnitron is decomposed into a handful of long-lived objects that all live inside a single daemon process. Operators talk to the daemon over Netron RPC; the daemon spawns and watches child processes; child processes report metrics, logs, and health back through structured pipes.

This page describes those pieces in enough detail to debug an incident at 2 AM.

Component map

The three planes

Omnitron exposes three independent transports — same Netron RPC surface, different network shape.

1. Management plane — unix://~/.omnitron/daemon.sock

Unix domain socket, file mode 0o600 (owner-only). The trust boundary: if you can open the socket, you've already passed the OS-level identity check. CLI calls auth-bypass through this socket for ergonomics.

CarriesUsed by
All 19 RPC servicesomnitron CLI
The OmnitronDaemon serviceWebapp dev (when running locally)
MCP server requestsAgent processes spawned by the CLI

2. Public TCP plane — tcp://0.0.0.0:9700

Opt-in. Disabled by default; enable when:

  • You run a fleet (other daemons connect for cluster membership).
  • You operate omnitron remote (alias-addressed daemons).
  • You expose a programmatic API to an external CI/CD.

JWT is required on this plane. RBAC roles (viewer / operator / admin) gate every method.

3. HTTP / WS plane — http://0.0.0.0:9800

Opt-in. Serves:

  • The webapp's static bundle (production build).
  • The Netron HTTP bridge (netron-browser uses this).
  • A REST gateway if httpRest: true is configured.

JWT also required here, except for static asset routes.

Daemon lifecycle

The state-store is the persistent intent — what should be running. On crash + restart, the daemon reads state.json and relaunches anything that was alive at last write.

State store — state.json

A single JSON file capturing:

interface DaemonState {
apps: Record<string, {
name: string;
status: 'starting' | 'running' | 'stopped' | 'crashed';
pid?: number;
startedAt?: number;
lastError?: string;
restarts: number;
processes: Record<string, ChildProcessState>;
}>;
cluster?: {
role: 'master' | 'follower';
leader?: string;
term: number;
};
}

Persisted on every status transition, atomic-rename style (write tmp → rename → fsync parent). If the file is corrupt at boot, the daemon starts fresh — empty apps map — and logs a warning.

PID manager

Owns ~/.omnitron/daemon.pid. Responsibilities:

  • Lock acquisition at boot: open exclusive, write process.pid. If lock fails, another daemon is running — abort.
  • Liveness sweep: periodically check whether the lock-holding PID is still alive; if not, reclaim the lock.
  • Atomic ownership transfer during cluster.step-down — the outgoing leader explicitly releases.

Child process PIDs are owned by the orchestrator (per IAppHandle), not the PID manager.

Daemon scheduler

A small in-process scheduler bound to the daemon's lifecycle. Runs periodic tasks:

TaskDefault interval
Health probe sweep across all apps15 s
Metrics aggregation tick5 s
State persistence flushon transition + 30 s baseline
Crash-loop backoff timerper-app, exponential
Cluster heartbeat (if cluster.enabled)2 s
Health-monitor sweep (cluster nodes)60 s

All scheduler timers are .unref()-ed so they don't block shutdown.

Orchestrator subsystem

Owns the per-app launch pipeline. One AppHandle per running app:

Two launch modes:

  • Classic launchernode bootstrap.js is forked once; bootstrap is responsible for creating all Applications and running its own subprocess management. Used for legacy apps.
  • Module-worker spawner — one fork per IProcessEntry. Each child imports a single module file and runs Application.create directly. Default for new apps; lower memory, faster boot.

→ Full pipeline: Orchestrator.

Built-in RPC services

The daemon registers 19 Netron services at boot. They share authentication / authorization with the OmnitronDaemon service.

ServicePurpose
OmnitronDaemonApp lifecycle — start / stop / restart / status / inspect
authJWT issue / verify / RBAC
secretsEncrypted secret CRUD
infrastructureDocker container management (Postgres / Redis / etc.)
deployDeployment workflows
fleetCross-node fleet operations
pipelineCI/CD pipeline runs
backupDatabase backup / restore
projectSeed project registry
kubernetesk8s integration (apply / scale / observe)
node-managerInfrastructure node inventory
log-collectorPer-app log streaming + filtering
trace-collectorDistributed trace ingestion
telemetryTelemetry-relay (titan-telemetry-relay) aggregator
health-checkActive health-check runs
discoveryService discovery state
event-broadcasterCross-process event bus
alertAlert rules + delivery
syncCross-daemon state synchronisation
system-infoHost CPU / RAM / disk inventory

→ Full reference: Services reference.

Infrastructure subsystem

When an app's omnitronConfig.infrastructure declares a requirement, the daemon's infrastructure subsystem:

  1. Checks if the requirement is already satisfied (running container, registered bare-metal service).
  2. Resolves connection parameters (host / port / credentials).
  3. Provisions if missing — Docker for dev/test, bare-metal hooks for prod.
  4. Injects resolved env vars (DATABASE_URL, REDIS_URL, …) into the app at startup.

→ Reference: omnitron infra status shows current containers; the Infra CLI section covers commands.

Cluster subsystem

When cluster.enabled: true in daemon config, multiple daemons form a cluster:

Election parameters:

ParameterDefault
discovery'redis' (or 'consul' / 'static')
electionTimeout5–15 s (jittered)
heartbeatInterval2 s

Cluster operations are exposed via the cluster CLI command group — see CLI Cluster section.

Webapp host

The daemon optionally serves the React console:

ModeSourceWhen
ProductionPre-built bundle from apps/omnitron/webapp/dist/After pnpm build
DevSpawns Vite dev server with HMRomnitron webapp dev

Both modes proxy Netron RPC over HTTP through the daemon's HTTP plane.

Auth model — three roles

The OmnitronDaemon service and others use role-based access:

RoleWhat they can do
viewerRead-only: list / status / inspect / metrics / health / logs
operatorViewer + lifecycle: start / stop / restart / reload / scale / exec
adminOperator + destructive: shutdown / reloadConfig / setMetricsEnabled

The local Unix socket bypasses auth — local CLI calls run as the implicit admin (OS-level trust). TCP/HTTP planes always require JWT.

Data flow — log shipping

Logs flow through the daemon — no separate log shipper. The ring buffer means omnitron logs --follow returns recent entries immediately even if the file has been rotated.

Data flow — metrics aggregation

Apps push metrics to the daemon via Netron — the daemon stores and aggregates centrally. The webapp reads the same store.

Data flow — leader election (cluster mode)

Step-down is graceful: omnitron cluster step-down releases the lock and demotes self before the next election.

Putting it together

Read these in order for a complete picture:

  1. Daemon — the always-on process; its internals.
  2. Orchestrator — how apps launch.
  3. Services reference — every RPC method.
  4. CLI — the operator's daily interface.
  5. Console — the web UI.