Files
Maven/docs/operations.md
claude 93987f2dfc docs: tier the tree by lifetime, so staleness shows in the path (V-446)
Seventeen markdown files at the repo root, twelve of them dated one-shot
reports sitting next to CLAUDE.md. That is why stale docs read as
current: nothing in the path said which was which.

Root now keeps CLAUDE.md and AGENTS.md. Living docs move under docs/
and carry a Last verified line. Dated measurements move to docs/evals/
ISO-prefixed, and are never edited after the day, so a newer number is
a new file. The senior review moves to docs/archive/.

Every reference was rewritten across markdown, Go comments, the Makefile
and the recall fixture. The touched Go packages still build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 03:28:49 +04:00

5.8 KiB

Start Commands

Last verified: 2026-08-02 @ 7079a24. Living doc: correct it in place, do not append.

All commands assume ROOT=/home/kami/apps/Maven and the local Go toolchain at $ROOT/deps/go/go/bin/go.

Prerequisites

export ROOT=/home/kami/apps/Maven
export CGO_CFLAGS="-I$ROOT/deps/include -I$ROOT/deps/whisper.cpp/ggml/include"
export CGO_LDFLAGS="-L$ROOT/deps/lib -Wl,-rpath,$ROOT/deps/lib"
export LD_LIBRARY_PATH="$ROOT/deps/lib"
export PATH="$ROOT/deps/go/go/bin:$PATH"

Build everything

cd "$ROOT"
go build ./cmd/mavend/
go build ./cmd/mavsttd/   # needs CGO (whisper.cpp)
go build ./cmd/mavttsd/   # pure Go

mavend — daemon (core)

cd "$ROOT"
./mavend -config mavend.json

Config path: ~/.config/maven/mavend.json. Full example with all options.

The phraser.model_path below is an example — point it at whatever GGUF you have locally. The deployed value lives in deploy/mavend.json, currently Qwen3.5-0.8B.Q4_K_M.gguf; the target is the CPT'd Qwen3-1.7B (#122).

{
  "db_path": "/home/kami/.local/share/maven/maven.db",
  "socket_path": "/run/user/1000/maven/mavend.sock",
  "tick_interval": "60s",
  "repeat_interval": "5m",
  "ntfy": {
    "base_url": "https://ntfy.kvmx.ru",
    "topic": "maven"
  },
  "phraser": {
    "model_path": "/mnt/hdd1/llms/Qwen3-Maven-1.7B-Q8_0.gguf",
    "bin_path": "/usr/local/bin/llama-server",
    "n_gpu_layers": -1
  },
  "voice": {
    "enabled": true,
    "bind": "127.0.0.1:9100",
    "lang": "ru",
    "embedder": {
      "model_path": "models/embedder/model.onnx",
      "tokenizer_path": "models/embedder/tokenizer.json",
      "lib_path": "deps/onnxruntime-linux-x64-1.17.1/lib/libonnxruntime.so.1.17.1"
    }
  }
}

Omit the embedder block entirely to use the deterministic HashEmbedder floor (no ML, no ONNX runtime dependency). Useful for testing or low-resource setups.

mavsttd — STT worker (optional, remote whisper.cpp)

Requires LD_LIBRARY_PATH to include deps/lib (for libwhisper.so, libggml-vulkan.so).

cd "$ROOT"
export LD_LIBRARY_PATH="$ROOT/deps/lib"
./mavsttd -socket /run/user/$UID/maven/stt.sock -model models/stt/ggml-small.bin

Without -model it runs as a stub (deterministic, no ML).

mavttsd — TTS worker (optional, remote Piper)

Requires LD_LIBRARY_PATH to include deps/piper (for Piper's espeak-ng).

cd "$ROOT"
export LD_LIBRARY_PATH="$ROOT/deps/piper"
./mavttsd -socket /run/user/$UID/maven/tts.sock -piper deps/piper/piper -model models/tts/ru_RU-irina-medium.onnx -espeak_data deps/piper/espeak-ng-data

Without -piper it runs as a stub.

mavweb — PWA voice bridge (WebSocket ↔ TCP)

No CGo, no deps; builds with stock Go.

cd "$ROOT"
go build ./cmd/mavweb/
./mavweb -addr :9200 -voice 127.0.0.1:9100

To also receive proactive nudges in-app, pass the ntfy WebSocket subscribe URL (the PWA connects to it directly; the auth token stays server-side config):

./mavweb -addr :9200 -voice 127.0.0.1:9100 \
  -ntfy 'wss://ntfy.kvmx.ru/maven/ws?auth=<base64-token>'

<base64-token> is a read-capable ntfy access token, base64url-encoded (ntfy's browser-WS auth: Bearer tk_... can't set a header, so ntfy takes it as the ?auth= query param). Without -ntfy, the PWA stays voice-only.

presence-signal ingest (-core)

Pass mavend's IPC socket so mavweb can feed presence via /api/signal:

./mavweb -addr :9200 -voice 127.0.0.1:9100 \
  -core /run/user/1000/maven/mavend.sock
  • page_heartbeat (weak, τ=4min) — the PWA auto-pings every 30s. Nothing to do.
  • desk_active (strongest, τ=8min) — a workstation signal (hyprland), so it can't be a homesrv module. Run scripts/desk-active.sh on the PC via a systemd-user timer, gated by hypridle (see the script header). Posts over wg.
  • wg_handshake (coarse, τ=20min) — still unfed; it's homesrv-local (wg show latest-handshakes), a natural small poller to add next.

Allowlisted keys only; without -core, /api/signal returns 503 and presence stays cold-start away.

Open http://10.42.0.1:9200/ (or http://voice.kvmx.ru:9200/) on your phone from inside the WireGuard tunnel. Tap & hold to speak; release to send; the reply plays automatically.

mavpoll — env poller (netdata + uptime-kuma → facts)

Thin adapter: reads netdata alarms + kuma monitor status and writes env facts through core's IPC socket. This is what makes service_down (sev4) and netdata_critical (sev3) rules fire on real data. Runs on homesrv where both services live — hit them on localhost, not the public .kvmx.ru names.

cd "$ROOT"
go build ./cmd/mavpoll/
# netdata only (kuma disabled until its API key exists):
./mavpoll -socket /run/user/$UID/maven/mavend.sock -netdata http://127.0.0.1:19999
# with kuma: create an API key in Kuma → Settings → API Keys, then:
./mavpoll -socket /run/user/$UID/maven/mavend.sock \
  -netdata http://127.0.0.1:19999 \
  -kuma http://127.0.0.1:3001/metrics -kuma-key <API_KEY>

Writes only on value change (append-only, no per-tick churn). service_down aggregates any monitor reading 0 as "down"; per-service granularity is a later add. netdata -timeout/-interval tunable; defaults 8s / 60s.

nginx (optional)

sudo cp cmd/mavweb/nginx.conf /etc/nginx/sites-available/voice.kvmx.ru
sudo ln -sf /etc/nginx/sites-available/voice.kvmx.ru /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Quick smoke test (stubs, no models)

cd "$ROOT"
./mavend -config mavend.json   # voice enabled, no stt/tts/embedder config → all stubs

Run all tests

cd "$ROOT"
go test ./internal/router/ ./internal/delivery/... ./cmd/mavend/ ./cmd/mavsttd/ ./cmd/mavttsd/

Benchmark

cd "$ROOT"
go test -bench=. ./internal/router/ ./cmd/mavsttd/ ./cmd/mavttsd/