Skip to main content

Development

Setting up a local development environment for HQ.

Prerequisites

  • Docker + Docker Compose
  • Node.js 24 (UI)
  • Git
  • A Supabase project for testing (a free one is fine)
On macOS: brew install node@24 docker (or install Docker Desktop). On Ubuntu: curl -fsSL https://get.docker.com | sudo sh and install Node from nodesource.

Clone and setup

Fill in .env:
  • SUPABASE_URL — optional override for gateway services. Leave empty to use browser onboarding.
  • SUPABASE_SERVICE_ROLE_KEY — optional override for gateway services. Leave empty to use browser onboarding.
  • WORKSPACE_SLUG — any slug, e.g. dev
  • GATEWAY_AUTH_TOKEN — generate with openssl rand -hex 32
Run the migration in your Supabase project:
  1. Open Supabase Studio → SQL Editor
  2. Run every file in db/migrations/ in filename order
  3. Confirm the schema now has the core tables plus agent_usage, agent_budgets, and agents.reports_to_id
Create an auth user: Supabase → Authentication → Users → Add user (check “Auto Confirm User”).

Run the stack in dev mode

Live-reload overlay mounts source directories so changes pick up without rebuilding:
  • UI at http://localhost:3000
  • Gateway’s noVNC at http://localhost:6901/vnc.html
  • Logs stream to stdout
Changes under apps/ui/ reload automatically. Changes to gateway/entrypoint.sh or the daemons require a restart:

Working on just the UI

If you only touch UI code and don’t need a gateway, run Next.js directly:
Create apps/ui/.env.local:
Then either complete browser onboarding against the dev server or set HQ_CONFIG_DIR to a local directory containing compatible workspaces.json and secrets.json files. Pages that depend on a gateway will error if no gateway is running — expected.

Working on just the gateway

UI won’t be running, so you drive the gateway via direct Supabase inserts or docker compose exec.

Project structure

Common tasks

Rebuild the UI image after a dependency change

Needed when you add npm packages or change build-time UI behavior. Supabase browser config is runtime-injected from the workspace registry, so changing Supabase connections does not require an image rebuild.

Reset the gateway state

Use sparingly. Better: start a fresh Supabase project + a fresh Compose project name (COMPOSE_PROJECT=yourhq-test) in .env so you don’t destroy your real data.

Add a dependency to the UI

Commit package.json and package-lock.json. CI will use the lock.

Run linting / type-checking

Run shellcheck

Shellcheck also runs in CI (severity: warning).

Tests

Today there’s no automated test suite — CI runs typecheck + lint + shellcheck only. Contributions of test infrastructure welcome. For manual testing, see Troubleshooting for known failure modes to verify against.

Publishing images

CI publishes ghcr.io/yourhq/yourhq-{ui,gateway,dispatcher,runner}:latest on every push to main, and versioned tags on v* git tags. To cut a release:
The docker-publish.yml workflow’s type=semver rule publishes :0.x.y tags automatically.

Getting help