Files
central_ai_llm_master/README.md
Sam Rolfe bf80efa25d 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>
2026-10-10 17:38:48 +11:00

116 lines
3.7 KiB
Markdown

# Central AI Hub
One small service that every way in reaches every ability through. Built once,
shared by the phone app, the house voice, chat, and the admin app.
## Demonstrated Skills & Tech Stack
- **Core Technologies**: Go 1.25 service · HTTP JSON API · MQTT · LLM
intent routing · OmniRoute gateway · Docker
- **Entry routes**: `POST /ask` · `POST /approve` · `GET /health`
(frozen in `docs/hub-api.md`)
- **Key Tools**: Jervis (voice) · Home Assistant · Paperclip · Artemis ·
internet use control · Apprise / NTFY · OmniRoute
- **Engineering Capabilities**: service design · intent routing · authorization
and approval flows · event-driven integration · deterministic safety for
high-consequence actions
## Quick Start
### Run the Hub
```bash
# Build and run the container (Docker host 192.168.20.13).
docker compose up -d --build
# Liveness (no token).
curl -s http://192.168.20.13:8788/health
# Ask a question (source esp32 speaks the reply on the house speakers).
curl -s -X POST http://192.168.20.13:8788/ask \
-H "Authorization: Bearer $HUB_TOKEN_ESP32" \
-H "Content-Type: application/json" \
-d '{"text":"what does Harry have on today?","asker":"sam","source":"esp32"}'
```
The Hub reads `HUB_TOKEN_*`, `OMNIROUTE_API_KEY`, and the project tokens from
`~/.config/environment.d/10-secrets.conf` (mounted read-only, never committed).
### Test without a network
```bash
scripts/hub-test.sh
```
The fake `/ask` project in `src/tests/fakeproject/` proves the round trip.
### Phase 1 — prove the Paperclip round trip
```bash
# 1. Create an agent API key in Paperclip.
# 2. Export it for the test only.
export PAPERCLIP_API_KEY=<redacted>
# 3. File one job.
scripts/paperclip-roundtrip.sh --title "round-trip test"
```
Full steps: `docs/outline/04-agent-runbook.md`.
## System Architecture
```mermaid
flowchart LR
subgraph IN["Ways in"]
PHONE["Phone app<br/>wake word + voice"]
ADMIN["Admin app<br/>restricted actions"]
ESP["ESP32 voice<br/>Hey Jervis"]
DSH["dsh chat"]
CONSOLE["Console portal"]
end
HUB{{"HUB<br/>hear - understand - check - route - answer"}}
subgraph OUT["Peers and services<br/>(the Hub is not a destination)"]
HA["Home Assistant"]
SPK["Speakers<br/>Jervis TTS"]
NET["Internet control<br/>parental limits"]
ART["Artemis<br/>phone screen"]
PC["Paperclip<br/>work bench"]
WEB["Web search"]
APP["Apprise / NTFY"]
end
PHONE --> HUB
ESP --> HUB
DSH --> HUB
CONSOLE --> HUB
ADMIN --> HUB
HUB --> HA
HUB --> SPK
HUB --> ART
HUB --> WEB
HUB --> APP
HUB -- "ask only (query)" --> NET
HUB -- "slow job (approved)" --> PC
ADMIN -- "control + tap to approve" --> NET
PC -. result .-> HUB
```
*Interactive architecture map:* [maps.lab.audasmedia.com.au/central_ai_llm_master](https://maps.lab.audasmedia.com.au/central_ai_llm_master/docs/)
## Usage & Configuration
- **Model calls** go through OmniRoute at `http://192.168.20.13:20129/v1`.
- **Secrets** come from `~/.config/environment.d/10-secrets.conf`.
- **Paperclip** is at `http://192.168.20.13:3100`. An API key is required.
- **Home Assistant** is at `http://192.168.20.30:8123`.
- **Jervis** (voice) is at `http://192.168.20.13:8501`.
- **Hub** is at `http://192.168.20.13:8788` (local Docker container).
The design brief is `hub_brief.md`. Project instructions are `AGENTS.md`.
The interface between the Hub and every data project is `docs/ask-contract.md`.
The frozen inbound API (ways in to the Hub) is `docs/hub-api.md`.
Every other project is a **peer**, not a sub-project. A high-consequence control
(for example, cutting the kids' internet) does **not** route through the Hub.