Files
tapir/docs/homelab-integration.md
T
mathiasandClaude Opus 4.8 6da9d61e63 feat(adapters): add Summarizer backed by local-first llm routing
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>
2026-06-02 17:04:29 +02:00

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 via kubectl get svc -n ai-stack):
    • In-cluster: http://litellm.ai-stack.svc.cluster.local:4000/v1/ (ClusterIP 10.43.159.89:4000).
    • Off-cluster (host / NodePort): http://koala:30401/v1/ — service litellm-nodeport (4000:30401).
    • NOTE: the earlier 31234 was wrong31234 is the llama-swap NodePort (8080:31234), not LiteLLM. Use 30401 for off-cluster LiteLLM. confirm resolved.
  • Auth key: treat as a secret via the SecretStore port; do not hardcode in committed code. NOTE: the documented sk-local-123 returned 401 on 30401/v1/models (2026-06-02) — it is stale or the gateway now enforces the LITELLM_MASTER_KEY (1Password op://HomeLab/LITELLM_MASTER_KEY). Resolve the live key from the vault when wiring; sk-local-123 is no longer valid. confirm partially resolved.
  • Model alias format: host/name, e.g. koala/qwen3-coder-30b, koala/phi4-mini, iguana/devstral, iguana/deepseek-r1-14b. Not the ollama/ 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, env TAPIR_SUMMARIZER_MODEL (format host/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 if max_tokens is 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 generous max_tokens to the copied llm.Client request (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_ingest tool (ADR-005). Do not use the filesystem brain package from hyperguild/ingestion.
  • brain-mcp base URL: confirm — not pinned in this snapshot. The homelab convention is *-mcp.d-ma.be ingress hostnames (e.g. git-mcp.d-ma.be, brain-mcp.d-ma.be is the likely form), but verify before wiring.
  • brain distinguishes knowledge/ (session-derived) from wiki/ (stable, manually promoted). Tapir summaries are session-derived signal → knowledge/-style ingestion. brain_ingest runs the LLM extraction pipeline; there is a raw-ingest path (brain_ingest_raw) and a reliable brain_write fallback 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-chassis shared 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-mcp references GITEA_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 default GOPROXY. If a homelab GOPROXY (e.g. Athens) exists, point GOPROXY at it and this pair is not needed directly — confirm whether one is run.
  • go.dev, dl.google.com — Go toolchain download (the CI setup-go step / 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/oauth2 and 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.dev during scaffolding, which is why the scaffold was reviewed but not compile-verified in-chat; verification belongs on koala via task check regardless.

Deployment / GitOps (when Tapir reaches deploy)

  • The homelab is Flux GitOps: manifests in mathias/infra under k3s/, Flux watches main.
  • Tapir's k3s manifests will live in infra/k3s/apps/tapir/ (by convention) — not in this repo. This repo is the application; infra is 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.