Docker

Run oversight as a Docker container for local development or production deployment. The multi-stage Dockerfile builds all three workspace packages (shared, server, web) into a single production image.

Single Container

The included Dockerfile uses a multi-stage build based on node:20-slim. The first stage installs dependencies with pnpm, builds all packages, and writes a build-hash.txt. The production stage copies only the compiled output and production dependencies.

Build the image bash
docker build \
  --build-arg VITE_SUPABASE_URL=https://<ref>.supabase.co \
  --build-arg VITE_SUPABASE_ANON_KEY=<anon-key> \
  -t oversight:latest .

The VITE_* build args are baked into the web frontend at build time. Server-side variables are provided at runtime instead.

Run the container bash
docker run -d \
  --name oversight \
  -p 3001:3001 \
  -e SUPABASE_URL=https://<ref>.supabase.co \
  -e SUPABASE_SERVICE_ROLE_KEY=<service-role-key> \
  -e SUPABASE_ANON_KEY=<anon-key> \
  -e NODE_ENV=production \
  oversight:latest

Environment Variables

Build-time (ARG)

Variable Required Description
VITE_SUPABASE_URL Yes Supabase project URL, baked into the web frontend
VITE_SUPABASE_ANON_KEY Yes Supabase anon/public JWT, baked into the web frontend
RAILWAY_GIT_COMMIT_SHA No Git SHA used for the build hash (defaults to dev)

Runtime (ENV)

Variable Required Description
SUPABASE_URL Yes Supabase project URL
SUPABASE_SERVICE_ROLE_KEY Yes Supabase service role JWT (Settings > API)
SUPABASE_ANON_KEY Yes Supabase anon/public JWT (Settings > API)
PORT No Server listen port (default: 3001)
NODE_ENV No Set to production for optimized logging

Docker Compose

For a full local stack you can run the server, runner, and web dev server together. The runner is a separate long-lived process that polls the Supabase tasks table and executes work locally using the Claude CLI.

docker-compose.yml yaml
version: "3.9"

services:
  server:
    build:
      context: .
      args:
        VITE_SUPABASE_URL: ${VITE_SUPABASE_URL}
        VITE_SUPABASE_ANON_KEY: ${VITE_SUPABASE_ANON_KEY}
    ports:
      - "3001:3001"
    environment:
      - SUPABASE_URL=${SUPABASE_URL}
      - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY}
      - SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
      - NODE_ENV=production
    restart: on-failure

  runner:
    build:
      context: .
    command: node packages/server/dist/runner.js
    environment:
      - SUPABASE_URL=${SUPABASE_URL}
      - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY}
      - SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
      - RUNNER_USER_ID=${RUNNER_USER_ID}
    volumes:
      - runner-data:/app/data
    restart: on-failure

volumes:
  runner-data:
Note: The runner requires access to the claude CLI on the host machine. In most setups you will run the runner outside Docker with pnpm runner and only containerize the server.

Health Endpoint

The server exposes GET /api/health which returns {"status":"ok"} with a 200 status code. Use this for Docker health checks and load balancer probes.

Docker health check bash
docker run -d \
  --health-cmd="curl -f http://localhost:3001/api/health || exit 1" \
  --health-interval=30s \
  --health-timeout=5s \
  --health-retries=3 \
  oversight:latest

Building from Source

The build process compiles three workspace packages in order: @oversight/shared, then @oversight/server, then @oversight/web. A build hash is written to build-hash.txt at the project root.

Manual build bash
# Clone and install
git clone https://github.com/CopilotKit/oversight.git
cd oversight
pnpm install

# Build all packages
pnpm run build

# Start the server
node packages/server/dist/index.js

Requires Node.js ≥ 20 and pnpm ≥ 9. The server listens on port 3001 by default and serves both the API and the static web frontend from packages/web/dist.