# Diwan — docker compose stack # 5 services + SQLite ledger. Reproducible via `docker compose up`. # # Service map: # lobstertrap — Veea's prompt/response inspection proxy (read-path) # zehrava — write-path policy + intent lifecycle (Connor's POC, vendored) # ledger-writer — tails Lobster Trap audit log, normalizes to SQLite # agent-harness — toy CRM agent for the demo (4 tools) # ui — Next.js: Preflight scoreboard, Receipts timeline, review queue # # All services share /data via a named volume; SQLite ledger lives at /data/diwan.db services: lobstertrap: build: context: ./lobstertrap dockerfile: Dockerfile image: diwan/lobstertrap:dev ports: - "8781:8080" # host:8781 → container:8080 (OpenAI-compat proxy) volumes: - ./policies:/policies:ro - ledger:/data # Reach the host's Ollama (or any localhost service) via host.docker.internal. extra_hosts: - "host.docker.internal:host-gateway" # Lobster Trap config is CLI-flag only (no env-var support). Note: the proxy # uses ONLY the backend's scheme+host (path is dropped) — pick a backend # that natively serves /v1/chat/completions at its root (Ollama, OpenAI). command: - "serve" - "--policy" - "/policies/agent-safety.yaml" - "--listen" - ":8080" - "--backend" - "${LOBSTERTRAP_UPSTREAM:-http://host.docker.internal:11434}" - "--audit-log" - "/data/lobstertrap-audit.log" - "--no-dashboard" restart: unless-stopped zehrava: build: context: ./zehrava dockerfile: Dockerfile image: diwan/zehrava:dev ports: - "8782:4000" # host:8782 → container:4000 (Zehrava intent API) volumes: - ./zehrava/policies:/policies:ro - ledger:/data environment: - ZEHRAVA_POLICY_DIR=/policies - ZEHRAVA_LEDGER_PATH=/data/diwan.db - ZEHRAVA_FAIL_CLOSED=true depends_on: - lobstertrap restart: unless-stopped ledger-writer: build: context: ./ledger-writer dockerfile: Dockerfile image: diwan/ledger-writer:dev volumes: - ledger:/data environment: - LOBSTERTRAP_AUDIT_LOG=/data/lobstertrap-audit.log - LEDGER_PATH=/data/diwan.db depends_on: - lobstertrap restart: unless-stopped agent-harness: build: context: ./agent-harness dockerfile: Dockerfile image: diwan/agent-harness:dev volumes: - ledger:/data # for /data/diwan.db, /data/crm.db, /data/side-effects.jsonl environment: - OPENAI_BASE_URL=http://lobstertrap:8080/v1 - ZEHRAVA_URL=http://zehrava:4000 - GEMINI_API_KEY=${GEMINI_API_KEY:-} - LEDGER_PATH=/data/diwan.db depends_on: - lobstertrap - zehrava restart: "no" # demo-on-demand # Diwan host ports live in the 87xx range (agent-box convention — casa, wiki, # kaicalls all live there). Avoids collisions with system services on 3000/4000/8080. ui: build: context: ./ui dockerfile: Dockerfile image: diwan/ui:dev ports: - "8780:3000" # host:8780 → container:3000 (UI) volumes: - ledger:/data:ro environment: - LEDGER_PATH=/data/diwan.db - ZEHRAVA_URL=http://zehrava:4000 - GEMINI_API_KEY=${GEMINI_API_KEY:-} - GEMINI_MODEL=gemini-3.1-pro depends_on: - ledger-writer - zehrava restart: unless-stopped volumes: ledger: driver: local