Decode the people list from each project's /capabilities and set the /ask person field from a whole-word, case-insensitive name in the question when the caller did not name a person. Match only the routed project's people, so a name from another project does not leak across. Fall back to asker when no name matches. Co-Authored-By: Paperclip <noreply@paperclip.ing>
3.9 KiB
3.9 KiB
Central AI Hub — Code Structure Map
Writing Style: ASD-STE100 Simplified Technical English (
ste-writing). Status: Hub skeleton built (AUD-49). The three inbound routes answer.
Folder Layout
central_ai_llm_master/
AGENTS.md project rules for agents
hub_brief.md agreed design (source of truth)
README.md technical readme
routing.md human-edited routing rules
Dockerfile multi-stage build (static binary, distroless)
docker-compose.yml one container, port 8788
.dockerignore build context filter
docs/
hub-architecture.mmd Mermaid source
hub-architecture-map.html Archify map
diagrams/ rendered images
archify/ Archify JSON input
outline/ AI context documents
ask-contract.md Hub to project interface
hub-api.md frozen inbound API (v1)
vikunja-tasks.json human task list
scripts/
paperclip-roundtrip.sh Phase 1 outbound job proof
src/ Hub service code (module hub)
go.mod module hub (Go 1.25, standard library only)
main.go HTTP layer: POST /ask, POST /approve, GET /health
apierr/ the frozen error envelope
ids/ ULID request and approval ids
config/ environment and secrets loading
hear/ step 1: decode and validate the request
understand/ step 2: never-route check, person match, routing LLM
check/ step 3: identity and source checks
route/ step 4: dispatch to one destination
answer/ step 5: reply shaping (text, speech, notify)
destinations/ one client per destination:
project.go (a data project through /ask)
speakers.go (Jervis house TTS)
paperclip.go (file a job after approval)
logbook/ append-only, size-capped request log
hub/ the pipeline that wires the five steps
tests/fakeproject/ fake /ask project for tests and manual runs
Entry Points
| Entry point | Use | Handler |
|---|---|---|
POST /ask |
Send a voice transcript or text. Returns a reply. | main.go, hub.Service.Ask |
POST /approve |
Admin app confirms a Hub-owned action. | main.go, hub.Service.Approve |
GET /health |
Liveness check. No authentication. | main.go, hub.Service.Health |
The inbound API is frozen. See docs/hub-api.md.
The Five Steps in Code
| Step | Package | Notes |
|---|---|---|
| Hear | hear |
Decode JSON, validate the frozen shape, make a request id. |
| Understand | understand |
The never-route check runs first, with no LLM. Then the OmniRoute LLM picks route, fanout, clarify, or no_match. |
| Check | check |
One identity (Sam) and a source that matches the token. |
| Route | route |
Dispatch. The action call holds no LLM. |
| Answer | answer |
Choose the reply shape from source and want. House TTS is out of band. |
Primary Dependencies
- HTTP server and client (Go 1.25, standard library
net/http). - No third-party module. The binary is static and small.
- OmniRoute, Home Assistant, MQTT, and Paperclip are called over HTTP.
Destinations
Each destination gets one client under src/destinations/. The client calls the
destination API. The client does not hold business logic.
Tests
# Unit and round-trip tests. No network, no secrets.
docker run --rm -v "$PWD/src":/src -w /src golang:1.25-alpine go test ./...
The fake /ask project (src/tests/fakeproject/) proves the Hub-to-project
round trip. It has no real data and changes no state.
Source Control
- Gitea:
sam/central_ai_llm_master - Local:
/home/sam/paseo/projects/central_ai_llm_master/