# Arbo (catalog) engine — FastAPI sidecar that drives ComfyUI from a # versioned workflow catalog. Serves the SPA + /workflows + /run. # # Co-located on irv-ml1 BESIDE the comfyui stack (ADR-0001 / D3). This # collapses the engine<->ComfyUI link to the shared traefik-net + the # local filesystem and ELIMINATES the old SSH/WireGuard dependency: # - generation : COMFYUI_URL=http://comfyui:8188 (container DNS on # traefik-net — the "localhost-equivalent"; no scp, no WG hop) # - file ops : ARBO_COMFY_INPUT_DIR / ARBO_COMFY_OUTPUT_DIR bind the # SAME host dirs comfyui mounts (/worktank/comfyui/basedir/{input, # output}), so to-input / upload-input / artifact-wipe are local fs # ops. ARBO_COMFY_SSH_HOST is left UNSET on purpose → the engine's # local-cp/shutil path (comfy-dev's D3 follow-on) takes over. # # State that MUST survive restarts (named volumes, local disk — NOT NFS, # per the DB-off-NFS rule; SQLite-on-NFS locking is a known foot-gun): # - arbo_db -> the gallery/history SQLite (ARBO_DB) # - arbo_heroes -> runtime hero images (ARBO_HEROES_DIR) # The catalog is a comfy-dev git checkout bind-mounted read-only (D2): # a workflow update = `git pull` on the host + restart, no image rebuild. # # IMAGE + CATALOG TARGET are owned by comfy-dev (they build the image + # add /healthz). Two items marked CONFIRM below need their image layout. # All tunables live in .env — edit that, not this file. services: engine: image: ${ARBO_IMAGE} # CONFIRM: gitea.phasefinal.com/vh/arbo:, comfy-dev builds container_name: arbo restart: unless-stopped # Run as the host owner of /worktank (1000:1000 = lkraven) so writes # into comfyui's basedir/input + the named volumes land with the # right ownership (matches the comfyui stack's WANTED_UID posture). user: "${ARBO_UID:-1000}:${ARBO_GID:-1000}" ports: - "${ARBO_BIND:-0.0.0.0}:${ARBO_PORT:-8200}:8200" env_file: .env environment: - ARBO_HOST=0.0.0.0 - ARBO_PORT=8200 - ARBO_DB=/data/gallery.sqlite - ARBO_HEROES_DIR=/heroes # engine<->ComfyUI over the shared network (no SSH): - COMFYUI_URL=http://comfyui:8188 - ARBO_COMFY_INPUT_DIR=/comfy/input - ARBO_COMFY_OUTPUT_DIR=/comfy/output # ARBO_COMFY_SSH_HOST intentionally UNSET -> local-cp path (D3 follow-on) # LiteLLM gateway for the granite hero/metadata calls: - GRANITE_ENDPOINT=http://10.250.50.70:4000/v1 - GRANITE_KEY=${GRANITE_KEY} # arbo-prompt-enhance scoped vkey (.env) # ENGINE_TOKEN intentionally NOT injected — bearer auth is OFF on prod by # operator decision (2026-06-13); WireGuard is the access boundary. The # app's protected-gate no-ops only when the var is ABSENT — an empty string # still gates — so it must not be set here OR in .env. Re-enable: restore # this line + set ENGINE_TOKEN in .env, then `compose up -d`. Reverses ADR-0001. #- ENGINE_TOKEN=${ENGINE_TOKEN} volumes: - arbo_db:/data - arbo_heroes:/heroes # comfyui's input/output, shared on the host (rw: upload-input writes # input, artifact-wipe deletes output): - /worktank/comfyui/basedir/input:/comfy/input - /worktank/comfyui/basedir/output:/comfy/output # comfy-dev checkout on the host (D2 git-pull target), read-only. catalog + # graphs + frontend all ride the mount, so a catalog OR SPA change reaches # prod via `git pull + restart` — no image rebuild (ADR-0001 D2, extended to # the frontend per the v0.11.2 prod fix). Baked image copies are the fallback. - ${ARBO_CATALOG_DIR:-/worktank/arbo/repo}/catalog:/app/catalog:ro - ${ARBO_CATALOG_DIR:-/worktank/arbo/repo}/graphs:/app/graphs:ro - ${ARBO_CATALOG_DIR:-/worktank/arbo/repo}/frontend:/app/frontend:ro # pyproject.toml rides the same checkout mount so /healthz catalog_version # reports the MOUNTED repo version (read from /app/pyproject.toml), not the # baked importlib.metadata one — otherwise a catalog/frontend-only webhook # deploy (no image rebuild) leaves the reported version stale (comfy-dev # v0.12.5 observability fix, 2026-06-16). Activated on the next engine # recreate; the code falls back cleanly if the file is absent. - ${ARBO_CATALOG_DIR:-/worktank/arbo/repo}/pyproject.toml:/app/pyproject.toml:ro # python-based (the slim image ships no curl/wget; python is always present): healthcheck: test: ["CMD-SHELL", "python -c \"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8200/healthz').status==200 else 1)\""] interval: 30s timeout: 10s retries: 3 start_period: 30s networks: - tnet labels: - homepage.group=AI - Studios - homepage.name=Arbo - homepage.icon=mdi-image-multiple-outline - homepage.description=Catalog-driven ComfyUI engine (irv-ml1) - homepage.href=http://10.100.79.3:${ARBO_PORT:-8200} volumes: arbo_db: name: arbo_db arbo_heroes: name: arbo_heroes networks: tnet: name: traefik-net external: true