AUD-49: build the Hub skeleton (hear-route-answer)

- Three inbound routes from docs/hub-api.md: POST /ask, POST /approve, GET /health.
- Five-step pipeline in src/hub, with packages hear, understand, check, route, answer.
- Routing through OmniRoute with the capability list and routing.md. The
  never-route control check runs before any LLM call.
- One real destination: Jervis house TTS, started out of band.
- Fake /ask project (src/tests/fakeproject) for the round-trip test.
- Append-only, size-capped request log. Bearer auth, source match, rate limit.
- Tests: all packages pass, including the fake /ask round trip. Race clean.
- Dockerfile and compose updated to mount routing.md and secrets, log on tmpfs.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-10-10 17:38:24 +11:00
parent 81f9722eee
commit bf80efa25d
33 changed files with 4025 additions and 110 deletions

View File

@@ -10,11 +10,26 @@ services:
- "8788:8788"
environment:
HUB_PORT: "8788"
# Secrets are never hard-coded. The Hub keys (HUB_TOKEN_*, OMNIROUTE_API_KEY)
# come from ~/.config/environment.d/10-secrets.conf. Add only the keys the
# running routes need, when they land (AUD-49+).
HUB_ROUTING_FILE: "/app/routing.md"
HUB_LOG_PATH: "/tmp/hub.log"
# Data projects that speak /ask (comma-separated name=url). Empty until a
# project is ready. The Hub reads each project's /capabilities.
HUB_PROJECTS: "${HUB_PROJECTS:-}"
# House TTS. The Hub starts speech and does not wait.
JERVIS_URL: "${JERVIS_URL:-http://192.168.20.13:8501}"
# Secrets are never hard-coded. The Hub keys (HUB_TOKEN_*, OMNIROUTE_API_KEY,
# PAPERCLIP_API_KEY, HUB_PROJECT_<NAME>_TOKEN) come from environment.d. The
# file is mounted read-only; the Hub reads it when the environment is empty.
HUB_SECRETS_FILE: "/run/secrets/hub.env"
volumes:
# routing.md is human-edited and stays outside the image.
- "./routing.md:/app/routing.md:ro"
- "${HOME}/.config/environment.d/10-secrets.conf:/run/secrets/hub.env:ro"
# The distroless image has no writable path except this tmpfs. The log lives here.
tmpfs:
- /tmp
healthcheck:
test: ["CMD", "/hub", "-healthcheck"]
test: ["CMD", "/app/hub", "-healthcheck"]
interval: 30s
timeout: 3s
retries: 3