Files
Maven/deploy/README.md
T
kami cb3641e7bb Read RSS and Atom feeds, and speak about them only when asked (#258)
internal/rss parses RSS 2.0 and Atom, and polls each configured feed on its own
interval; internal/webfetch is the one door either of them uses to touch the
network. The poller writes items as notes with source "rss:<feed>" and nothing
else: the answer path reads them back when he asks "что нового в лентах?", and
nothing is announced on arrival. A feed that dispatched would be a nag, which is
why the plan's breaking-news rule was left out rather than built.

webfetch is where the limits live, as code rather than a paragraph: http(s)
only, an allowlist (the configured feeds' hosts) and a denylist, a 2 MiB body
cap, a 3-redirect cap, one request per host per second, and a refusal to connect
to any private address — checked in the dialer's Control hook so it holds for
every resolved address and every redirect hop, not just for a literal IP.

Off unless configured: no "feeds" block, no poller, no outbound request. How far
a feed was read is a config fact (rss:latest:<name>), so a restart does not
re-note yesterday's headlines.
2026-08-01 03:27:45 +04:00

87 lines
3.7 KiB
Markdown

# Maven — Docker deployment
One image, one container per daemon (`docker-compose.yml`). Core (`mavend`)
holds the encryption key and the db; the modules mount only the shared socket
dir and read-only models.
## First run
```sh
# 1. generate the at-rest db key (32 bytes, base64) — keep it safe, losing it loses the db
cp deploy/db_key.env.example deploy/db_key.env
printf 'MAVEN_DB_KEY=%s\n' "$(openssl rand 32 | base64 -w0)" > deploy/db_key.env
# 2. build + start
docker compose build
docker compose up -d
# 3. logs
docker compose logs -f mavend
```
`models/` and `deps/` are bind-mounted / baked from the host — they are NOT in
git (fetched via `make deps` + downloaded models). The build context needs
`deps/lib`, `deps/piper`, `deps/include`, and `deps/whisper.cpp/ggml/include`
present (see `.dockerignore`).
## Layout
| Path (in container) | What |
|----------------------------|-----------------------------------------|
| `/opt/maven/bin` | the six daemons |
| `/opt/maven/lib` | native .so (whisper+vulkan, onnxruntime)|
| `/opt/maven/piper` | piper binary + espeak data |
| `/opt/maven/models` (ro) | bind-mount of `./models` |
| `/run/maven` (volume) | shared IPC sockets |
| `/var/lib/maven` (volume) | encrypted db at rest |
| `/dev/shm` (tmpfs) | decrypted db working copy (RAM only) |
## Reading the outside world (off by default)
`mavend.json` ships without a `feeds` block, which means no RSS/Atom feed is
fetched and no outbound request is made. Switching it on is adding the block:
```json
"feeds": {
"poll_interval": "30m",
"max_items": 5,
"max_age": "24h",
"sources": [
{ "name": "habr", "url": "https://habr.com/ru/rss/best/daily/",
"category": "технологии", "exclude": ["реклама"] }
]
}
```
What it does and does not do:
- items are written as notes with source `rss:<name>`, visible on `/dash`;
- **nothing is announced.** She reads them back when asked — "что нового в
лентах?", "что нового по технологиям?" — and never on arrival. There is no
severity or channel knob here on purpose;
- the fetcher is allowlisted to the hosts of the configured feeds, plus any
`allow_hosts`. It refuses non-http(s) schemes and every private address
(loopback, the LAN, the `10.42.0.0/24` wg range, cloud metadata). It caps the
response at 2 MiB and redirects at 3, and makes at most one request per host
per second. See `internal/webfetch`;
- how far each feed was read is stored as a config fact `rss:latest:<name>`, so
a restart does not re-note yesterday's headlines.
## Not yet verified / host-dependent
This stack is correct-by-construction but has **not been build-tested here**
(no docker in the authoring env; ~1GB context; GPU). Expect a tweak on first
build on the target host, most likely in one of these:
- **GPU passthrough** — `mavsttd` maps `/dev/dri` for Vulkan. On an NVIDIA host
you'd swap to the nvidia container runtime instead of `/dev/dri`.
- **onnxruntime lib path** — `mavend`'s embedder needs `libonnxruntime.so`
(on `LD_LIBRARY_PATH=/opt/maven/lib`). If the embedder wants an explicit
path, set it in the config's embedder block.
- **cross-container voice** — `mavweb -voice mavend:9100` only works once
`mavend` binds its voice server on `0.0.0.0:9100` (Voice config, currently
unset). Until then, voice-over-web is inert; `/tools`, passkey, and the dash
work fine over the core socket.
- **netdata** — `mavpoll` reaches it via `host.docker.internal`; adjust if
netdata runs elsewhere.