Skip to content

Architecture Decision Records

Historical ADRs were rendered from bd decision records (/adr skill), named <bd-id>-<slug>.md; those retain their adr-render provenance comment. That pipeline is retired (beads removed). Newer ADRs are hand-authored with a date-based <date>-<slug>.md name — edit the file directly, not a bd record.

Date ADR Status
2026-09-21 2026-09-21 — Tailscale ACL owned by Terraform Accepted
2026-09-09 2026-09-09 — The Firewalla stops being a DNS server: Unbound off and its fallback upstream moved to the resolver pair through the WAN DNS field — the per-network Primary DNS repoint rejected because it is a DHCPv4 option with no write surface on nine of eleven legs, a public secondary rejected because it imports a second authority for the same names, and every appliance reading recorded once with a date rather than gated Accepted
2026-09-08 2026-09-08 — agentgateway is decommissioned — LiteLLM is the only LLM and MCP data plane; llm-gw and mcp-gw retired without alias; rollback is a revert plus a Vault undelete Accepted
2026-09-08 2026-09-08 — Keycloak DCR deny removed; the loopback Trusted-Hosts policy is the sole DCR control — measured: the Traefik deny 403’d LAN clients only, while the Cloudflare tunnel already delivered anonymous DCR straight to Keycloak Accepted
2026-08-28 2026-08-28 — Untrusted clients lose the whole fzymgc.house apex, its real public names included — Blocky’s per-client denylist is the only tier that can withhold it, denylist-then-allowlist rejected because it fails quietly, and the appliance’s whole aggregated population trusted as one client Accepted
2026-08-15 2026-08-15 — LiteLLM, not agentgateway, is the unified LLM and MCP data plane — reversing hl-hv3 on measured per-key USD budget enforcement, with the MCP auth model left undecided because it was never observable Accepted
2026-08-08 2026-08-08 — The drop.fzymgc.net Access edge and its origin trust: four ingest surfaces behind Cloudflare Access, with origin-side JWT verification deliberately declined under D-70 and a measured A3 verdict on header forgeability Accepted
2026-08-02 2026-08-02 — The hl-assets write path: key the object by the bytes actually stored, with cross-architecture encoder determinism measured and the derivation frozen; the audit record written last as the commit marker; video and camera-RAW refused Accepted
2026-08-01 2026-08-01 — Confine the hl-assets R2 credential by resource selector, dedicated Vault path and Velero exclusion — measured against the shared backup bucket, with a coarse egress policy accepted because toFQDNs does not work on this cluster Accepted
2026-07-31 2026-07-31 — hl-assets edge policy in three zone rulesets: /f/-scoped caching, five response headers, allowlist-inline disposition — with Hotlink Protection deliberately off and one measured response class the transform phase does not reach Accepted
2026-07-30 2026-07-30 — Split the hl-assets read path from the write path across two R2 buckets, accepting the R2 list-permission residual Accepted
2026-07-10 2026-07-10 — Send engram’s memory corpus to Google’s paid Gemini embedder (gemini-embedding-2), accepting a limited-retention, not-ZDR posture Accepted
2026-07-07 hl-fyy5 — Router-hosts-generated unbound zone replaces dnsmasq overlay Accepted
2026-07-07 hl-p5ck — Accept Control D endpoint-level attribution, not per-client Accepted
2026-07-05 hl-4z56 — Move oauth2-proxy to Valkey server-side session store Accepted
2026-07-05 hl-swfp — Split Tailscale ACL (gitops-acl-action) from tf/tailscale (Terraform) Superseded
2026-07-05 hl-imbj — Standardize Tailscale node auth on TF-minted OAuth clients (not static keys) Accepted
2026-07-05 hl-r9en — Declare telemetry disposable; greenfield table cutover Accepted
2026-07-05 hl-olui — Native CH BACKUP to RustFS replaces Velero CSI snapshots Accepted
2026-07-05 hl-hiiu — External CronJob watchdog, not an in-stack tile alert Accepted
2026-07-05 hl-4pmu — Replicate ClickHouse without sharding via bootstrap Job Accepted
2026-07-03 hl-zzmt — Document deprecated-read exceptions where no write-only sink exists Accepted
2026-07-03 hl-ujwi — Migrate Vault KV reads per value-sensitivity, not via vault_generic_secret Accepted
2026-07-03 hl-u103 — Split Keycloak OIDC secrets into TF-owned /oidc subpaths Accepted
2026-07-03 hl-sqtn — Allow GitHub SSO to auto-create Keycloak accounts Accepted
2026-07-03 hl-sqk9 — Mint per-resource MCP audiences via optional client scopes Accepted
2026-07-03 hl-ndh5 — Deliver k8s groups via a scoped optional scope, not a blanket mapper Accepted
2026-07-03 hl-iu87 — Hosted Terraform MCP is read-only; no MCP-triggered TFC runs Accepted
2026-07-03 hl-d3y5 — Read public CA chain live from Vault PKI, not repo PEM Accepted
2026-07-03 hl-bc94 — Hosted Kubernetes MCP uses Keycloak-OIDC identity passthrough, not a shared ServiceAccount Accepted
2026-07-03 hl-94n1 — Use the resource URL as the hosted k8s MCP token audience Accepted
2026-07-03 hl-3328 — Retire Tandoor rather than migrate to Keycloak Accepted
2026-07-03 hl-2jrh — Multi-route MCP OAuth discovery uses resource-specific well-known paths Superseded by 2026-09-08-agentgateway-decommissioned
2026-07-03 hl-1fia — Replace Authentik forward-auth with shared oauth2-proxy + per-route group gate Accepted
2026-07-02 hl-ll5p — Restore cluster-internal-only Keycloak DCR (A1+trust) Superseded by 2026-09-08-keycloak-dcr-deny-removed-loopback-trusted-hosts-sole-control
2026-07-02 hl-cnyd — Gate Keycloak admin console via Cloudflare Access, excluding Keycloak as IdP Accepted
2026-07-02 hl-1e4w — Preserve real client IPs on Traefik Service (externalTrafficPolicy: Local) Accepted
2026-07-01 hl-idws — Use single-issuer structured AuthenticationConfiguration for k8s OIDC Accepted
2026-06-30 hl-toju — Decommission kube-prometheus-stack; migrate alerting to HyperDX TILE alerts Accepted
2026-06-30 hl-tir8 — Use groups-claim model for Phase 2 OIDC authz; defer roles to Phase 4 Accepted
2026-06-30 hl-lil1 — Deploy kube-state-metrics standalone; replace node-exporter with OTel hostmetrics Accepted
2026-06-30 hl-hssw — Inject HyperDX dnsConfig via kustomize helmCharts inflation Accepted
2026-06-30 hl-hpbv — Collect Keycloak metrics via OTel-native OTLP push, not Prometheus scrape Accepted
2026-06-30 hl-6bib — Accept open-realm client access; defer per-client group gating to Keycloak authz services Accepted
2026-06-29 hl-amad — Remove Traefik DCR deny; loopback Trusted-Hosts as sole DCR control Superseded by hl-ll5p
2026-06-28 hl-zrbh — NAS Kopia v1 backs up live datasets, deferring snapshot consistency Accepted
2026-06-28 hl-xktj — Enable Keycloak anonymous DCR via Trusted-Hosts policy Superseded by hl-amad
2026-06-28 hl-wxz2 — Build nas-otel derived image in CI/GHCR, not on-box Accepted
2026-06-28 hl-ptnd — B2 Object Lock in GOVERNANCE mode with an offline bypass key for v1 Accepted
2026-06-28 hl-mx5n — Fix Keycloak issuer at id.fzymgc.house from day one Accepted
2026-06-28 hl-jecc — Scoped CiliumNetworkPolicy as sole Phase-1 access control for fovea audit Accepted
2026-06-28 hl-gww0 — Self-managed Kopia to Backblaze B2 with Object Lock for NAS irreplaceable-data backup Accepted
2026-06-28 hl-cbln — Run model: scheduled-CLI Kopia in the nas-support LXC, not a server or Docker app Accepted
2026-06-28 hl-buts — Accept velero PVC backup for fovea audit data, no native Qdrant snapshot Accepted
2026-06-28 hl-9uzu — NAS Kopia snapshot consistency via TrueNAS snapshot-task plus per-leaf .zfs read Superseded by hl-zrbh
2026-06-28 hl-9rhj — Use k8s structured auth config for dual-issuer OIDC transition Superseded by hl-idws
2026-06-28 hl-2vsw — Sign nas-otel GHCR image with keyless cosign Accepted
2026-06-28 hl-12i8 — Migrate cluster IdP from Authentik to Keycloak Accepted
2026-06-27 hl-wo1m — Ship NAS telemetry via a dedicated nas-otel-collector TrueNAS custom app Accepted
2026-06-27 hl-hghu — Build NAS containers on TrueNAS libvirt-LXC, not Incus Accepted
2026-06-27 hl-akt3 — Manage the TrueNAS NAS exclusively via the middleware API Accepted
2026-06-27 hl-3ek7 — Grant NAS sandbox dataset access via DEFAULT idmap plus per-dataset ACLs Accepted
2026-06-26 hl-osb5 — Expression-policy audit alerts excluding the GitOps automation actor Accepted
2026-06-26 hl-a1uh — Invitation email via ak_send_email, not NotificationTransport Accepted
2026-06-25 hl-93me — Tier fovea scout aspects across two models via the closed scout/deepdive role set Accepted
2026-06-25 hl-5xgq — Adopt HyperDX/ClickStack as cluster observability platform; retire Grafana-Labs Accepted
2026-06-25 hl-0ah0 — Route fovea LLM roles to ZDR open models via path-prefix agentgateway lanes Accepted
2026-06-23 hl-poj0 — Transparent credential pass-through; no Headroom auth layer Accepted
2026-06-23 hl-k1am — Disable the Headroom semantic response cache on both instances Accepted
2026-06-23 hl-g0fn — Split Headroom into two instances by run mode Accepted
2026-06-23 hl-8ycr — Use official GHCR Headroom images; do not build cluster-owned images Accepted
2026-06-22 hl-1pwl — Scrape agentgateway metrics via otel-scraper; push traces directly Superseded by 2026-09-08-agentgateway-decommissioned
2026-06-20 hl-v4vo — Add dedicated transparent OpenRouter passthrough host on agentgateway Superseded by 2026-09-08-agentgateway-decommissioned
2026-06-20 hl-rzrg — Split read and write Firewalla MCP routes at the gateway for topology-enforced blast-radius Accepted
2026-06-20 hl-nmix — Use VK + static upstream bearer auth for Firewalla MCP (not per-user OIDC) Accepted
2026-06-20 hl-l875 — Use Detect not Passthrough for the generic OpenRouter lane (preserve OTel telemetry) Accepted
2026-06-20 hl-d5lu — Select the ZDR lane via two HTTPRoutes + Gateway API header-count tiebreaker Accepted
2026-06-20 hl-93zf — Build Firewalla MCP server rather than adopt off-the-shelf amittell server Accepted
2026-06-19 hl-qra1 — Use per-name dnsmasq local=+address= records for the authoritative internal fzymgc.house zone Superseded by hl-fyy5
2026-06-18 hl-2t4o — Use dnsmasq local= for an authoritative internal fzymgc.house zone Superseded by hl-qra1
2026-06-15 hl-cujh — Use hybrid autodiscoverFilter + App-install fence for multi-account Renovate governance Accepted
2026-06-15 hl-6fu4 — Use inline config.js baseline over a shared preset repo for Renovate policy Accepted
2026-06-14 hl-v808 — Use SQLite on a Longhorn PVC for Renovate CE state, not CNPG Postgres Accepted
2026-06-14 hl-qovi — Use Cilium WireGuard pod-to-pod encryption cluster-wide Accepted
2026-06-14 hl-5sr0 — Expose Renovate CE via dual trigger: scheduler plus webhook Accepted
2026-06-14 hl-543e — Use a single public GitHub App for multi-org Renovate CE Accepted
2026-06-13 hl-fvje — Traefik metrics: pure-OTLP push; disable the Prometheus endpoint Accepted
2026-06-13 hl-aek4 — Inject Traefik OTLP auth headers via TRAEFIK_* env vars, not Helm values Accepted
2026-06-13 hl-5z4x — Use the native experimental OTLP access-log exporter on cluster ingress Accepted
2026-06-13 hl-57x5 — Upgrade engram embedding model to Qwen3-Embedding-8B (4096-dim) via OpenRouter ZDR Superseded by 2026-07-10-engram-gemini-embedder-retention-posture
2026-06-13 hl-0gol — Exclude the orphaned (vestigial-Flux) wildcard cert from the new ArgoCD source Accepted
2026-06-12 hl-cgb4 — Choose Miniflux over FreshRSS as the cluster feedreader Accepted
2026-06-12 hl-27xf — Authenticate Miniflux with native Authentik OIDC, not forward-auth Accepted
2026-06-08 hl-fk0 — Gating split: env-gate recency scan, ship doc-aware analysis unconditionally (refines hl-78b) Accepted
2026-06-08 hl-bit.30 — Use symlinked content collection + stock docsLoader for Starlight docs Accepted
2026-06-08 hl-26y — null (never now()) as the absent-recency sentinel for lastModifiedAt Accepted
2026-06-08 hl-0d4 — Per-file recency via bare blob-less git clone at index time (octopus fork) Accepted
2026-06-07 hl-yrh — Cluster cross-check is advisory only; never a CI gate Accepted
2026-06-07 hl-nhi — Per-server path-routed MCP gateway with per-upstream client-auth choice (OAuth or VK) Accepted
2026-06-07 hl-m3c — Deploy agentgateway via k8s-native Gateway-API/CRD control plane (supersedes standalone) Superseded by 2026-09-08-agentgateway-decommissioned
2026-06-07 hl-bc5 — Phase 1 audit harness in Python/uv reusing pinned clients; Node deferred to Phase 3 Accepted
2026-06-07 hl-6iz — Use isolated website/ subproject with externalDocsLoader for Starlight docs Superseded by hl-bit.30
2026-06-07 hl-25z — Serve llms.txt artifacts from the build; enforce coverage via custom CI gate Accepted
2026-06-07 hl-0eb — ZDR via structured field-override (ai.overrides); CEL only for drop_params Accepted
2026-06-06 hl-pvn — Pin self-owned images by short-SHA, not mutable tags Accepted
2026-06-06 hl-msh — Dedicate Qdrant + CNPG database to octopus, isolated from engram Accepted
2026-06-06 hl-jd4 — Deploy agentgateway in standalone mode, not the K8s Gateway-API control plane Superseded by hl-m3c
2026-06-06 hl-hv3 — Use agentgateway as the unified LLM + MCP data plane (replace LiteLLM) Superseded by 2026-08-15-litellm-is-the-unified-llm-and-mcp-data-plane
2026-06-06 hl-env — ZDR and drop_params via CEL config transformations (no custom binary/plugin) Superseded by hl-0eb
2026-06-06 hl-8g4 — Split octopus across two hostnames: public webhook + internal UI Accepted
2026-06-06 hl-78b — Fork octopus as thin staging ground; upstream the EMBEDDING_DIM patch Accepted
2026-06-06 hl-6nm — Split model routing: OpenRouter reviews + in-cluster bge-m3 embeddings (1024-dim) Accepted
2026-06-06 hl-23m — agentgateway is the MCP auth enforcement point + DCR short-circuit (engram stays the Resource Server) Accepted
2026-06-02 hl-cy3 — Use dual backup paths for Qdrant memory store Accepted