Skip to Content

Architecture

Overview

Companion Hub is a self-hosting platform built from a few cooperating pieces: a Hub container that runs the API and dashboard, a database and a message queue, a reverse proxy, and one Docker Compose project for each app you install.

Hub is the app runtime layer of the Companion stack. On Companion Core hardware it sits on Companion OS; on any other Linux, Windows, or macOS machine it runs on your own operating system. Everything above it — Companion Memory, agents, and the apps you install — runs on Hub.

The Companion stack, layer by layer Five layers of the platform drawn as isometric slabs stacked one above the next, each slab a true isometric rhombus with a visible edge, lit from high on the left so that the top face of every slab is the palest of its three and the left face the darkest. Lowest is Companion Core, the Framework Mini-ITX board in its steel chassis; above it Companion OS; then Companion Hub, held a full step deeper in the campaign’s phthalo green because it is the layer this plate is about; then Companion Memory and Agents; and on top an open plane carrying a four-by-three grid of twelve rounded tiles, one for each catalogue app: Companion Memory, OpenClaw, Hermes, Planning, Capture, Spellbook, Local Bench, Just In Case, Earth, Photo Time Machine, Web XR Scan and Glasses Bridge. Each tile carries a simple line mark drawn for this sheet — a node graph, a pincer, a paper dart, three checked rows, an arrow dropping into a tray, an open book, a gauge and needle, two rings on four spokes, a globe, a framed landscape, four scan brackets, and a pair of lenses under a signal arc — rather than the shipped icon artwork, which is raster and cannot be read at this size. Each slab carries its own name, set in the plane of its top face along the lower-left edge, with no description. Your apps, your agents, your files Companion Memory and Agents Companion Hub Companion OS Companion Core
Where Hub sits: above Companion OS and Companion Core, beneath Companion Memory and Agents and the apps, agents, and files you run.

Core Components

Hub (Local Server)

The Hub is the main application running on your server:

The next diagram shows what runs where. The Hub container talks to the Docker Engine through the mounted socket, which is how it installs and manages each app. It keeps its state in PostgreSQL and hands slow work, such as installs and updates, to RabbitMQ. Those two services sit on a network that no app can join.

CI Account (hub.ci.computer)

Your CI Account at hub.ci.computer . Pairing your Hub with it is the first step of setup: until the Hub is paired, the dashboard sends you to its pairing screen instead of the app store. Pairing is also required to install apps from the store, because Hub sends a device key that CI Account issues when you pair. A paired Hub checks in with CI Account about every hour. It provides:

  • Device pairing
  • Organizations (add people and grant device access)
  • Remote Hub management
  • Managed Cloudflare Gateway provisioning
  • The app catalog and remote App Store access

Cloudflare Gateway

A managed Cloudflare Tunnel  that securely exposes your apps without port forwarding. Provisioned and managed through your CI Account.

Docker Layer

All apps run as Docker Compose projects. Each app is isolated in its own compose stack. Every app’s main container joins the shared ci-hub_network, which is how apps reach the Hub API and each other. The Hub’s database and queue are on a separate ci-hub_internal network that apps never see, so an installed app cannot reach them.

A third network, ci-hub_edge, carries public traffic. Only Traefik, cloudflared, and the Tailscale sidecar join it, at fixed addresses, so Traefik and Hub can trust the visitor’s real address from the tunnel and tailnet hops and from nothing else. A fourth network, ci-os-hub_network, is the retired name for the app network. Hub keeps it so apps installed before the rename keep working.

How requests reach an app

Locally, you open an app on its direct port, which bypasses the proxy: http://127.0.0.1:<port> on the Hub machine, or http://<hub-address>:<port> from another device. Hub doesn’t give a locally opened app a hostname, and the app’s page lists each address it has. See Finding your app’s URL. Agent apps and apps with no login of their own publish that port on 127.0.0.1 only, so reach them from another device through Private VPN or the public web. Traefik routes by hostname only for the apps you expose.

Remotely, the Cloudflare Gateway is a managed tunnel that your CI Account provisions when you pair your Hub. The cloudflared container dials out to Cloudflare and holds the connection open, so traffic for an exposed app arrives at Cloudflare, travels down that existing tunnel to your Hub, and reaches Traefik on the edge network — your router never needs an open inbound port. Only apps whose Exposure mode is Public Web get a public URL. Before an app receives a request, Traefik asks the Hub whether the visitor is signed in, for apps you protect with Require Auth.

AI and agents

Hub does not run the inference engines. Ollama, vLLM, oMLX, and Lemonade run on the host (or on another machine you point Hub at), and Hub reaches them from inside Docker at host.docker.internal. Hub resolves which model and endpoint each AI app should use and writes them into the app’s environment. See AI and inference.

Hub also serves two inference APIs itself. An OpenAI-compatible API at /api/inference/v1 lets an editor or SDK use your hardware, and a pool proxy at /api/inference/pool sends a request to whichever paired Hub has the model and the shortest queue. AI apps use the proxy by default; with no peer paired it serves them from this Hub’s own engines. See Hub Pool.

Agents reach Hub over the Model Context Protocol. The /api/mcp endpoint speaks Streamable HTTP and authenticates each client with a key from Hub’s key store. Agent apps that declare hub_integration.mcp_client receive an endpoint address and a key of their own when you install them. See Companion agent.

Docker Services

The Hub runs several containers defined in the stack’s compose file (docker-compose.prod.yml):

ServiceImagePurposeEnabled
ci-hubHub backend + frontendMain application (API on port 5002)Always
ci-hub-dbPostgreSQL 14Database. Private network; published on 127.0.0.1:6543 onlyAlways
ci-hub-queueRabbitMQ 4Message broker. Private network; published on 127.0.0.1:5001 onlyAlways
traefikTraefik v3Reverse proxy, SSL, routing (ports 80 and 443, or 8880 and 8443 in the Linux desktop app, and 8080 for the dashboard)Always
hub-tailscaleTailscalePrivate VPN sidecar (compose profile private-vpn)When you set an auth key or have signed in, and have not opted out
cloudflaredCloudflare tunnel agentManaged gateway (compose profile cloudflare)When the Hub is paired
Containers in the Hub stack compose file.

Hub renamed its containers from the ci-os-hub names to ci-hub. The old names, such as ci-os-hub and ci-os-hub-queue, still resolve as network aliases, so apps and configuration written for them keep working.

Technologies

TechnologyRoleWhere it runs
Docker ContainerisationHost machine
Traefik Reverse proxy and load balancertraefik
TypeScript End-to-end type safetyci-hub
NestJS Backend frameworkci-hub
React Dashboard frontendci-hub
Tauri 2 Cross-platform desktop appYour desktop (macOS, Windows, Linux)
Drizzle ORM Type-safe database accessci-hub
PostgreSQL Databaseci-hub-db
RabbitMQ Message brokerci-hub-queue
Tailscale Optional private networkinghub-tailscale
Last updated on