Files
vortex/docker-compose.yml
T
Prad NukalaandClaude Fable 5 d57086cd00 feat: unified messaging TUI MVP — Synapse + 7 mautrix bridges + Textual TUI + MCP draft staging
One-command local stack: cp .env.example .env && make up. Idempotent
bootstrap renders Synapse + bridge configs from pristine upstream examples,
provisions databases, registrations, double puppeting, and the admin user.
Textual TUI with bridge manager, in-terminal QR login, and drafts panel.
MCP server exposes read tools and a human-gated draft send workflow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 12:13:13 -04:00

204 lines
5.1 KiB
YAML

name: vortex
x-bridge-common: &bridge-common
restart: unless-stopped
depends_on:
bootstrap:
condition: service_completed_successfully
synapse:
condition: service_healthy
environment:
TZ: ${TZ:-UTC}
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: vortex
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: synapse
POSTGRES_INITDB_ARGS: --encoding=UTF8 --locale=C
TZ: ${TZ:-UTC}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U vortex -d synapse"]
interval: 5s
timeout: 5s
retries: 12
bootstrap:
build: ./bootstrap
environment:
MATRIX_SERVER_NAME: ${MATRIX_SERVER_NAME:-localhost}
MATRIX_USER: ${MATRIX_USER:-admin}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
REGISTRATION_SHARED_SECRET: ${REGISTRATION_SHARED_SECRET:-auto}
DOUBLEPUPPET_SHARED_SECRET: ${DOUBLEPUPPET_SHARED_SECRET:-auto}
BRIDGES_ENABLED: ${BRIDGES_ENABLED:-}
TELEGRAM_API_ID: ${TELEGRAM_API_ID:-}
TELEGRAM_API_HASH: ${TELEGRAM_API_HASH:-}
TZ: ${TZ:-UTC}
volumes:
- data:/data
- ./synapse:/templates/synapse:ro
- ./bridges/templates:/templates/bridges:ro
depends_on:
postgres:
condition: service_healthy
command: /bootstrap.sh
synapse:
image: matrixdotorg/synapse:v1.156.0
restart: unless-stopped
environment:
TZ: ${TZ:-UTC}
volumes:
- type: volume
source: data
target: /data
volume: { subpath: synapse }
ports:
- "8008:8008"
depends_on:
bootstrap:
condition: service_completed_successfully
postgres:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:8008/health')\""]
interval: 5s
timeout: 5s
retries: 24
start_period: 30s
provision:
build: ./bootstrap
environment:
MATRIX_SERVER_NAME: ${MATRIX_SERVER_NAME:-localhost}
MATRIX_USER: ${MATRIX_USER:-admin}
MATRIX_PASSWORD: ${MATRIX_PASSWORD:?set MATRIX_PASSWORD in .env}
TZ: ${TZ:-UTC}
volumes:
- data:/data
depends_on:
synapse:
condition: service_healthy
command: /provision.sh
whatsapp:
<<: *bridge-common
image: dock.mau.dev/mautrix/whatsapp:v0.2606.0
profiles: [whatsapp]
volumes:
- type: volume
source: data
target: /data
volume: { subpath: bridges/whatsapp }
gmessages:
<<: *bridge-common
image: dock.mau.dev/mautrix/gmessages:v26.05
profiles: [gmessages]
volumes:
- type: volume
source: data
target: /data
volume: { subpath: bridges/gmessages }
telegram:
<<: *bridge-common
image: dock.mau.dev/mautrix/telegram:v26.06
profiles: [telegram]
entrypoint: ["/bin/sh", "-c", "if [ ! -f /data/config.yaml ]; then echo 'telegram bridge skipped: TELEGRAM_API_ID / TELEGRAM_API_HASH not set in .env'; exec sleep infinity; fi; exec /docker-run.sh"]
volumes:
- type: volume
source: data
target: /data
volume: { subpath: bridges/telegram }
twitter:
<<: *bridge-common
image: dock.mau.dev/mautrix/twitter:v26.06
profiles: [twitter]
volumes:
- type: volume
source: data
target: /data
volume: { subpath: bridges/twitter }
linkedin:
<<: *bridge-common
image: dock.mau.dev/mautrix/linkedin:v26.04
profiles: [linkedin]
volumes:
- type: volume
source: data
target: /data
volume: { subpath: bridges/linkedin }
discord:
<<: *bridge-common
image: dock.mau.dev/mautrix/discord:v0.7.6
profiles: [discord]
volumes:
- type: volume
source: data
target: /data
volume: { subpath: bridges/discord }
meta:
<<: *bridge-common
image: dock.mau.dev/mautrix/meta:v26.06
profiles: [meta]
volumes:
- type: volume
source: data
target: /data
volume: { subpath: bridges/meta }
mcp:
build: ./mcp
restart: unless-stopped
environment:
MCP_HTTP_PORT: ${MCP_HTTP_PORT:-8765}
MCP_ALLOW_SEND: ${MCP_ALLOW_SEND:-false}
CREDENTIALS_FILE: /shared/credentials.json
DRAFTS_DB: /shared/drafts/drafts.db
STORE_DIR: /shared/mcp-store
TZ: ${TZ:-UTC}
ports:
- "${MCP_HTTP_PORT:-8765}:${MCP_HTTP_PORT:-8765}"
volumes:
- type: volume
source: data
target: /shared
volume: { subpath: shared }
depends_on:
provision:
condition: service_completed_successfully
tui:
build: ./tui
profiles: [tui]
stdin_open: true
tty: true
environment:
CREDENTIALS_FILE: /shared/credentials.json
DRAFTS_DB: /shared/drafts/drafts.db
STORE_DIR: /shared/tui-store
TZ: ${TZ:-UTC}
volumes:
- type: volume
source: data
target: /shared
volume: { subpath: shared }
depends_on:
synapse:
condition: service_healthy
volumes:
pgdata:
data: