- main.go's wiring was untested (the test built its own copy of the router, so dropping auth in main or re-registering POST /query as public stayed green). Routing is now one function, buildMux, which main calls and the tests call: it constructs the bearer middleware itself, registers public handlers only for patterns on a fixed allowlist (a public REST pattern would beat the authenticated catch-all by specificity), refuses an empty token, and returns an http.Handler so nothing can add a route to the result. - hyperguild CLI: PassRate sent no token and would 401. Every request now goes through brainClient.do, which adds it; the test covers Query, Write and PassRate and is named for that. - ResolveIngestPath returns one refusal for every bad path; the raw EvalSymlinks error let a caller probe which server files exist and leaked the brain directory. - PROJECT.md (and derived adapters) and the pass-rate runbook state that the REST API needs BRAIN_MCP_TOKEN and is tailnet/in-cluster. Refs #149 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.7 KiB
Project context
Identity
- Name: supervisor
- Owner: Mathias
- Client: personal
- Repo:
- Status: active
Stack
- Primary language: Go
- UI layer: HTMX + Templ (when applicable)
- Fallback languages: Python, TypeScript (justify in PR if used)
- Build: Task (taskfile.dev), not Make
- Containers: Docker (compose for dev, k3s for deploy)
- Target infra: koala (GPU workloads), iguana (services), flamingo (edge)
Conventions
Code style
- Go: follow
golines,gofumpt,golangci-lintwith project config - Tests: table-driven, in
_test.gonext to source,testifyfor assertions - Errors: wrap with
fmt.Errorf("operation: %w", err), no naked returns - Naming: stdlib conventions, no stuttering (
http.Clientnothttp.HTTPClient)
Architecture preferences
- Prefer standard library over frameworks (net/http over gin/echo)
- Dependency injection via constructor functions, not containers
- Configuration via environment variables, parsed at startup into a typed struct
- Structured logging via
slog
Git
- Conventional commits:
feat:,fix:,chore:,docs:,refactor: - Branch naming:
feat/short-description,fix/short-description - PRs: one concern per PR, description explains why not what
Security
- No secrets in code, ever — use env vars or SOPS-encrypted files
- Client data never leaves local network unless explicitly cleared
- Dependencies: audit with
govulncheckbefore adding
MCP endpoints
Two MCP servers are live, both reachable over Tailscale and via HTTPS domain:
brainathttps://brain-mcp.d-ma.be/mcp(NodePortkoala:30330) —brain_query,brain_write,brain_ingest,brain_ingest_raw,brain_answer,brain_classify,session_log. Hosted by the ingestion service. Auth: Dex JWT (claude.ai OAuth) or staticBRAIN_MCP_TOKEN.routingathttp://koala:30310/mcp— Mode 2 routing pod. Advertisesreview,debug,retrospective,trainer; per-call routes to local model or Claude based on brain/pass-rate. Bearer auth viaROUTING_MCP_TOKEN(opt-in). Onlymode client-localregisters this endpoint.
The supervisor MCP (koala:30320) was retired in Plan 7 (2026-05-12). Its
skill workers (tdd, spec) are now SKILL.md files; routed skills moved to
the routing pod; brain tools moved to the brain MCP.
The brain HTTP REST API (/query, /write, /ingest, /ingest-raw,
/ingest-path, /backfill-refs, /pass-rate) remains available on port 3300
for shell scripts and non-MCP clients, with the same bearer token as /mcp
(BRAIN_MCP_TOKEN; hyperguild#149). It is not served on the public host
(infra#517): use the tailnet (koala:8443) or in-cluster
ingestion.supervisor.svc:3300. /ingest-path and brain_ingest path
accept only paths inside brain/raw/.
brain_answer(query) performs BM25 retrieval + LLM synthesis (berget.ai
gemma4:31b → iguana fallback). brain_classify(text) infers doc type, title,
and tags. Both require BRAIN_LLM_PRIMARY_URL to be set in the ingestion pod.
Agent instructions
When acting as a coding agent on this project:
- Read this file and all
SKILL.mdfiles in.skills/before starting work - Run
task checkbefore committing (lint + test + vet) - If unsure about a convention, check
DECISIONS.mdor ask - Never modify files outside the project root without explicit permission
- When adding a dependency, explain why in the commit message
- For client projects: never send code or context to cloud APIs — use local models via LiteLLM