name: maven # One image (built once), one container per daemon. Only mavend holds the key # and the db volume; the modules mount just the shared socket dir + models. # IPC stays unix-domain over the shared `sockets` volume — no code change from # the bare-metal setup, only paths move to /run/maven. x-image: &image # NOT "maven" — that's Apache Maven on Docker Hub and compose will happily # pull it, giving every container `mvn-entrypoint.sh` and exit 127. image: mavenai:latest # build on EVERY service (same image name ⇒ built once) so `docker compose # build ` actually rebuilds. With build on only one service, the # others silently no-op and you deploy a stale binary. build: . pull_policy: never # only ever the locally-built image restart: unless-stopped # local time for clock/date replies AND quiet-hours evaluation. Change to # your zone; needs tzdata in the image (installed in the Dockerfile). environment: - TZ=Europe/Samara services: mavend: <<: *image command: ["mavend", "-config", "/opt/maven/config/mavend.json"] # both nets: `default` keeps the `mavend` DNS name the other daemons reach # (mavweb -> mavend:9100); `ecosystem` reaches nexus/praxis/hexis by name. networks: [default, ecosystem] # the key lives ONLY here. deploy/db_key.env holds MAVEN_DB_KEY=. env_file: - ./deploy/db_key.env - ./deploy/telegram.env volumes: - dbdata:/var/lib/maven # encrypted db at rest - sockets:/run/maven # IPC socket dir - ./deploy/mavend.json:/opt/maven/config/mavend.json:ro - ./models:/opt/maven/models:ro - /mnt/hdd1/llms:/opt/maven/models/llm:ro # LFM gguf library # the LFM engine (llama-server) offloads onto the AMD iGPU (RADV RENOIR, # Ryzen 5 5600U) via Vulkan — same device + render gid as mavsttd, which # uses the same driver for whisper. Without these Vulkan # enumerates zero devices and llama-server silently falls back to CPU. devices: - "/dev/dri:/dev/dri" group_add: - "993" # host 'render' gid owning /dev/dri/renderD128 (getent group render) # the decrypted working copy lives in RAM (see db_tmpfs in mavend.json). tmpfs: - /dev/shm mavsttd: <<: *image command: ["mavsttd", "-socket", "/run/maven/stt.sock", "-model", "/opt/maven/models/stt/ggml-small.bin"] depends_on: [mavend] # whisper uses libggml-vulkan (RADV on the host's AMD GPU) → needs the # render node AND membership in the group that owns it, or Vulkan enumerates # zero devices and falls back to CPU. devices: - "/dev/dri:/dev/dri" group_add: - "993" # host 'render' gid owning /dev/dri/renderD128 (getent group render) volumes: - sockets:/run/maven - ./models:/opt/maven/models:ro mavttsd: <<: *image command: ["mavttsd", "-socket", "/run/maven/tts.sock", "-piper", "/opt/maven/piper/piper", "-model", "/opt/maven/models/tts/ru_RU-irina-medium.onnx", "-espeak_data", "/opt/maven/piper/espeak-ng-data"] depends_on: [mavend] volumes: - sockets:/run/maven - ./models:/opt/maven/models:ro mavweb: <<: *image # voice.bind is 0.0.0.0:9100 in deploy/mavend.json so mavweb can reach it # cross-container. Verified 2026-07-06. command: ["mavweb", "-addr", ":9201", "-voice", "mavend:9100", "-core", "/run/maven/mavend.sock", "-nexus", "http://nexus:9740", "-praxis", "http://praxis:8989", "-hexis", "http://hexis:9741"] depends_on: [mavend] # loopback-only on purpose: /tools defines+executes arbitrary argv and # mavweb has no in-process auth of its own without -webauthn-origin/-rpid. # Reaching the UI therefore requires the wg tunnel (or the local nginx) by # construction, not by convention. The other daemons talk to mavweb over # the compose network, not this published port. ports: ["127.0.0.1:9201:9201"] # ecosystem: reach the siblings by name for the read-only /ecosystem panel; # default: keep resolving mavend:9100 for voice + the IPC socket peers. networks: [default, ecosystem] volumes: - sockets:/run/maven mavpoll: <<: *image network_mode: host command: ["mavpoll", "-socket", "/run/maven/mavend.sock", "-netdata", "http://127.0.0.1:19999", "-kuma", "http://127.0.0.1:3001/metrics", "-kuma-key", "uk5_mavpoll-key"] depends_on: [mavend] volumes: - sockets:/run/maven volumes: dbdata: sockets: networks: default: ecosystem: external: true # created by deploy/ecosystem/docker-compose.yml name: ecosystem