Skip to content

Server Internals

The HOS server (apps/server/) is a Node.js application built on Express, with an Electron wrapper for desktop deployment. It serves as the central hub — receiving commands from mobile clients via REST/SSE, dispatching actions to OS-local driver processes or external WebSocket drivers, and broadcasting state changes back to all connected clients.


ActionDispatcher

File: apps/server/src/bridge/action-dispatcher.tsInstantiation: Singleton via initBridge() in apps/server/src/bridge/index.ts

The ActionDispatcher is the command gateway between the REST layer and the driver layer.

Responsibilities:

  • Receives deviceId + action + data triples from controllers
  • Looks up ActionMap entries (outbound direction, driver-specific command mappings)
  • Resolves to the mapped command or passes the action directly if no map entry exists
  • Calls DeviceManager.executeTypedCommand() or a driver-specific dispatch path
  • HOS Controls Sync: Supports Device.store() logic which fetches OS commands and populates HOS controls automatically.
  • Publishes events to ProtocolHub at each stage of dispatch

ProtocolHub events emitted:

EventWhen
ACTION_REQUESTEDImmediately on dispatch entry
ACTION_DISPATCHEDAfter successful command delivery
ACTION_FAILEDOn device not found, driver error, or map lookup failure

DriverWSServer

File: apps/server/src/core/driver-ws-server.ts

The raw WebSocket server for external SDK-style drivers. Uses the ws library — not Socket.IO.

OS-local uploaded drivers do not need to open this socket. They are spawned by DriverManager from manifest metadata and exchange newline-delimited JSON over stdin/stdout.

Connection details:

PropertyValue
WebSocket path/driver
Protocol version1
Default port8080 (same as HTTP server)
Env varDRIVER_WS_PORT

Session record shape:

{
  id: string,
  driverKey: string,
  instanceId: string,
  name?: string,
  protocolVersion?: number,
  socket: WebSocket
}

Validation rules:

  • Driver key: /^[A-Z0-9_]{2,64}$/
  • Instance ID: /^[a-zA-Z0-9:_-]{1,128}$/

Driver registration message:

json
{
  "method": "driver.register",
  "driverKey": "MY_DRIVER",
  "instanceId": "my-driver:1",
  "protocolVersion": 1
}

Accepted inbound event types:

Event TypePurpose
DEVICE_DISCOVEREDDriver announces a new device
DEVICE_UPDATEDDriver updates device metadata
DEVICE_REMOVEDDriver removes a device
STATE_UPDATEDriver pushes device state snapshot
ACTION_RESULTDriver responds to a dispatched command
METRIC_UPDATEDriver reports telemetry metrics

Local Driver Processes

Files: apps/server/src/drivers/DriverManager.ts, apps/server/src/drivers/PythonDriverProcess.ts, apps/server/src/drivers/JavaScriptDriverProcess.ts, apps/server/src/drivers/LuaDriverProcess.ts

DriverManager starts OS-local drivers loaded from Integration Manager packages. The loader maps implementation extensions to runtime types:

File extensionRuntime
.pypython
.jsjavascript
.lualua

Local process drivers share the same high-level event contract as WebSocket drivers, but use line-delimited JSON:

  • HOS writes command messages to driver stdin.
  • Driver writes one JSON event per stdout line.
  • Non-JSON stdout is forwarded as runtime output.
  • stderr is forwarded as runtime diagnostics.

JavaScriptDriverProcess launches .js drivers with HOS_NODE_BINARY, process.execPath, or node fallback. In Electron builds, it sets ELECTRON_RUN_AS_NODE=1 when needed so the bundled executable can behave as Node. Stop behavior mirrors Python: SIGTERM first, then SIGKILL after a short timeout.

Uploaded JavaScript drivers are plain Node-compatible .js files. TypeScript can be used as an authoring format, but must be compiled before upload.


HOS Fleet Manager (Phase 06)

Purpose: Enterprise-grade management of HOS device fleets. Provides a centralized UI and API for monitoring, commanding, and categorizing multiple HOS hubs.

Key Components:

  • Fleet UI: Web-based interface within the OS dashboard for fleet overview and device-level drill-down.
  • Fleet Routes: (apps/server/src/routes/fleet.ts)
    • POST /device/hos/command: Unified endpoint for dispatching commands to fleet devices.
    • POST /device/hos/category: Management of device categories for organizational filtering.
  • Fleet Bridge Auto-Expose: (apps/server/src/bridge/fleet-bridge-auto-expose.ts) Automatically exposes local devices to the fleet bridge for remote visibility and control.

Driver Ecosystem

Generic IR Driver & Fleet Sync

Driver Key: GENERIC_IRAdapter File: apps/server/src/drivers/generic-ir/generic-ir-adapter.ts

The Generic IR driver allows Haptique OS to control physical IR devices (TVs, ACs, Fans) via a network-attached Haptique IR Extender (hardware bridge).

Provisioning Flow

  1. Fleet Registration: IR devices are first registered or captured via the Fleet mobile app/API.
  2. Auto-Sync: The DeviceManager.syncIrDevices() method (triggered on startup or via API hooks) scans the Fleet database for paired IR devices.
  3. Logical Device Creation: For each Fleet IR device, a native OS LogicalDevice is created.
  4. Payload Embedding: Raw IR pulse timings and carrier frequency data are extracted from the Fleet controls array and embedded directly into the Logical Device's properties.irCommands dictionary.

Command Dispatch

When a command (e.g., volume_up) is sent to a GENERIC_IR device:

  1. The GenericIrAdapter retrieves the raw pulse array from the device's metadata.
  2. It resolves the target hardware Extender's IP and Access Token.
  3. It dispatches a secured HTTP POST to http://<extender-ip>/api/ir/send.
  4. Payload Structure:
    json
    {
      "freq_khz": 38,
      "duty": 33,
      "repeat": 1,
      "raw": [microsecond_timings...]
    }

Android TV Driver

Driver Key: ANDROID_TVAdapter File: apps/server/src/drivers/android-tv/android-tv-adapter.ts

The Android TV driver provides ADB-over-TCP control for Android TV and Google TV devices.

Capabilities:

  • Media Control: Play, pause, stop, next, previous.
  • Power Management: Wake and sleep via ADB keyevents.
  • App Launching: Direct intent-based app launching (YouTube, Netflix, etc.).
  • D-Pad Navigation: Remote control simulation for UI navigation.

Technical Detail: Uses adb-shell or direct socket frames to communicate with the target device's ADB port (default 5555). Requires "Network Debugging" to be enabled on the TV.


ProtocolHub

File: apps/server/src/core/protocol-hub.ts

An EventEmitter singleton (protocolHub) that acts as the internal event bus bridging the driver runtime to all UI and debug consumers.

Key method:

protocolHub.publish(HaptiqueProtocolEvent)

Broadcasts the event to all subscribers and stores the last 60 events in an in-memory ring buffer.

Event shape:

{
  event: string,
  driver: string,
  device_id: string,
  data?: unknown,
  timestamp?: number
}

Subscribers:

SubscriberChannel
SSE controller (/state/stream)Streams events to mobile HaptiqueContext
Socket.IO /socket/haptique-protocolDesigner and debug consumers
Electron main window IPCDesktop sidebar and debug panel

DeviceStateManager

File: apps/server/src/state/DeviceStateManager.ts

Holds per-device runtime state snapshots in memory. All state reads from the mobile app go through this manager; all state writes from drivers arrive here.

State snapshot shape:

{
  power: boolean | string,
  volume?: number,
  brightness?: number,
  input?: string,
  playback?: object,
  extras?: Record<string, unknown>,
  updatedAt: number
}

Events emitted:

EventConsumers
state_changedSSE bridge, Socket.IO /socket/device-state channel

Drivers push STATE_UPDATE messages to DriverWSServer, which writes to DeviceStateManager. SSE reads from DeviceStateManager to build the initial state snapshot on client connection.


AiServiceManager

File: apps/server/src/core/ai-service-manager.ts

Manages the lifecycle of the local AI inference engine and the proxy connection to cloud AI providers.

Responsibilities:

  • Process Lifecycle: Spawns and monitors the llama-service child process (the local inference engine).
  • Model Resolution: Identifies and verifies the latest GGUF model in the local storage directory.
  • Resource Guardrails: Calculates model memory requirements and prevents service start if system RAM is critically low.
  • Inference Queueing: Manages a request queue for AI prompts, supporting both synchronous (wait-for-result) and asynchronous (event-streamed) patterns.
  • Auto-Stop Logic: Shuts down the local inference process after a period of inactivity to conserve system memory and CPU.
  • Provider Proxy: Routes prompts to OpenRouter or other cloud providers if configured as the primary AI provider.

Key Method: aiServiceManager.prompt(text, options) — returns a requestId used to track the inference lifecycle.

ProtocolHub events emitted:

EventWhen
ai_service_statusOn service start, stop, or health change
ai_inference_chunkOn every token generated (streaming)
ai_inference_resultOn successful completion of a prompt
ai_inference_errorOn generation failure or service timeout

REST API Routes

The server mounts several route families for different client types. Each family uses its own auth middleware.

Route PrefixFileAuthPurpose
/app/os, /api/os, /v1/osroutes/os-api.tsBearer token (osApiAuth)Main OS JSON API used by mobile app
/app, /apiroutes/app.tsappAuthLegacy app API
/remote, /v1/remoteroutes/remote.tsremoteAuthRemote-controller pairing and commands
/adminroutes/admin.tsAdmin authAdmin panel
/osroutes/os/index.tsServer-rendered EJS web UI
/dev(dev only)Development tooling

For the full endpoint inventory — all paths, HTTP methods, query parameters, and response shapes — see the API Reference page.


Socket.IO Layer

File: apps/server/src/socket/index.tsSocket path: /socket.io (default)

Socket.IO handles real-time connections from mobile clients and the designer. Driver connections use raw WebSocket (DriverWSServer), not Socket.IO.

NamespacePurposeKey Events
/socket/remote-connectRemote pairing flowremote:pairing, remote:pairing:status, pairing:code:verify
/socket/device-ir-testIR signal testingir:data
/socket/device-statePer-device live state (remote app)device:state:update, device:state:snapshot
/socket/haptique-protocolOS protocol command/response bushaptique:event, haptique:command, haptique:response
/socket/designerDesigner live-pushdesigner:published, designer:refresh

For the full Socket.IO event reference, see the API Reference page.


Data Flow

The following diagram shows the full request path from an incoming mobile command through to state broadcast:

Mobile / REST Client
       |
       v
Express Routes (/app/os, /app, /remote, /os)
       |
       v
Auth Middleware (osApiAuth / appAuth / remoteAuth)
       |
       v
Controllers (controllers/app/os.ts, etc.)
       |
       v
ActionDispatcher (bridge/)
       |        \
       v         v
DeviceManager  DriverManager / DriverWSServer
       |               |
       v               v
Core Services     Driver Processes (JS/Python/Lua/native/core)
(device-manager, space-service,
 program-engine, zone-store,
 media-services-manager, ...)
       |
       v
DeviceStateManager   <----  STATE_UPDATE from drivers
       |
       v
ProtocolHub (event bus)
       |
       +---> SSE Controller (/state/stream) --> Mobile HaptiqueContext
       |
       +---> Socket.IO (/socket/haptique-protocol) --> Designer
       |
       +---> Socket.IO (/socket/device-state) --> Remote App

Key Source Files

ModuleFile
ActionDispatcherapps/server/src/bridge/action-dispatcher.ts
AiServiceManagerapps/server/src/core/ai-service-manager.ts
Bridge initapps/server/src/bridge/index.ts
DriverWSServerapps/server/src/core/driver-ws-server.ts
DriverManagerapps/server/src/drivers/DriverManager.ts
JavaScriptDriverProcessapps/server/src/drivers/JavaScriptDriverProcess.ts
ProtocolHubapps/server/src/core/protocol-hub.ts
DeviceStateManagerapps/server/src/state/DeviceStateManager.ts
Socket.IO setupapps/server/src/socket/index.ts
OS API routesapps/server/src/routes/os-api.ts
Server entryapps/server/src/app.ts
Env configapps/server/src/config/env.ts

See Also

  • API Reference — full endpoint inventory and Socket.IO event reference
  • HOS Overview — conceptual introduction to the driver ecosystem
  • AI Driver Builder MCP — generated OS-local driver packages and JavaScript runtime rules
  • Dev Setup — running the server locally with a driver connected