Files
Maven/CLAUDE.md
T
kami 5fe8f228c1 feat(mavweb): /ecosystem page consuming Nexus/Praxis/Hexis + shell fixes
Add a read-only /ecosystem page that consumes the sibling services'
JSON APIs (Nexus entities, Praxis attention, Hexis capabilities),
fetched concurrently with honest per-panel error states. Siblings stay
headless — mavweb is their human surface (arch §16). Wired via mavweb
-nexus/-praxis/-hexis flags; mavweb joins the ecosystem compose network.

Fix mobile horizontal overflow across all pages: .content is a flex
child with default min-width:auto, so it refused to shrink below the
tables' intrinsic width. min-width:0 lets wide tables pan inside .scroll
instead of dragging the page sideways. Verified via CDP geometry check
(scrollWidth === clientWidth at 430px).

Also includes in-progress Ethos UI redesign, ecosystem deploy compose,
and planning docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 22:04:23 +04:00

4.2 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Maven is a self-hosted, privacy-first voice assistant (Russian + English). Go daemons talking over unix sockets; one resident Qwen3-1.7B for routing + phrasing; whisper.cpp STT, piper TTS. Deploy target is a CPU-only Ryzen laptop (homesrv) — the resident model stays at 1.7B. See REARCH.md for the target architecture and AGENTS.md for local-preview + model-download recipes.

Build & test

CGO daemons (mavend, mavsttd, mavttsd, mavenclient) need the vendored toolchain and libs wired through the Makefile — do not call go build on them bare, use make:

make build          # all 8 binaries
make build-web      # single daemon (pure-Go ones: web/waked/poll/caldav build without CGO)
make test           # go test -race across ./internal/... ./cmd/... with CGO env set

Run a single test (must carry the CGO env for packages that touch STT/TTS/voice):

CGO_CFLAGS="-I$(pwd)/deps/include -I$(pwd)/deps/whisper.cpp/ggml/include" \
CGO_LDFLAGS="-L$(pwd)/deps/lib -Wl,-rpath,$(pwd)/deps/lib" \
LD_LIBRARY_PATH="$(pwd)/deps/lib" \
deps/go/go/bin/go test -run TestName ./internal/router/

Pure-Go packages (router, memory, mavweb, …) run under a plain go test ./pkg/.

The daemons (cmd/)

Binary Role
mavend Core. Router, phraser, memory, reminders, digestion tick. Owns the DB + IPC socket.
mavweb HTTP UI + PWA (/dash, /history, /trace, /notifications, /tools); WebAuthn auth. Connects to mavend's socket.
mavsttd Speech-to-text (whisper.cpp, CGO).
mavttsd Text-to-speech (piper subprocess).
mavwaked Wake-word / VAD gate.
mavenclient Voice loop client (mic → stt → core → tts).
mavpoll Telegram long-poll reach.
mavcaldav CalDAV calendar sync.

Daemons are wired socket-to-socket, not linked. internal/ipc is the client/server wire protocol; the config in deploy/mavend.json (with ${VAR} env expansion from gitignored deploy/telegram.env) sets socket paths, model paths, and the phraser/embedder blocks.

Routing — read this before touching the router

internal/router/ has TWO layered engines and the committed default is an interim stopgap, not the intended design (see memory routing-architecture-target):

  • Target (REARCH.md): LLM-as-router. One resident Qwen3-1.7B (llmrouter.go) emits GBNF-constrained structured JSON, and the SAME model phrases replies. Embedder is demoted from a routing gate to a RAG hint.
  • Current stopgap: llmrouter is wired nil (around voice.go), so the classifier.go + embedder.go nearest-neighbour cascade actually runs. It routes by similarity to frozen seed phrases — the known cause of weak RU query handling.

Cascade order: stage0.go exact-match fast-path → LLM router (when non-nil) → classifier fallback. Any LLM error falls through to the classifier so a turn never breaks on the model.

LLM output contract

All phrasing paths emit {"response":"...","mood":"..."} (parsed in replier_llm.go and internal/phraser/llmphraser.go), with fallback to plain text and the legacy {"body","summary"}. Mood is a fixed enum. Router prompt is a separate contract: [{"intent":<enum>, key?, value?, text?, verb?}, ...], 7 intents (fact, reminder, note, query, act, chat, system). llm/check_prompt_parity.py in the training workspace enforces that the Go and relabelling prompts remain identical.

Non-goals (hard constraints)

Never phones home. Not a nag, not autonomous. Maven's persona is feminine — Russian self-reference must use feminine forms (the user is male; see memory maven-persona-gender).

Web UI conventions

Server-rendered pages share cmd/mavweb/static/ui.css (served at /ui.css) and the nav partial (navHTML in cmd/mavweb/main.go, {{template "nav" "<active-page>"}}). No per-page <style> beyond true one-offs. Wrap every table in <div class=scroll> so wide data pans on a phone. Local preview + headless screenshot recipe is in AGENTS.md.

Vikunja

This repo is project Maven (ID 2) in Vikunja. MCP: http://localhost:9100/mcp (or http://192.168.1.104:9100/mcp from workpc). Feature/bug/deploy tasks go there.