docs(ai): record the in-repo ai-bot Synapse appservice (Vojo AI) and the single-file bind-mount / non-root registration gotchas
This commit is contained in:
parent
add6107d66
commit
1385123b55
3 changed files with 19 additions and 2 deletions
|
|
@ -54,6 +54,7 @@ src/
|
|||
└── styles/ # Vanilla-extract global styles (global.css.ts, horseshoe.ts)
|
||||
electron/ # Electron desktop wrapper (see electron.md)
|
||||
apps/widget-{telegram,discord,whatsapp}/ # Preact bot-widget apps (see overview.md)
|
||||
apps/ai-bot/ # Go Synapse appservice — "Vojo AI" (@ai), xAI-Grok backend (server-side, NOT client; see its README + server-side.md)
|
||||
```
|
||||
|
||||
## Pages & Routing (`src/app/pages/`)
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ Value proposition: "Telegram works without VPN" — the server runs a mautrix-te
|
|||
- **Synapse modules**: in-tree `username_blocklist.py` bind-mounted into the Synapse image (`synapse/modules/`)
|
||||
- **Client**: this repo — built and deployed as static files via Caddy
|
||||
- **Bot widgets**: three Preact apps in `apps/widget-{telegram,discord,whatsapp}/`, built independently and deployed to `~/vojo/widgets/{telegram,discord,whatsapp}/` for BotShell to embed
|
||||
- **AI bot ("Vojo AI", `@ai:vojo.chat`)**: a Go **Synapse appservice** in [`apps/ai-bot/`](../../apps/ai-bot/) (xAI-Grok backend; answers `@`-mentions in groups + all 1:1 messages). Built locally + shipped via `docker save`/`load`, deployed to `~/vojo/ai-bot/`. v1 is **backend-only — users add it by inviting `@ai` into any room manually**; the in-app "Bots"-tab widget + "Add to chat" picker (plan Parts B/C) are deferred. Branded **Vojo AI** with a generic icon — "Grok" is only the factual "powered by" attribution + the model id (xAI trademark). 152-ФЗ / transborder-transfer legal gating is a pre-launch item (see `docs/plans/grok_bot.md` §6). See `server-side.md` + `apps/ai-bot/README.md`.
|
||||
|
||||
Server filesystem under `~/vojo/`: `caddy/`, `synapse/`, `postgres/`, `coturn/`, `livekit/`, `sygnal/`, `prometheus/`, `grafana/`, `bridges/{telegram,discord,whatsapp}/`, `widgets/{telegram,discord,whatsapp}/`, `cinny/`, `docker-compose.yml`. Caddy serves the client at `https://vojo.chat` with the host's `cinny/` directory bind-mounted into the container as `/var/www/cinny`.
|
||||
Server filesystem under `~/vojo/`: `caddy/`, `synapse/`, `postgres/`, `coturn/`, `livekit/`, `sygnal/`, `prometheus/`, `grafana/`, `bridges/{telegram,discord,whatsapp}/`, `widgets/{telegram,discord,whatsapp}/`, `ai-bot/`, `cinny/`, `docker-compose.yml`. Caddy serves the client at `https://vojo.chat` with the host's `cinny/` directory bind-mounted into the container as `/var/www/cinny`.
|
||||
|
||||
## Branding
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ in doubt.
|
|||
| Service | Image | Notes |
|
||||
|---|---|---|
|
||||
| `postgres` | `postgres:16` | `POSTGRES_INITDB_ARGS: "--encoding=UTF8 --lc-collate=C --lc-ctype=C"` |
|
||||
| `synapse` | `matrixdotorg/synapse:latest` | Bind-mounts: `./synapse:/data` plus three module mounts (`username_blocklist.py`, `blocked_usernames.txt`, `blocked_patterns.txt` → `/usr/local/lib/python3.13/site-packages/`), and four registration mounts (`bridges/telegram/registration.yaml`, `synapse/doublepuppet.yaml`, `bridges/discord/registration.yaml`, `bridges/whatsapp/registration.yaml`) into `/data/*-registration.yaml`. Exposes 8008. |
|
||||
| `synapse` | `matrixdotorg/synapse:latest` | Bind-mounts: `./synapse:/data` plus three module mounts (`username_blocklist.py`, `blocked_usernames.txt`, `blocked_patterns.txt` → `/usr/local/lib/python3.13/site-packages/`), and **five** registration mounts (`bridges/telegram/registration.yaml`, `synapse/doublepuppet.yaml`, `bridges/discord/registration.yaml`, `bridges/whatsapp/registration.yaml`, `ai-bot/registration.yaml`) into `/data/*-registration.yaml`. Exposes 8008. |
|
||||
| `caddy` | `caddy:2` | Ports 80/443/8448. Bind-mounts `./caddy/Caddyfile`, `./caddy/data`, `./caddy/config`, `./cinny:/var/www/cinny`, **and the three `widgets/<bridge>` directories** (Caddy serves them at the bot widget origins). |
|
||||
| `coturn` | `coturn/coturn:latest` | `network_mode: host`; `./coturn/turnserver.conf` mounted read-only at `/etc/coturn/turnserver.conf`. |
|
||||
| `livekit` | LiveKit server image | Backed by `./livekit/livekit.yaml` + `./livekit/secrets`. Element Call backend. **(env / image tag not on hand — read the file)** |
|
||||
|
|
@ -130,6 +130,7 @@ in doubt.
|
|||
| `telegram-bridge` | `dock.mau.dev/mautrix/telegram:<v26.04 bridgev2 tag>` | `./bridges/telegram:/data` |
|
||||
| `discord-bridge` | `dock.mau.dev/mautrix/discord:v0.7.5` | `./bridges/discord:/data` (legacy bridge — runtime reports `0.7.6+dev`) |
|
||||
| `whatsapp-bridge` | `dock.mau.dev/mautrix/whatsapp:v0.12.4` | `./bridges/whatsapp:/data` |
|
||||
| `ai-bot` | `ai-bot:custom` (built locally from [`apps/ai-bot/`](../../apps/ai-bot/), shipped via `docker save \| ssh docker load` — VS Code task **Deploy AI bot**) | **Vojo AI** = `@ai:vojo.chat`, an xAI-Grok-backed **application service** (NOT a normal bot user). Answers `@`-mentions in groups + everything in 1:1s. Mounts `./ai-bot:/data` (owned **uid 65532**, distroless nonroot) holding `registration.yaml` (self-generated, `generate-registration`), `state/` (SQLite spend ledger + txn dedup) and `secrets/xai_api_key`. Push port `:8009` (registration `url: http://ai-bot:8009`). Secrets via env/`*_FILE`; `as_token`/`hs_token` read from `registration.yaml` (no rotation). See [`apps/ai-bot/README.md`](../../apps/ai-bot/README.md). |
|
||||
|
||||
### Bridge service stanza (template)
|
||||
|
||||
|
|
@ -203,6 +204,20 @@ configs:
|
|||
`registration.yaml`. (bridgev2 — telegram/whatsapp — does this correctly.)
|
||||
6. **Double puppeting secret prefix `as_token:` is mandatory.** Without it, the bridge
|
||||
tries to find the deprecated `synapse-shared-secret-auth` Synapse module.
|
||||
7. **Single-file bind-mount + `depends_on` = phantom directory.** Docker creates the
|
||||
*source* of a single-file bind-mount as an **empty directory** if it doesn't exist when
|
||||
the container starts. This bit the `ai-bot` bring-up: Synapse `depends_on`-started while
|
||||
`ai-bot/registration.yaml` didn't exist yet → Docker made it a dir → Synapse crashed
|
||||
`IsADirectoryError`, and `generate-registration` then saw the dir and refused to write.
|
||||
Rule: **generate the file BEFORE the mounting container starts.** Generate the bot's
|
||||
registration with `docker compose run --rm --no-deps ai-bot generate-registration`
|
||||
(`--no-deps` so Synapse doesn't start and recreate the dir). Bridges avoid this because
|
||||
each bridge writes its own `registration.yaml` into its `/data` before Synapse mounts it.
|
||||
8. **Registration files must be world-readable (`644`).** The Synapse container runs
|
||||
**non-root**, so a `0600` registration owned by another uid yields `PermissionError`.
|
||||
`ai-bot`'s `generate-registration` writes `0644` for this reason (token secrecy relies on
|
||||
host access control on the single-tenant VPS, not the file mode). The xAI key stays a
|
||||
separate `0600`-ish secret file the bot reads as its own uid.
|
||||
|
||||
## Refresh procedure
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue