services: pinchy: image: ghcr.io/heypinchy/pinchy:${PINCHY_VERSION:?set PINCHY_VERSION in .env (e.g. PINCHY_VERSION=v0.5.0)} ports: - "${PINCHY_PORT:-127.0.0.1:7777}:7777" environment: - DATABASE_URL=postgresql://pinchy:${DB_PASSWORD:-pinchy_dev}@db:5432/pinchy - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-} - OPENCLAW_WS_URL=ws://openclaw:18789 - ENCRYPTION_KEY=${ENCRYPTION_KEY:-} - PINCHY_ENTERPRISE_KEY=${PINCHY_ENTERPRISE_KEY:-} volumes: - openclaw-config:/openclaw-config - openclaw-secrets:/openclaw-secrets - pinchy-workspaces:/openclaw-config/workspaces - openclaw-extensions:/openclaw-extensions - pinchy-secrets:/app/secrets # KB corpus, read-only. The knowledge-base ingest pipeline and the # workspace-file serve route (packages/web) read source documents from # /data — the SAME path the openclaw service mounts, so an agent's # allowed_paths (/data/...) resolve identically in both containers. # Read-only: web only reads the corpus (it never writes it; user uploads # land in a separate store), which also keeps the corpus tamper-proof # from the web tier. - pinchy-data:/data:ro restart: unless-stopped depends_on: db: condition: service_healthy healthcheck: test: [ "CMD-SHELL", 'node -e "require(''http'').get(''http://localhost:7777/api/internal/openclaw-config-ready'', r => process.exit(r.statusCode === 200 ? 0 : 1))"', ] interval: 2s timeout: 3s retries: 30 start_period: 5s # Resource limits (#263) — overridable via env for larger deployments. mem_limit: ${PINCHY_MEM_LIMIT:-1g} cpus: ${PINCHY_CPUS:-1.5} openclaw: image: ghcr.io/heypinchy/pinchy-openclaw:${PINCHY_VERSION:?set PINCHY_VERSION in .env (e.g. PINCHY_VERSION=v0.5.0)} expose: - "18789" extra_hosts: # ollama.local is mapped to the host gateway so the OpenClaw container can # reach Ollama on the host. Pinchy normalizes every container-host alias # (host.docker.internal, *.orb.internal, ...) -> ollama.local in the # emitted config, which clears OpenClaw's isLocalBaseUrl via the stable # `.local` rule -- a deliberate decoupling from its host-alias allowlist # (which has changed across versions). See # packages/web/src/lib/openclaw-local-url.ts. - "ollama.local:host-gateway" volumes: - openclaw-config:/root/.openclaw - openclaw-secrets:/openclaw-secrets - pinchy-workspaces:/root/.openclaw/workspaces - openclaw-extensions:/root/.openclaw/extensions - pinchy-data:/data - pinchy-pdf-cache:/var/cache/pinchy-files restart: unless-stopped depends_on: pinchy: condition: service_healthy # Liveness check: the gateway listens on 18789. A TCP connect succeeds once # the WS server is up (the OpenClaw start script's own health loop respawns # the gateway process if it dies). This is diagnostic only — Compose does # NOT restart an unhealthy-but-running container, so a stuck container # surfaces as `unhealthy` in `docker compose ps` for an operator to act on, # it does not self-heal. #263 healthcheck: test: [ "CMD-SHELL", 'node -e "const s=require(''net'').connect(18789,''localhost'');s.on(''connect'',()=>process.exit(0));s.on(''error'',()=>process.exit(1));setTimeout(()=>process.exit(1),2000)"', ] interval: 10s timeout: 5s retries: 5 start_period: 15s mem_limit: ${OPENCLAW_MEM_LIMIT:-2g} cpus: ${OPENCLAW_CPUS:-2} db: # pgvector/pgvector:pg17-trixie bundles the pgvector extension's shared # library on top of postgres:17 so `CREATE EXTENSION vector` (see # packages/web/drizzle/0054_safe_vision.sql) succeeds. Powers the # knowledge-base RAG index (kb_documents/kb_chunks, vector(1024) columns). # # Pinned to the `-trixie` variant, NOT the bare `pg17` tag: the plain # `pgvector/pgvector:pg17` tag is built on Debian 12 (bookworm), while # the `postgres:17` image it replaces here currently resolves to Debian # 13 (trixie). Swapping to a different glibc base on an EXISTING data # volume (any real dev/prod install doing `docker compose pull && up`, # not just a fresh `initdb`) trips Postgres's collation-version guard — # `CREATE DATABASE` on the mismatched template1 errors outright # ("template database ... has a collation version mismatch"), verified # locally by swapping images in place on a volume initialized under # postgres:17. `-trixie` matches postgres:17's current base exactly, so # in-place upgrades of existing volumes don't hit this. image: pgvector/pgvector:pg17-trixie volumes: - pgdata:/var/lib/postgresql/data environment: - POSTGRES_DB=pinchy - POSTGRES_USER=pinchy - POSTGRES_PASSWORD=${DB_PASSWORD:-pinchy_dev} restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U pinchy"] interval: 5s timeout: 5s retries: 5 mem_limit: ${DB_MEM_LIMIT:-1g} cpus: ${DB_CPUS:-1} volumes: pgdata: openclaw-config: pinchy-workspaces: pinchy-data: pinchy-secrets: openclaw-extensions: pinchy-pdf-cache: openclaw-secrets: driver: local driver_opts: type: tmpfs device: tmpfs # uid/gid match the pinchy user inside the Pinchy container # (Dockerfile.pinchy: useradd -r → uid 999). OpenClaw runs as root # and can write here regardless of ownership; Pinchy needs ownership # to atomically rewrite secrets.json via writeSecretsFile(). o: "mode=0770,uid=999,gid=999"