Skip to Content

Running locally

How to run Companion Hub from a source checkout — for contributing, or for testing changes before they ship.

The Companion Hub repository uses pnpm , not Bun. It declares packageManager: pnpm@11.5.1 and ships only pnpm-lock.yaml. This docs site uses Bun; Hub does not. Running bun install in a Hub checkout will not give you a working tree.

The repository is public at github.com/companionintelligence/Companion-Hub , and its default branch is dev. You can clone it and run pnpm install without a GitHub account or an access token. You need an account only to open an issue or a pull request.

The development loop

Clone, install, bring the stack up from source, edit, test — there is no Docker image rebuild between edits.

Prerequisites

  • Docker with the Compose plugin — verify with docker compose version. See Install Docker if you need it.
  • Node.js 22 or later — Hub declares engines.node: >=22, and .nvmrc pins Node 22
  • pnpm 11 or later — engines.pnpm: >=11

The simplest way to get the right pnpm is Corepack, which reads the pinned version out of the repository’s packageManager field:

corepack enable

Install dependencies

Clone the repository  (or your fork of it), then install from its root:

pnpm install

The install needs no credentials. The design files the frontend needs are copied into the repository, so no private package registry is involved.

Build packages/common before you run backend tests, because the backend resolves @ci-hub/common/validation from its dist/ folder:

pnpm --filter common build

If you build the desktop app or run its Rust tests, you also need the GTK and WebKit development headers. On Debian and Ubuntu:

sudo apt-get install -y build-essential pkg-config libssl-dev libdbus-1-dev libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev libxdo-dev

The web stack does not need them.

Create your env file

A source checkout does not generate its own environment file. Copy the template and fill in the required values:

cp .env.example .env.local

.env.example is a template, not a working config. Set at least the values below in .env.local before you start the stack.

VariableValue
ENV_FILE.env.local — must match the file name
ROOT_FOLDER_HOSTAbsolute path for persistent data
POSTGRES_PASSWORDAny password; the Postgres container and the backend share it
JWT_SECRETA random secret, for example from openssl rand -hex 32
INTERNAL_IP0.0.0.0 binds all interfaces
DOMAINThe public domain used for Traefik routing
CI_CLOUD_URLhttps://hub.ci.computer for the production Portal

Start the stack

Run the wizard

./bin/cihub.cjs wizard

The wizard needs an interactive terminal. When .env.local is missing, it enters first-run mode: it shows a step tracker, checks that Docker is available, prepares host assets, and starts the Hub. It does not create the env file for you, so create .env.local first, as described above.

For the local environment, the backend and frontend run in the foreground of the wizard’s terminal, so the wizard’s later steps — pairing with CI Cloud and installing a model — do not run. In a second terminal, run cihub register local to pair. Install models from the dashboard.

./bin/cihub.cjs is the CLI as declared in the repository’s package.json. It runs your working-tree TypeScript directly — see Running the CLI locally.

Open the dashboard

cihub up local runs the backend and the Vite dev server on your host, so its ports differ from the containerized stack:

SurfaceURL
Dashboard (Vite dev server)http://localhost:5005 — Vite opens it in your browser
Backend APIhttp://localhost:5004 — Vite proxies /api here
PostgreSQLlocalhost:6543
RabbitMQlocalhost:5672

The containerized Hub — the desktop app, and cihub up dev or cihub up prod — serves the dashboard at http://localhost:5002 instead.

Doing it by hand instead

If you’d rather not use the wizard, the same result in two commands:

cihub setup local
cihub up local

cihub up local starts PostgreSQL and RabbitMQ in Docker, then runs the backend and frontend from source — no Docker image rebuild between edits. pnpm run local is the same command.

If port 5004 or 5005 is already in use by something else, the command stops with Local development port conflict. Stop the other process and run it again.

Environments

Each environment reads its own file at the repository root:

EnvironmentFile
local.env.local
dev.env.dev
staging.env.staging
prod.env.prod

Most commands take the environment as an argument — cihub up local, cihub setup local, cihub wizard staging. Omitted, it defaults to local.

Day to day

cihub status # containers, dashboard URL, tunnel, VPN, models
cihub down # stop the stack
cihub reset local --yes # wipe local runtime state for a clean-slate run

cihub reset removes installed apps, runtime state, volumes, and the data folder. It does not delete .env.local, so the wizard does not re-enter first-run mode afterward. To see the first-run flow again, move .env.local aside first.

For cihub up local, cihub status prints http://localhost:5002 as the dashboard address unless your env file sets FRONTEND_PORT or BACKEND_PORT. Use the addresses in the table above instead.

See the CLI Reference for the full command set.

Running tests

pnpm test # unit tests, the CLI suite, and the entrypoint tests
pnpm test:integration
pnpm test:e2e
pnpm test:cli # CLI and TUI presentation tests

Automatic CI triggers are gated, so run pnpm run check:pr before you request review — nothing runs it for you on push. It runs lint, the dead-code check, type checks, the OpenAPI drift check, the tests, and the desktop crate’s Rust tests.

Working on the CLI itself? Running the CLI locally covers the tighter iteration loop.

Last updated on