How the OmniRoute Version Manager Handles Live Updates and Rollback

OmniRoute's Version Manager enables safe, zero-downtime live upgrades and controlled rollbacks for auxiliary tools through database-persisted state, process orchestration, and version pinning.

The OmniRoute Version Manager is a core subsystem designed to manage the lifecycle of external tools like 9router and cliproxy. According to the diegosouzapw/OmniRoute source code, it combines a SQLite-backed state store with runtime process management to support live version updates without server restarts and instant rollback via pinned versions.


Core Architecture

The Version Manager operates through five integrated layers:

Component Key File Responsibility
Database layer src/lib/db/versionManager.ts Schema and CRUD operations for the version_manager_tools table
Process manager src/lib/versionManager/processManager.ts Runtime orchestration: start, stop, pin, unpin
Service façade src/lib/versionManager/index.ts Public API exports for route handlers
Bootstrap controller src/lib/services/bootstrap.ts Reads persisted state on startup to launch correct versions
Tool installers src/lib/services/installers/*.ts Binary download and version resolution logic

The version_manager_tools table persists one row per tool with these critical fields:

  • installedVersion — the currently active binary version
  • pinnedVersion — optional override forcing a specific version
  • statusrunning, stopped, or not_installed
  • lastStartedAt / lastSyncAt — timestamps for health tracking

Live Updates: Zero-Downtime Version Swaps

OmniRoute applies updates through a database-driven state machine. The server does not require restart to activate new versions.

Step 1: API Request and Validation

Clients trigger updates via the Version Manager endpoint. The request body is validated by Zod in src/app/api/version-manager/request.ts:

// Example payload for live update
{
  tool: "cliproxy",
  installedVersion: "2.1.0",
  status: "running"
}

Step 2: Persist State Change

The updateVersionManagerTool function in src/lib/db/versionManager.ts writes the new version and status to the database row. This function is exported alongside upsertVersionManagerTool, getVersionManagerTool, and deleteVersionManagerTool from the same file.

Step 3: Process Manager Reaction

The process manager (processManager.ts) monitors the database state. When installedVersion changes, it:

  1. Gracefully terminates the running tool process
  2. Spawns the binary matching the new version
  3. Records the PID and updates lastStartedAt

Step 4: Health Confirmation

A background sync task (src/lib/services/modelSync.ts) periodically calls updateVersionManagerTool with fresh lastSyncAt timestamps, confirming the tool remains healthy.

// Direct database update for live version change
import { updateVersionManagerTool } from '@/lib/db/versionManager'

await updateVersionManagerTool('cliproxy', {
  installedVersion: '2.0.0',
  status: 'running',
  lastStartedAt: new Date().toISOString()
})

Rollback Mechanism: Version Pinning

Rollback is controlled through the pinnedVersion field, which overrides any newer installedVersion on restart or health-check failure.

Pinning a Version

The pinToolVersion function in processManager.ts sets pinnedVersion in the database:

// Force cliproxy to run version 1.4.2 regardless of installedVersion
await updateVersionManagerTool('cliproxy', {
  pinnedVersion: '1.4.2',
  status: 'running'
})

Resolver Logic in Bootstrap

When src/lib/services/bootstrap.ts initializes a tool, it checks pinnedVersion first:

  1. If pinnedVersion exists → force that version
  2. If pinnedVersion is null → use installedVersion
  3. If neither exists → trigger installer to fetch latest

Unpinning to Resume Auto-Upgrade

Clearing the pin restores normal upgrade behavior:

// Remove version lock
await updateVersionManagerTool('cliproxy', {
  pinnedVersion: null
})

Automatic Fallback on Failure

Tool installers in src/lib/services/installers/cliproxy.ts and similar files implement defensive logic: if a health check fails or the binary crashes, the installer consults pinnedVersion (if set) or falls back to the last known good installedVersion recorded in the database.


API Examples

Live Update via cURL


# Upgrade cliproxy to v2.0.0 immediately

curl -X PATCH https://omniroute.example.com/api/v1/version-manager \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"tool":"cliproxy","installedVersion":"2.0.0","status":"running"}'

Rollback via cURL


# Pin to older version for instant rollback

curl -X PATCH https://omniroute.example.com/api/v1/version-manager \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"tool":"cliproxy","pinnedVersion":"1.4.2"}'

Key Source Files

File Path Purpose
src/lib/db/versionManager.ts Database schema and CRUD: upsertVersionManagerTool, updateVersionManagerTool, getVersionManagerStatus
src/lib/versionManager/processManager.ts Runtime orchestration with setToolStatus, pinToolVersion, unpinToolVersion
src/lib/versionManager/index.ts Public façade exporting all Version Manager functions
src/lib/services/bootstrap.ts Startup routine reading tool state from database
src/app/api/version-manager/request.ts Zod validation schemas for API requests
src/lib/services/installers/cliproxy.ts Example installer respecting pinnedVersion and installedVersion
src/lib/services/modelSync.ts Background health check and timestamp updates

Summary

  • Database-driven state — The version_manager_tools table in src/lib/db/versionManager.ts is the single source of truth for tool versions and status
  • Zero-downtime updates — Changing installedVersion triggers process manager restart without server reload
  • Controlled rollback — The pinnedVersion field forces specific versions, with resolution logic in src/lib/services/bootstrap.ts
  • Health monitoring — Background sync tasks confirm tool viability via lastSyncAt timestamps
  • API-first design — All operations exposed through validated REST endpoints under /api/v1/version-manager/

Frequently Asked Questions

What database table stores the Version Manager state?

The version_manager_tools table, defined in the migration files and accessed through src/lib/db/versionManager.ts, stores one row per tool with fields for installedVersion, pinnedVersion, status, and timing metadata.

How does OmniRoute switch versions without restarting the server?

The process manager (src/lib/versionManager/processManager.ts) monitors database changes to installedVersion. When updated, it terminates the current process and spawns the new binary immediately—no server restart required.

What happens if a tool fails health checks?

The bootstrap controller and installer scripts check pinnedVersion first, then fall back to the last successful installedVersion. This automatic recovery logic is implemented in src/lib/services/installers/*.ts files.

Can I pin multiple tools to different versions simultaneously?

Yes. Each tool has its own row in version_manager_tools with an independent pinnedVersion field. Pinning one tool does not affect others.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →