Implement ports.Summarizer in internal/adapters/summarizer. It routes through a
local Primary endpoint first and an optional BYO Fallback, owning the routing
itself (not delegating to llm.Router) so it can record AIProvider, AIModel, and
FallbackUsed on domain.Summary. Prompt asks for JSON {summary, highlights,
takeaways}; the parser tolerates thinking-model fences/reasoning and rejects an
empty summary.
The summarizer is the single egress point for content toward an AI model, so it
enforces the local-first guarantee from ai_routing.feature: with no BYO
configured (nil fallback) there is no external endpoint, so content reaches the
local stack and nowhere else. Tests assert all four scenarios via a fake client.
Model alias is config (TAPIR_SUMMARIZER_MODEL, host/name) — not hardcoded;
docs/homelab-integration.md notes it stays `confirm` and that thinking models
need an explicit max_tokens or they return empty content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.4 KiB
Tapir — Homelab Integration Facts
The concrete endpoints, conventions, and identifiers Tapir depends on, so an independent session doesn't have to rediscover them. Verify anything marked "confirm" before relying on it — endpoints and aliases drift, and this file is a snapshot (2026-06-02), not a live source.
Local AI (the Primary in llm.Router)
- LiteLLM gateway: OpenAI-compatible, lives in k3s namespace
ai-stack(verified 2026-06-02 from koala viakubectl get svc -n ai-stack):- In-cluster:
http://litellm.ai-stack.svc.cluster.local:4000/v1/(ClusterIP10.43.159.89:4000). - Off-cluster (host / NodePort):
http://koala:30401/v1/— servicelitellm-nodeport(4000:30401). - NOTE: the earlier
31234was wrong —31234is thellama-swapNodePort (8080:31234), not LiteLLM. Use30401for off-cluster LiteLLM.confirmresolved.
- In-cluster:
- Auth key: treat as a secret via the SecretStore port; do not hardcode in committed code.
NOTE: the documented
sk-local-123returned401on30401/v1/models(2026-06-02) — it is stale or the gateway now enforces theLITELLM_MASTER_KEY(1Passwordop://HomeLab/LITELLM_MASTER_KEY). Resolve the live key from the vault when wiring;sk-local-123is no longer valid.confirmpartially resolved. - Model alias format:
host/name, e.g.koala/qwen3-coder-30b,koala/phi4-mini,iguana/devstral,iguana/deepseek-r1-14b. Not theollama/prefix form. - Which alias for summarization: NOT yet decided.
confirm. Tapir summarizes transcript text, so a capable general/instruct model on koala or iguana is the candidate — pick during the build and record the choice (an ADR if it's load-bearing). Do not assume a coder alias is right for prose summarization. The summarizer adapter does not hardcode an alias: it is config, envTAPIR_SUMMARIZER_MODEL(formathost/name, e.g.iguana/deepseek-r1-14b). - Thinking models need an explicit
max_tokens. qwen3 / deepseek-r1 spend the budget on reasoning and return empty content ifmax_tokensis too low (or unset). The summarizer's parser treats an empty summary as an error for exactly this reason. When the alias resolves to a thinking model, add a generousmax_tokensto the copiedllm.Clientrequest (it currently sends none — change Tapir's copy per ADR-004), or pick a non-thinking instruct model.
This maps directly onto the copied llm package: Client is the OpenAI-compatible caller,
Router.Primary points at this gateway with a chosen alias, Router.Fallback is the user's BYO.
BYO AI (the Fallback in llm.Router)
- Per-user, opt-in: Anthropic / OpenAI / Gemini. All reachable as OpenAI-compatible or via a thin
adapter. The user's key is stored only as a secret reference (data-model
AI_CREDENTIAL). - Used only when Primary fails and the user has configured a provider (see
docs/use-cases/ai_routing.feature). With no BYO, work is queued for retry — content is never sent externally.
Brain sink (optional delivery target)
- Reached via brain-mcp over HTTP, calling the
brain_ingesttool (ADR-005). Do not use the filesystembrainpackage fromhyperguild/ingestion. - brain-mcp base URL: confirm — not pinned in this snapshot. The homelab convention is
*-mcp.d-ma.beingress hostnames (e.g.git-mcp.d-ma.be,brain-mcp.d-ma.beis the likely form), but verify before wiring. - brain distinguishes
knowledge/(session-derived) fromwiki/(stable, manually promoted). Tapir summaries are session-derived signal →knowledge/-style ingestion.brain_ingestruns the LLM extraction pipeline; there is a raw-ingest path (brain_ingest_raw) and a reliablebrain_writefallback when the local extraction model is unavailable — relevant if ingestion reliability becomes an issue.
Auth / identity (Stage 1+, dormant at Stage 0)
- Dex (
auth.d-ma.be) is the homelab OIDC provider. When Tapir needs real user identity (Stage 1, Future B), it authenticates via Dex — not a new auth system (ADR-002). - If Tapir ever exposes an MCP surface, use the
mcp-chassisshared Go library (gitea.d-ma.be/mathias/mcp-chassis) for the Dex-JWT validator + Bearer middleware + RFC 9728 metadata, rather than hand-rolling it.
Secrets (OAuth tokens + BYO keys)
- Convention: ESO + 1Password (the homelab's External Secrets Operator against a 1Password
vault). Tables store only an opaque
*_secret_ref; the secret material lives in the vault and is surfaced to the workload via ESO. - Exact ref format / vault item naming for Tapir: confirm / decide during build. Follow
the pattern existing services use (e.g. how
gitea-mcpreferencesGITEA_MCP_DEFAULT_TOKEN) rather than inventing a new scheme.
Hosts (for reference)
- koala — Arch, RTX 5070, k3s single-node, Gitea, GPU inference. Where Tapir most likely runs and where the local models live.
- iguana — Mac Studio M2 Ultra, ollama + mlx-whisper, also serves models via the gateway.
- piguard — Pi, NPM perimeter (public HTTPS edge). Note: the May-2026 architecture review has LiteLLM relocating from piguard into k3s/ai-stack on koala — confirm current location if latency or endpoint matters.
Network egress the build and runtime assume
If the koala act_runner (or a dev environment) has locked-down egress, these must be reachable or the build/run fails. Split into build-time and runtime because they're different lists and fail at different stages.
Build-time (CI check/build, and local go/task work)
proxy.golang.org,sum.golang.org— Go module proxy + checksum DB. The defaultGOPROXY. If a homelab GOPROXY (e.g. Athens) exists, pointGOPROXYat it and this pair is not needed directly — confirm whether one is run.go.dev,dl.google.com— Go toolchain download (the CIsetup-gostep /go-version-file). Not needed if the runner already has the matching Go installed.raw.githubusercontent.com— the CI installs golangci-lint via its install script from here (.gitea/workflows/ci.yml).github.com,codeload.github.com— any module not served by the proxy (incl. golangci-lint and, later,golang.org/x/oauth2and its deps) is fetched from GitHub.objects.githubusercontent.com— GitHub release asset downloads (some installers redirect here).
A configured GOPROXY collapses most of the module-fetch entries into one host. Recording the
homelab's actual GOPROXY/GONOSUMCHECK policy here once known would remove the confirm.
Runtime (the running service)
koala:4000(or the NodePort / post-relocation address) — LiteLLM gateway, the Primary.- brain-mcp host (
*-mcp.d-ma.be, confirm) — only when the brain sink is enabled. www.googleapis.com/ YouTube Data API +oauth2.googleapis.com(token exchange/refresh) — the YouTube provider adapter.api.vimeo.com— the Vimeo provider adapter.- BYO-AI endpoints, per configured provider and only when a user opts in:
api.anthropic.com,api.openai.com,generativelanguage.googleapis.com. - 1Password / ESO reach for secret resolution follows the homelab's existing ESO egress, not Tapir-specific — no new rule expected.
Note: a user with no BYO configured means the service never needs the third-party AI hosts
(the local-first guarantee, docs/use-cases/ai_routing.feature). Don't allow them by default;
allow per-provider when a user connects one.
The claude.ai chat sandbox (where planning sessions run code) has its own separate egress allowlist — unrelated to koala. It blocked
go.devduring scaffolding, which is why the scaffold was reviewed but not compile-verified in-chat; verification belongs on koala viatask checkregardless.
Deployment / GitOps (when Tapir reaches deploy)
- The homelab is Flux GitOps: manifests in
mathias/infraunderk3s/, Flux watchesmain. - Tapir's k3s manifests will live in
infra/k3s/apps/tapir/(by convention) — not in this repo. This repo is the application;infrais the deployment source of truth. - Multi-tenancy primitives (NetworkPolicy per namespace, Kyverno, postgres role-per-tenant,
tenant=label) exist in the architecture review (SC7/P6) and apply at Stage 1 — not Stage 0.
Snapshot date 2026-06-02. Items marked confirm were not verified to a pinned source at snapshot time — check brain or the live cluster before depending on them.