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.
| Carries | Used by |
|---|---|
| All 19 RPC services | omnitron CLI |
The OmnitronDaemon service | Webapp dev (when running locally) |
| MCP server requests | Agent 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-browseruses this). - A REST gateway if
httpRest: trueis 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:
| Task | Default interval |
|---|---|
| Health probe sweep across all apps | 15 s |
| Metrics aggregation tick | 5 s |
| State persistence flush | on transition + 30 s baseline |
| Crash-loop backoff timer | per-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 launcher —
node bootstrap.jsis forked once; bootstrap is responsible for creating allApplications 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 runsApplication.createdirectly. 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.
| Service | Purpose |
|---|---|
OmnitronDaemon | App lifecycle — start / stop / restart / status / inspect |
auth | JWT issue / verify / RBAC |
secrets | Encrypted secret CRUD |
infrastructure | Docker container management (Postgres / Redis / etc.) |
deploy | Deployment workflows |
fleet | Cross-node fleet operations |
pipeline | CI/CD pipeline runs |
backup | Database backup / restore |
project | Seed project registry |
kubernetes | k8s integration (apply / scale / observe) |
node-manager | Infrastructure node inventory |
log-collector | Per-app log streaming + filtering |
trace-collector | Distributed trace ingestion |
telemetry | Telemetry-relay (titan-telemetry-relay) aggregator |
health-check | Active health-check runs |
discovery | Service discovery state |
event-broadcaster | Cross-process event bus |
alert | Alert rules + delivery |
sync | Cross-daemon state synchronisation |
system-info | Host CPU / RAM / disk inventory |
→ Full reference: Services reference.
Infrastructure subsystem
When an app's omnitronConfig.infrastructure declares a
requirement, the daemon's infrastructure subsystem:
- Checks if the requirement is already satisfied (running container, registered bare-metal service).
- Resolves connection parameters (host / port / credentials).
- Provisions if missing — Docker for dev/test, bare-metal hooks for prod.
- 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:
| Parameter | Default |
|---|---|
discovery | 'redis' (or 'consul' / 'static') |
electionTimeout | 5–15 s (jittered) |
heartbeatInterval | 2 s |
Cluster operations are exposed via the cluster CLI command
group — see CLI Cluster section.
Webapp host
The daemon optionally serves the React console:
| Mode | Source | When |
|---|---|---|
| Production | Pre-built bundle from apps/omnitron/webapp/dist/ | After pnpm build |
| Dev | Spawns Vite dev server with HMR | omnitron 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:
| Role | What they can do |
|---|---|
viewer | Read-only: list / status / inspect / metrics / health / logs |
operator | Viewer + lifecycle: start / stop / restart / reload / scale / exec |
admin | Operator + 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:
- Daemon — the always-on process; its internals.
- Orchestrator — how apps launch.
- Services reference — every RPC method.
- CLI — the operator's daily interface.
- Console — the web UI.