Changelog archive — v1.18
Moved verbatim from CHANGELOG.md; never edited.
[v1.18.3] - 2026-07-21
Features
- The ringtail agent workspaces now run a heph spoke synced to the indri hub, so agent sessions can use
hephfor task/context — heph is a deliberate in-boundary agentic-workflow substrate (distinct from the 1Password blumeops vault, which stays isolated). heph/hephd are cargo-installed at a pinned tag via a mise-resolved Rust toolchain (nixpkgs rustc lags heph’s floor) by aagent-heph-installsystemd oneshot; aagent-heph-spokeservice runshephdauthenticating as a dedicated, independently-revocableheph-agentsAuthentik identity, with its OIDC token stored in theagentsvault via hephd’s command token store (no plaintext at rest). The indri hub authorizes that identity as a co-owner viahephd --authorized-sub(sourced from the vault). Requires heph ≥ v1.7.0. - Stood up an “under construction” landing page at the apex
eblu.me(andwww.eblu.me) — a hi-I’m-Erich splash with the obligatory old-school hazard-barricade GIF and links to docs.eblu.me / forge.eblu.me. Unlike the other public sites, it’s served straight from nginx on the Fly proxy (files baked into the image) rather than tunneled back to Caddy on indri, so the front door stays up even when indri or the tunnel is down. The apex usesA/AAAArecords to Fly’s ingress IPs (aCNAMEis illegal at the zone apex);wwwis a normalCNAMElike the rest. - Stood up a private Factorio dedicated server on ringtail (
services.factorio, UDP 34197), reachable atfactorio.ops.eblu.me. It is BlumeOps’ first externally-shared service: guests are shared onto ringtail (autogroup:shared) rather than invited as members, and the Tailscale ACL hands them exactly the one game port — they inherit none of the member-facing services.
Bug Fixes
- Fixed flake input discovery in the dagger
flake-updatepipeline: nix cannotreadFile /dev/stdin(it canonicalizes to a/proc/.../pipe:[...]path), so discovery had been silently empty since the pipeline was written, degenerating every run into a barenix flake updateof all inputs — thenixpkgs-servicespin survived only because its URL is rev-pinned. Metadata now lands in a real file, stderr is no longer suppressed, and run 658’s “refusing bare flake update” guard failure becomes a green no-op again. - Fixed the Ringtail Flake Update workflow hanging in its summary step (
git logspawned a pager on the runner; now--no-pager), and two latent bugs in the daggerflake-updatepipeline:skip_inputswas never applied (single-quoted$SKIP_INPUTSnever expanded, so a real update would have bumped the pinnednixpkgs-servicesinput), and an empty discovered-input list now fails loudly instead of falling back to a barenix flake updateof everything. - Changed
factorio.ops.eblu.mefrom a pinned A record to a CNAME →ringtail.tail8d86e.ts.net. Tailscale remaps a shared node’s100.xaddress inside each guest’s tailnet, so the hardcoded owner-tailnet IP was unroutable for guests and the name timed out for them; the CNAME lets each client’s own MagicDNS resolve ringtail to the address correct for its view. - Firefox on ringtail now runs under XWayland (
MOZ_ENABLE_WAYLAND=0), working around a hard deadlock that froze the whole browser. NVIDIA’s Wayland EGL explicit-sync path can leave a DRM timeline fence unsignaled insideeglSwapBuffers, so the Renderer thread blocks forever indrmSyncobjTimelineWait; the Compositor thread then blocks inWaitUntilPresentationFlushed, and the main thread blocks behind a synchronousSendFlushRenderingIPC issued while painting a popup. Painting any doorhanger, menu, or dropdown could trigger it, leaving Firefox wedged at 0% CPU until killed — the trigger that surfaced it was clicking “enable notifications”, which is a repaint, not a network call. No Firefox pref or wlroots/sway toggle governs this path, and nixpkgs production/latest/beta were all pinned to the affected 580.142 driver, so XWayland is the only lever until a newer driver ships. - Pinned ringtail’s Factorio headless server to 2.0.77 via a temporary
versionsJsonoverlay so it matches the auto-updated Steam client (nixos-25.11 still ships 2.0.76). Remove the overlay once nixpkgs catches up. - Restored the nightly indri borgmatic run, which had aborted since 2026-07-10.
The multi-user hardening that locked
/etc/rancher/k3s/k3s.yamlto0600 rooton ringtail also locked outeblume, the user borgmatic’sbefore: configurationk8s-dump hooks SSH in as to snapshot mealie/shower/navidrome — a non-zero hook exit aborts the whole run, so nothing landed. The hooks now reach the cluster viasudo k3s kubectl, keeping the kubeconfig locked away from the restricted web-agent user. container-build-and-releaseno longer fails spuriously: the Forgejo dispatch endpoint routinely holds the connection open past the read timeout even though the dispatch lands, which surfaced as an unhandledReadTimeout. The POST timeout is now non-fatal — the task falls through to run verification (polling for the dispatched run) as the real source of truth, and only errors if no matching run appears.eblume-heph-spokemoved from a system unit to a systemd user service (with linger): as a system service hephd bound the~/.local/sharefallback socket while interactive shells looked in/run/user/1000, so thehephCLI could never reach the daemon. Shared install machinery split intomkInstallUnits(heph-common.nix).mise run services-check: thek3snode-readiness probe now reads the cluster viasudo k3s kubectlinstead ofKUBECONFIG=/etc/rancher/k3s/k3s.yaml. That kubeconfig went 0600 root-only when ringtail became a multi-user host, so the probe had been failing on permission (the cluster was healthy —k3s-apiserver (remote)and every pod/HTTP check passed). Samesudo-not-locked-kubeconfig pattern as the borgmatic dump hooks. Also tightenedgrep -q Ready→grep -qw Readyso aNotReadynode can’t false-pass on the substring.
Infrastructure
-
Agent workspaces: add a native build toolchain (
gcc,binutils,pkg-config,gnumake+CC=gcc) to the session PATH socargo buildno longer dies withlinker `cc` not found, letting agents compile and verify Rust they author. Also expose thegamedevBevy project’s Linux native deps —alsa/udevonPKG_CONFIG_PATH, and thedlopen’d windowing/graphics libs (vulkan-loader, libxkbcommon, wayland, libGL, xorg) onLD_LIBRARY_PATH. Building/verifying works headlessly; running a windowed Bevy app still needs a GPU/display, so playtesting stays a human job. -
Ringtail now hosts agent workspaces — per-repo Claude Code Remote Control servers (hephaestus, blumeops, research, playground) run under an unprivileged
agentuser, steerable on demand from the Claude mobile app. Agents authenticate to 1Password only as a vault-scoped service account and push to Forgejo as a dedicated bot (nevermain). Seeagent-workspacesand thebootstrap-agent-workspacesrunbook. -
Agent workspaces can now author blumeops: a read-write, agent-owned clone lands at
~agent/code/personal/blumeops(pool-only, no dedicated server) so sessions can edit it and open PRs as the bot. Deploys stay gated — and to make that real, the k3s admin kubeconfig is locked from world-readable0644to0600(it previously handed the unprivilegedagentuser cluster-admin and an ArgoCD-admin deploy path). -
Agent workspaces collapsed from per-repo Remote Control servers (
ringtail-{hephaestus,research,playground,parsimony}) to a single home-base session,ringtail-agent, rooted in the newagentsrepo whoseAGENTS.mdcarries the base instructions (repo map, toolbox, execution environments). All other repos are sibling checkouts the sessioncds into; theplaygroundworkspace is dropped (a home-base worktree is already a scratch space).Also:
hephfor Erich on ringtail — a second hephd spoke (eblume-heph-spoke, token-file store, logging in as Erich himself) alongside the agent’s, with the shared version pin and install machinery extracted tonixos/ringtail/heph-common.nix. -
New
parsimonyagent workspace on ringtail fortimberborn-parsimony, a Timberborn “Least Actions Challenge” mod. The remote agent builds the mod against the local game install’s DLLs; playtesting (launching the game) remains a human-session step via the repo’smise run playtest. -
Agent workspaces: put the research report toolchain (mise, uv, pandoc, typst, weasyprint) on the session PATH, and expose WeasyPrint’s native libraries via
LD_LIBRARY_PATHsomise run compile-reportrenders a PDF on ringtail. Repo mise configs are pre-trusted to avoid interactive prompts. -
The
agentsbot now authors blumeops via a fork (agents/blumeops) with only read on the canonical repo, instead of pushing branches toeblume/blumeopswith write. This closes a privilege-escalation path:workflow_dispatchis write-gated, so a write-access bot could have dispatched a branch workflow that reads blumeops’ deploy-credentialed Actions secrets (ARGOCD_AUTH_TOKEN,FLY_DEPLOY_TOKEN,ZOT_CI_API_KEY,MAIN_PUSH_TOKEN) — Forgejo has no per-run approval gate for write users, so read-only + fork is the enforceable boundary. The ringtail agent-workspaces clone is repointed automatically (origin= fork,upstream= canonical); agents branch offupstream/mainand open cross-repo PRs. -
Closed a borgmatic monitoring blind spot: the metrics collector never scraped the main BorgBase offsite repo (only
sifaka-localand the immich photos repo were configured), so a failed offsite run produced no metric and no alert — BorgBase’s own email was the only signal. Added the offsite repo to the collector and aBorgmaticStaleGrafana alert (fires when any repo’s newest archive is older than 30h, ~7h after a missed nightly run). The hourly per-repo poll stays metadata-only (borg info/list); the heavy per-source manifest listing is now skipped for remote repos to avoid pulling a 100k-entry file manifest over the internet every hour. Also corrected the metrics script’s stale/opt/homebrew/var/forgejosource-path mapping to~/forgejo. -
Added
retries: 3/retry_wait: 300to the borgmatic config so a transient failure on a single repository — e.g. a broken SSH pipe partway through a large offsite upload to BorgBase — is retried (resuming from borg’s checkpoint) instead of losing that night’s backup. Surfaced when PR #407 repointed the forgejo source from the empty/opt/homebrew/var/forgejohusk to the real ~8.8 GB tree: the first offsite run under the new config had ~6.7 GB of new deduplicated data to push, the pipe broke mid-transfer (borg exit 87), and the night’s offsite backup failed with no retry. The dump hooks (before: configuration) are not re-run on retry. -
Agent workspaces can now open PRs and commit. Wired
tea(with a login seeded from the agents vault), aFORGEJO_TOKENfor the pr/branch/runner mise tasks, and a git author/committer identity into the workspace launcher. The token is an agents-owned Forgejo PAT (scopeswrite:repository+write:issue— PRs are issues in Forgejo, so tea needs the issue scope — stored concealed asagents-forgejo-tokenin the agents vault) — structurally bounded to the repos agents collaborates on, with no blumeops-vault dependency. Also revoked the bot’s leftover write on blumeops/project-template/adelaide-baby-shower-app. -
Disabled hephd’s
--self-updateon the indri heph hub and put its version fully under IaC:ansible/roles/hephnow converges the installedhephdto the pinnedheph_version(v1.7.0) on every provision — installing, upgrading, or downgrading as the pin changes — instead of bootstrapping once and letting the daemon self-update. The--self-update/--self-update-interval-secsflags are gone from the launchagent, so no release lands on the hub until a human bumps the pin and re-provisions. The ringtail agent spoke was already pin-only (no self-update); gilbert’s manual spoke gets documented steps to strip its self-update flags and pin its binary. Seehephaestus(reference/services) for the release → deploy flow. -
blumeops
mainis branch-protected — a push + merge whitelist limited toeblume— so no write collaborator can merge a PR or push tomain; human review/merge is the gate (theagentsbot is separately read-only + fork, see the fork-model change). The release workflows (build-blumeops,cv-deploy) commit a version bump back tomain, and because the automatic Forgejo Actions token can’t be push-whitelisted (Forgejo #11159) they now push withMAIN_PUSH_TOKEN— aneblume-owned PAT (write:repository) provisioned as an Actions secret via theforgejo_actions_secretsrole. This supersedes the earlier “mainis intentionally left unprotected against the bot” stance. -
Ringtail: the stray fish
ipfunction (which curled ipinfo.io / checkip.amazonaws.com) was shadowing iproute2’s realip, soip addr,ip route, etc. silently hit the network instead of running the command. Renamed it tomyipand brought it under home-manager (xdg.configFile) so it can’t drift back, and removed the shadowingip.fishplus a broken (prettyping-less)ping.fishfrom the host. -
Dropped the blumeops agent workspace — remote workers are now hephaestus, research, and playground only. Real blumeops work needs the whole blumeops 1Password vault (its ansible
pre_tasksand mise tasksop readbroadly), and that vault is deliberately the operational-secret blast-radius boundary with no least-privilege subset to grant a service account — so blumeops stays a local-on-gilbert, biometric-opjob. Also documented the deployment’s terms-of-use footing (ordinary, individual usage; native-app OAuth). Seeagent-workspaces§“Why blumeops is not a workspace”. -
Service review: reviewed the ringtail snowflake-proxy. Upstream is at 2.14.1 (2.12/2.13/2.14 released since), but nixos-25.11 is frozen at 2.11.0 and the
nixpkgs-servicespin is shared with k3s and forgejo-runner. As a minor anti-censorship service, it stays on the in-channel 2.11.0 build rather than mixing in an unstable channel; the version tracking now records the upstream gap. -
Service review: upgraded the ringtail forgejo-runner (
nix-container-builder) from 12.7.2 to 12.11.1 via thenixpkgs-servicespin, picking up the Go toolchain,golang.org/x/sys, andgo-gitsecurity fixes released since 12.7.2. k3s and snowflake (sharing the pin) are unchanged. -
Service review: reviewed k3s on ringtail (most stale, 94d). nixos-25.11 is frozen at the deployed 1.34.5+k3s1 (no
k3s_1_35/k3s_1_36attrs; unstable has 1.35.6, upstream latest 1.36.2), so it stays on the in-channel build rather than channel-mixing; the upstream 1.34.9 patch gap (klipper-helm CVE bump, containerd fixes) is recorded in version tracking. Cluster verified healthy. Also ran the weekly ringtail flake.lock update: nixpkgs3cac626→b6018f8(nixos-25.11); disko/home-manager already current,nixpkgs-servicespin held. -
Service review: reviewed tempo (most stale, 96d). Upgraded the home-built container 2.10.3 → 2.10.7 — the 2.10.x patch line brings
golang.org/x/netandgolang.org/x/cryptosecurity fixes; its one breaking change (OpenCensus receiver removal in 2.10.6) doesn’t apply since the distributor only uses the OTLP receiver. The v2.10.6 Go-1.26 floor required overridingbuildGoModule’s Go togo_1_26. Upstream 3.0.x is a major with breaking write-path/config changes and was deferred to a separate task. Also reviewed the weekly Prowler K8s CIS report (2026-07-05): all clear, 0 unmuted FAILs, net-zero week-over-week (1127 PASS / 53 muted). -
Service review (2026-07-13): reviewed the seven stalest ArgoCD services against upstream and actioned the three low-risk, self-contained bumps: grafana 12.4.2 → 12.4.5 (in-minor security CVEs — CVE-2026-9029/-33382/-42127; home-built
fetchurlcontainer rebuilt via CI), argo-cd v3.3.6 → v3.3.12 (in-minor, CVE-2026-41240 dompurify), and ollama 0.20.4 → 0.31.2 (upstream image tag). Deferred with heph follow-up tasks rather than stamping them reviewed: miniflux 2.3.2 and navidrome 0.63.2 (both bare-nixpkgs packages pinned to the deployed version — need a package override with recomputed hashes; navidrome also needsEnableSharing=false), authentik 2026.2.5 (from-source Nix build — sources + Go/Py/web vendorHashes; SSO blast radius), and immich v3.0.x (breaking major — pgvecto.rs dropped, DB migration). Theirlast-revieweddates were intentionally left un-stamped so they resurface in the stale queue until actually upgraded. -
agent-workspaces: add a general CLI toolbox (
cliTools: gawk, jq, curl, python3) to the ringtail agent-session PATH alongside the report toolchain. Plain shell agents constantly reach forawk/jq/curland quickpython3one-liners; without them sessions hitcommand not foundor fall back to slower workarounds. All nixpkgs builds — declarative, no new/run/current-system/sw/binexposure.python3is a bare interpreter (uv is already on PATH foruv run --script). Applied on the nextprovision-ringtail. -
Upgraded Immich v2.6.3 → v3.0.2 (server + machine-learning CUDA). The v3 breaking change (pgvecto.rs dropped for VectorChord) was already satisfied — ringtail’s
immich-pgrunscloudnative-vectorchord:17-0.5.0(vchord 0.5.0, pgvector 0.8.0), both inside v3.0.2’s accepted ranges — so this was a clean tag bump plus immich’s own startup migrations. Closes the v2.6.3 High-severity panorama-OCR stored XSS and the 2026-07-06 advisory cluster. A pre-upgradepg_dumpwas taken as a rollback artifact, and post-upgrade a one-time Metadata Extraction re-run is pending (tracked in heph). -
Service review 2026-07-17 (remote-agent): authentik 2026.2.2 → 2026.2.6 (most-stale service; latest patch on the current train — the 2026.5.x train jump is a separate follow-up). Source bump of the nix-built container via the Build Container CI dispatch with TOFU hash discovery; go vendorHash and the client-go pin carry over (go.mod/go.sum unchanged upstream). Also added a manual-dispatch Ringtail Flake Update workflow so remote-agent sessions can land
flake.lockbumps via CI on a PR branch. Added a Service Health Grafana dashboard (uid: service-health, folder “Service Health”): degraded deployments/statefulsets, containers stuck waiting, restart counts, and scrape-target status — the read surface for agent post-deploy health checks (credential design for agent API access under discussion). Reworkedmise run runner-logsto fetch job logs over the Forgejo web log route (…/jobs/N/attempt/M/logs) with the existing API token — no ssh to indri needed, so it now works from remote-agent sessions and while logs are still in dbfs. Also taught the Build Container workflow to post nix build failures (including TOFU hash mismatches) as PR comments. -
Service review (flyio-tailscale): reconciled tracking (the Fly proxy binary was bumped to v1.94.2 during the 2026-06-22 review but
service-versions.yamlstill read v1.94.1) and attempted the long-held jump to the 1.98 train. Deployed v1.98.8 toblumeops-proxyand tested MagicDNS inside the Firecracker container — it stillSERVFAILs tailnet names (nslookup indri.tail8d86e.ts.net 100.100.100.100) and blacked out all public routing (eblu.me/forge/cv → HTTP 000), the same failure mode as the original v1.96.5 regression. Rolled back to v1.94.2 in a few minutes; routing and MagicDNS verified restored. Notable: the 1.98 train is clean in k3s pods (PR #390) but NOT in the Fly no-DNS-manager container, so the pin stays on 1.94. Root cause (Fly container has no DNS manager, so tailscaled’s split resolver isn’t consulted) and the unblock path are tracked as a heph task. -
Fly proxy nginx base image bumped 1.30.3-alpine → 1.30.4-alpine (security release: CVE-2026-42533, CVE-2026-60005, CVE-2026-56434). Service review stamp for flyio-nginx; tracking entry corrected from stale 1.29.6.
-
Service review: upgraded the Fly proxy’s Grafana Alloy sidecar binary from v1.17.0 to v1.17.1 (digest-pinned), and corrected the stale
flyio-alloytracking entry inservice-versions.yaml, which claimed v1.14.1 while the Dockerfile had been on v1.17.0. -
Agent workspace repos on ringtail now clone to
~/code/personal/<repo>(was~/workspaces/<name>/<repo>), so the paths agents read in everyAGENTS.md/CLAUDE.mdresolve on the agent box. Remote Control session names (ringtail-<name>) are unchanged. -
Fly proxy deploys now work from any host: flyctl 0.4.71 pinned in mise.toml (was gilbert-only via brew).
Documentation
- Doc review: verified the “Manage Ringtail Lockfile” how-to — dagger
flake-lock/flake-updatepipelines, theprune-ringtail-generationstask, and its wiki-links all resolve against the current tooling. Stamped last-reviewed. - Doc review: corrected the NVIDIA device plugin reference card — time-slicing is 4 replicas per GPU (not 2) and the deployed image tag (v0.19.2) is now recorded.
- Doc review: verified the QArt Tuner reference card against
utils/qart/— CLI flags, web-UI parameter ranges, keyboard shortcuts, miseservetask, and thersc.io/qrdependency all match the code; wiki-links resolve. Stamped last-reviewed. - Doc review: verified the No Helm Policy explanation card against the live manifests — no Helm chart references remain anywhere under
argocd/, 1Password Connect is plain rendered manifests, and ArgoCD and the Tailscale operator both pull pinned upstream manifests viaresources:(forge mirror / raw GitHub) rather than charts. The migration-history table and “all services use kustomize” claim hold. No content changes; stamped last-reviewed. - Doc review (2026-07-14): reviewed the never-reviewed Caddy reference card and corrected several stale entries —
cv/docsare now served as static files from disk (not proxied to Tailscale endpoints), the retired minikube5432 → pg.tail8d86e.ts.netL4 route was replaced with the live5433/5434Postgres routes, and the proxied-service table was refreshed againstansible/roles/caddy/defaults/main.yml. - Doc review: corrected the mealie reference card for the ringtail k3s migration — manifests path (
mealie/→mealie-ringtail/) and storage class (minikube-hostpath→local-path). Service review: 1password-connect confirmed at upstream-latest 1.8.2 (Synced/Healthy), stamped reviewed. - Doc review 2026-07-17: rewrote the stale ArgoCD
apps.mdregistry card (post-minikube-ringtailapp names, six missing apps, cv/forgejo-runner departures, manual-sync-everywhere policy). Documented the remote-agent variant of the service-review, doc-review, and flake-update runbooks, and retired C0/C1/C2 references fromreview-documentation.mdto match the new AGENTS.md process. - Doc review: verified the Zot service reference card. Fixed the stale pull-through-cache description — it referred to
[[cluster|minikube]], but the cluster has been k3s on ringtail since the 2026-06 migration. Confirmed the registry is healthy (registry.ops.eblu.me/v2/ → 200) and the namespace convention, security model, and API-key-rotation steps still match the deployment. Stamped last-reviewed. - Doc review: tutorials/ai-assistance-guide.md — replaced the retired
minikube-indrikubectl context guidance withk3s-ringtail, corrected the indri native-service list, and noted Jellyfin’s LaunchAgent management. - Doc review: reviewed
tutorials/exploring-the-docs.md— replaced the stale reference to AGENTS.md’s retired kubectl-context requirement with its current critical rule (public repo, no secrets), and stampedlast-reviewed. - Added the ringtail Factorio headless server to
service-versions.yaml(nixos type, 2.0.77), documenting the temporaryversionsJsonoverlay that pins it ahead of nixpkgs to match the Steam client — including how to bump the pin and the note to remove it once nixpkgs catches up. - Forgejo reference: documented the consumers of the
api-tokenPAT (ansible role, runner-logs, and — new — the tea CLI, which keeps a copy in its own config) so a future rotation updates all three. Context: tea 0.14.2’s httpsign deadlock forced tea off SSH-signature auth and onto this shared PAT. - run-1password-backup: note that the account-wide export now also covers the new
agentsvault (and that any newly-added vault is swept in automatically — the export has no per-vault selection). Theop-backupscript is vault-agnostic, so no code change was needed.
[v1.18.1] - 2026-06-29
Bug Fixes
- Restored the
argocd/manifests/1password-connectandargocd/manifests/external-secretsbase manifests that the minikube decommission (a520f023) deleted while leaving the1password-connect-ringtailandexternal-secrets-ringtailApplications still pointing at them. Both apps had been stuck inComparisonError(ArgoCD could not generate their target state) ever since — the running pods stayed Healthy under Manual sync, so the breakage went unnoticed. The restored bases render images identical to what is live (1password/connect-*:1.8.2;external-secrets:v2.2.0-13895bb-nixvia the ringtail overlay), so syncing is a no-op. - Fixed all paperless-ngx document ingestion (API upload, consume folder, mail), broken since the Nix-image migration: the image ships no
/tmp, soSCRATCH_DIRresolved to a nonexistent/paperless, and in the multi-container pod the scratch dir was not shared between the web container (which writes API uploads there) and the worker (which reads them).PAPERLESS_SCRATCH_DIRnow points at a shared emptyDir, and a/tmpemptyDir keeps general temp usage off the container overlay. - Fixed a silent backup gap: borgmatic was backing up the dead Homebrew-era forgejo path (
/opt/homebrew/var/forgejo, frozen at 2026-04-06) while the live forge data at/Users/erichblume/forgejo— the 272MB DB and 8.8GB of git repositories — went uncaptured since the brew→source migration. Backups kept succeeding (the husk still existed), so no alarm fired. Now the live repos are insource_directoriesandforgejo.dbis dumped WAL-safe via the online.backupAPI (it is WAL-mode); the raw db files are excluded to avoid torn copies. Verified a fresh archive captures the live 272MB DB + current repos. - Added a
personobject-filter mask to thegablecamFrigate camera to stop a newly-planted Japanese maple (in the bottom-right planter) from being detected as a person and spamming alerts. The false detections scored 0.57–0.84 — overlapping real-person scores — somin_scorecouldn’t filter them; the mask covers only the front-deck-stairs corner by the building. Trade-off: a person actually on the stairs no longer alerts, but should trip an alert as soon as they step off into the driveway. Mask region derived from the actual false-positive bounding boxes via the Frigate events API. - Fixed duplicate homepage entries (DJ/Navidrome, Kiwix, Miniflux, ArgoCD,
Grafana, Prometheus, Transmission) after retire-minikube — the static
services.yamlentries that covered the formerly-invisible minikube services now collided with k8s Ingress annotation auto-discovery on ringtail. The annotations are the source of truth; the static duplicates are removed. - Paperless-ngx: raised the Celery
workermemory limit from 1Gi to 3Gi. The 1Gi cap introduced in the indri→ringtail migration OOMKilled OCR (consume_file) mid-import, stranding scanned uploads and freezing the auto-incrementing ASN at 46. - Refreshed all stale ZIM torrent URLs in
kiwix-ringtail/torrents.txt. kiwix only keeps the.torrentfor the latest build of each ZIM, so the whole_2026-01devdocs section plus thewikipedia_en_top1m_maxi_2025-09entry had silently 404’d — the kiwix sidecar could no longer add them to transmission. Bumped wikipedia to2026-04and every devdocs package to its current build (mostly2026-04, some2026-05); all 43 URLs now resolve 200. Added a note documenting the latest-only behavior so future 404s are an obvious date bump. - Relaxed the
frigateliveness probe (timeoutSeconds: 10,failureThreshold: 5; readinesstimeoutSeconds: 5). The default 1s timeout / 3 failures was killing the pod with SIGTERM on transient API stalls — 206 graceful-shutdown restarts over 36d, never an OOM — whenever frigate’s API thread blocked under detector/GPU load or NFS recording I/O. The pod now tolerates ~2.5min of unresponsiveness before a restart.
Infrastructure
-
Re-broadened the ringtail Alloy blackbox exporter from a single probe (
immich) to all 18 in-cluster HTTP services (argocd, authentik, frigate, grafana, homepage, immich, kiwix, loki, mealie, miniflux, navidrome, ntfy, paperless, prometheus, shower, teslamate, tempo, transmission). Coverage had collapsed to immich-only during the minikube retirement, leaving the other services silently unmonitored — andmise run services-checkwas reporting a green “OK” for 10 of them because itsServiceProbeFailurecheck passes when no firing instance exists. Each health path was verified to return 2xx unauthenticated from inside the cluster;showeris probed with itsHost: shower.ops.eblu.meheader andollamais intentionally excluded (scaled to zero on demand). The singleServiceProbeFailurealert covers every new target automatically vialabel_replaceon theintegrations/blackbox/*job label, so no new alert rules were needed.services-checkwas updated to mirror the probe list (no more false OKs) and to check indri/public services (forgejo, zot, devpi, cv) directly. Also swept stale post-minikube monitoring-host claims from the docs (runbook-service-probe-failure, port-services-check-alerts, federated-login, thetag:loki/tag:k8s-apirows in tailscale, and the prometheus textfile list). -
Migrated the borgmatic role’s pre-backup database snapshot hooks from the deprecated
before_backup:key to borgmatic 2.x’scommands:syntax, clearing thebefore_backup is deprecatedwarning logged since borgmatic 2.1.4. Usingbefore: configurationalso stages the heph/mealie/shower/navidrome dumps once per run instead of once per repository — previously the two repos (sifaka + BorgBase) each re-ran every dump, harmless but redundant. The abort-on-failure guarantee (a non-zero hook aborts the whole backup, so a failed snapshot is never silent) is preserved. -
retire-minikube tail cleanup (follow-up): simplified the container build tooling to nix-only.
container-version-checknow validates each container’sdefault.nixagainstservice-versions.yaml(dropped the dead container.pyVERSION/ DockerfileARGrules), andcontainer-build-and-releaseno longer carries dead container.py/Dockerfile classification. Stale build-model references purged from docs (forgejo, forgejo-runner, dagger tooling, grafana-image how-to, review-services, zot CI-auth) and thebuild-container.yamlworkflow comment. -
Pruned the remaining dead
container.py/Dockerfilebuild-model references left after retire-minikube.container-listandservice-reviewmise tasks dropped theirhas_container_py/has_dockerfileclassification branches (every container is nowcontainers/<name>/default.nix), and theupgrade-grafanaanddeploy-prowlerhow-tos now point at the nix builds instead of the retired Dockerfiles.Also reconciled the CI runner/dagger docs with the phase-6 host-mode reality (jobs run directly on indri with the mise toolchain — no job container, no
runner-job-image): rewrote upgrade-dagger around the mise-pinned host CLI, fixed the runner-environment section of the update-documentation how-to and the job model in configure-launchd-runner, and deleted the obsolete configure-k8s-runner how-to (superseded by configure-launchd-runner), repointing its inbound links. -
retire-minikube tail cleanup: pruned the dead container-build framework. Removed the
build,publish, andcontainer_versionDagger functions (and the now-orphanedcontainers.pycontainer.py-discovery module) — the Dockerfile/docker_build()and native-container.pybuild paths were retired when the minikube/arm64 runner went away, leaving nix as the only container build path. Updated dagger and build-container-image to document the nix-only reality. -
deploy-fly CI: provision
flyctlon the host-mode runner via mise (forgejo_runner_host_tools) and drop the in-jobcurl | shinstall, which hung indefinitely on an interactive PATH prompt on the macOS host runner (the install assumed an ephemeral minikube container). Workflow now callsflyctldirectly, matching how every other host-mode job finds its tools. -
Declared AI crawlers (ClaudeBot, GPTBot, meta-externalagent, Amazonbot, …) now get a bare nginx 403 at the Fly edge before the Anubis proxy hop. Outcome of the 2026-06-11 scraper-surge review: these bots were ~88% of all forge.eblu.me traffic and their Anubis/naughty rejection pages were >99% of remaining proxy egress, enough to saturate the proxy VM under storms. Anubis is unchanged and still walls off UA-spoofing crawlers.
-
Closed two backup gaps in the borgmatic role on indri. The heph hub DB (
heph.db, the only copy of all task/context data) is now snapshotted by a before-backupsqlite3 .backuphook — WAL-safe and fails loud, unlike borgmatic’s nativesqlite_databaseshook whose.dumpcan fail silently on a live WAL database. navidrome’s database (users, play counts, playlists) — a gap predating the ringtail migration — is now captured by enabling navidrome’s ownND_BACKUP_*snapshots (/data/backup, daily 01:00, keep 7) and ferrying the newest snapshot off the PVC via a newborgmatic_k8s_file_dumpshook (ls/catoverkubectl exec); this addedcoreutilsto the navidrome nix image for the in-pod tooling. -
Upgraded
authentik-redis(Authentik’s cache/broker) from Redis 8.2.3 to 8.6.3, rebuilt from nixpkgs on the nix-container-builder. The deployment has no persistence (ephemeral cache/broker), so the jump carries no data-migration risk. Also reviewed therefactor-services-check-to-query-alertsdoc card and the most-stale service (authentik-redis) as part of the recurring maintenance sweep. -
ringtail: add zram swap (zstd, swappiness=10) as an OOM pressure valve and set k3s
--kubelet-arg=fail-swap-on=false. Scale ollama to 0 replicas (on-demand) to drop its GPU contention and large memory tail. Relieves host-level OOM kills of k3s pods when gaming pushes memory over the top. -
Downgraded the security posture: kept the weekly Prowler K8s CIS hygiene scan but retired the kingfisher secret scanner entirely (ArgoCD app, manifests, custom container, prek hook, and the forge spork). TruffleHog remains the prek secret scanner. Also remediated the outstanding app-pod seccomp Prowler findings by adding
seccompProfile: RuntimeDefaultto the authentik (server/worker/redis) and frigate-notify pods rather than muting them. -
Tailscale operator stack: upgraded v1.94.2 → v1.98.5 (operator, proxy, and the new local k8s-nameserver), rebuilt from the forge mirror with the
go_1_26buildGoModule override (v1.98.5 go.mod floor is >= 1.26.3). The in-cluster MagicDNS nameserver is now a local nix-built image (containers/tailscale-k8s-nameserver/), replacing the floatingdocker.io/tailscale/k8s-nameserver:stabletag — that mutable tag was the vector behind the v1.96.5 MagicDNS-in-containers regression. -
Upgraded kube-state-metrics v2.18.0 → v2.19.1 (service review) — nix container rebuild from the forge mirror, picking up Go-toolchain and golang.org/x CVE fixes plus the pprof auth-filter hardening from v2.19.0. Added a
RuntimeDefaultseccomp profile to its deployment, remediating one of the Prowler K8s CIS findings. Compliance triage of the weekly Prowler report (18 unmuted, net-zero week-over-week) reworked the mutelist for the k3s finding profile: alloy node agents, the nvidia device plugin, local-path-provisioner, the k3s cloud-controller, and kube-apiserver node-proxy access are now muted as upstream-managed system/node-agent privileges. Remaining app-pod seccomp findings (authentik, frigate-notify) are tracked for RuntimeDefault remediation. -
Upgraded the homepage dashboard
v1.11.0→v1.13.2(service review). Rebuilt the custom nix image from the forge mirror (src + pnpm-deps hashes re-resolved, full build verified on ringtail). The range adds the ntfy widget, UniFi Drive widget, qBittorrent v5.2.0 / dispatcharr v24 API compatibility, and theGHSA-rg3r-jprv-xq38security fix — no breaking config changes for our widget set. -
Service review: upgraded the CloudNativePG operator on ringtail from v1.27.1 to v1.29.1. The 1.27 series reached end-of-life upstream (“no longer supported”); 1.29.1 is the latest stable and carries a metrics-exporter privilege-escalation fix plus Go runtime CVE patches. Operand PostgreSQL stays at 18.3. Also corrected a stale
service-versions.yamlentry (tracked 1.28.1 while the app deployed 1.27.1) and removed a dead minikube-sibling comment from the Application manifest. -
Upgraded Forgejo from v14.0.3 to v15.0.3 (major version) and made the forgejo Ansible role version-driven:
forgejo_version(+forgejo_go_version/forgejo_node_version/forgejo_build_tags) in the role defaults now pins the deployed tag, and the role fetches from the mirror, checks out, rebuilds when the running binary differs, and restarts. Bumpingforgejo_versionin a PR is now the whole upgrade — reproducible and DR-safe, closing the gap where the forge version lived only on indri’s filesystem. Added an upgrade-forgejo runbook (build-from-mirror flow, go-toolchain pin requirement, v15 breaking changes, SQLite DB backup, rollback). -
Upgraded Loki 3.6.7 → 3.7.2 (service review). Breaking changes in 3.7 are confined to the experimental v2 engine/scheduler, which blumeops’ single-binary deployment does not use.
-
Monthly tooling dependency refresh: prek hooks (trufflehog v3.95.6, ruff v0.15.18, prettier v3.8.4, taplo SHA correction, ansible-core 2.21.1), Fly proxy images (nginx 1.30.3-alpine, alloy v1.17.0), mise-task
typerpin 0.26.7, andactions/checkoutv6.0.3 in Forgejo workflows. -
Daily recurring review pass (2026-06-18):
- Service review of
frigate(stalest, 86d): already at the latest upstream stable (0.17.1 — v0.17.1 is the newest GitHub release), pod healthy and serving the API. No upgrade needed;last-reviewedbumped inservice-versions.yaml. Noted a high lifetime restart count (206 over 36d, last a graceful SIGTERM 3d ago, not an active crash loop) — filed a heph task to investigate. - Doc review of port-services-check-alerts (never reviewed): corrected the
stale “blackbox exporter already covers 5 services” claim — the ringtail
blackbox probe set is currently only
immich(argocd/manifests/alloy-ringtail/config.alloy), so re-broadening it is now the most impactful next step. All wiki-links verified; setlast-reviewed.
- Service review of
-
Service review: bumped
blumeops-pgPostgreSQL operand 18.3 → 18.4 (ghcr.io/cloudnative-pg/postgresql), picking up the May 2026 security release (11 CVEs incl. CVE-2026-6473 buffer overruns and several SQL-injection fixes); 18.x→18.x needs no dump/restore. Updated ringtail flake.lock (nixpkgsd6df3513→3cac626e, nixos-25.11;nixpkgs-servicespin held) viadagger call flake-update. -
Daily recurring review pass (2026-06-17):
- ntfy upgraded v2.19.2 → v2.24.0 (service review). Custom nix image rebuilt
from the forge mirror; no breaking config changes across v2.20–v2.24 (S3
attachment store, verified-email recipients, ACL access cache, SQLite
case-sensitive ACL fix, PWA token auto-extend). Image tag bumped in
argocd/manifests/ntfy/kustomization.yaml. - Doc review of first-alert-and-runbook: marked the alerting POC as
complete/deployed and corrected the stale “5 probed services” claim —
blackbox coverage is currently only
immich(see port-services-check-alerts to re-expand).
- ntfy upgraded v2.19.2 → v2.24.0 (service review). Custom nix image rebuilt
from the forge mirror; no breaking config changes across v2.20–v2.24 (S3
attachment store, verified-email recipients, ACL access cache, SQLite
case-sensitive ACL fix, PWA token auto-extend). Image tag bumped in
-
retire-minikube phase 6: the indri forgejo-runner flips to host-mode jobs (no more
runner-job-image; jobs run aserichblumewith the mise toolchain, which gains pinneddaggerandprek). Scope revision: Docker Desktop stays as the dagger engine host (hephaestus/cv CI also use dagger), right-sized from 6cpu/8GiB to 2cpu/4GiB. All stale arm64 build files deleted andbuild-container.yamlis nix-only. -
Added
uvto ringtail’ssystemPackagesfor fast Python package and project management alongside the existingmisetooling. -
Enabled
systemd-oomdswap-kill on ringtail (ManagedOOMSwap=killon the root slice,SwapUsedLimit=80%). A Crusader Kings 3 spike filled zram swap to ~95% and froze the whole host in a multi-minute memory-pressure stall (PSI memoryfull avg300≈30%) — sshd and the k3s API included. oomd was running but monitored zero cgroups, so nothing got killed. Now oomd kills the heaviest-swap cgroup when swap crosses 80%; because k3s pods are pinned to no-swap (so kubepods hold ~0 swap vs the gaming session’s ~15G), the victim is always a non-k3s process. Pod OOM remains the job of each pod’s memory limit plus the kernel cgroup OOM-killer. Pressure-based root killing (enableRootSlice) was deliberately avoided — it selects by memory footprint and could reap a pod before the game. -
Pinned
sifakato its LAN IP (192.168.1.203) in ringtail’s/etc/hostsvianetworking.hosts, so NFS mounts resolve over the LAN instead of tailscale MagicDNS. On 2026-06-26 sifaka’s tailscale node key expired; MagicDNS kept resolvingsifakato the now-dead node and every NFS mount on ringtail hung (kiwix, transmission, immich, paperless, etc.). The LAN path is authoritative (/etc/hostsbeats MagicDNS), keeps NFS traffic off the tailnet, and is immune to tailscale node-key churn — implementing the design the immichpv-nfs.yamlcomment always described. sifaka’s NFS export already permits192.168.1.0/24. Also disabled key expiry on sifaka’s tailscale node so it stops expiring. -
Removed
librewolffrom ringtail’ssystemPackages. After the nixpkgs flake bump, nixpkgs markslibrewolf-151.0.2insecure (unmaintained in nixpkgs, not a specific CVE), which blockednixos-rebuild. Firefox remains the configured default browser; librewolf was a standalone extra. -
Removed the retired
minikubeentry fromservice-versions.yaml— minikube on indri was retired 2026-06 (see retire-minikube); the service-review staleness queue no longer lists a non-existent service.
Documentation
- Corrected the
ServiceProbeFailurerunbook’s Affected Services table: verified against live Prometheus that the Alloy blackbox exporter now probes only immich (job=integrations/blackbox/immich), so the table no longer lists the retired indri-era services (miniflux/kiwix/transmission/devpi/argocd). Added superseded notes to the historical zot version-sync/tagging design cards (pin-container-versions, add-container-version-sync-check, adopt-commit-based-container-tags) pointing at the nix-only reality. - Condensed the
docs/how-to/zot/cards, which were verbose mikado-chain leftovers. Merged the four overlapping container-versioning cards (pin-container-versions, add-container-version-sync-check, adopt-commit-based-container-tags, add-dagger-nix-build) into a single container-versioning card documenting the current nix-only model, and trimmed the zot-hardening cards (harden-zot-registry, wire-ci-registry-auth, register-zot-oidc-client) down to tight present-tense how-tos — dropping theWhat Was Done/Verificationchecklists and file-listing tables that read as project records rather than documentation. - Doc review: purged retired-minikube references from the four alerting runbooks
(service-probe-failure, postgres-unhealthy, pod-not-ready, textfile-stale) —
--context=minikube-indri→--context=k3s-ringtail, “indri’s minikube cluster” → “ringtail’s k3s cluster”, and minikube health checks → k3s-on-ringtail equivalents. Also corrected the textfile-stale collector table (dropped the deadminikube.prom, added the liveforgejo.promandmacos_power.prom). - Reframed the security docs away from compliance-program emulation: the
securityreference card was retitled “Security & Compliance” → “Security”, dropped the PCI DSS / SOC 2 / ISO 27001 framework table, and now frames the Prowler scan as a hygiene check. Staleminikube-indriandargocd/manifests/prowler/paths corrected to ringtail /prowler-ringtail/. Spork docs note that kingfisher (the worked example) has been retired while the spork machinery stays for future sporks. - Doc review:
deploy-infra-alertingrunbook updated — the services-check coverage table no longer references the retired minikube cluster (k3s on ringtail is the only cluster post-retire-minikube). - Doc review: configure-grafana-alerting-pipeline accuracy pass — corrected the stale “Grafana and ntfy are on different clusters” rationale. Both now run on ringtail’s k3s since the minikube retirement, so the cross-cluster Caddy workaround is no longer load-bearing (cluster-internal ntfy DNS is now a viable future simplification).
- Reviewed
runbook-argocd-out-of-sync.md(never reviewed). Corrected the stale “30+ minutes” claim — theArgoCDAppOutOfSyncalert actually fires after a 5mfor:window. Verified both wiki-links resolve and the alert is defined ingrafana-ringtail/alerting.yaml. Setlast-reviewed: 2026-06-21. - Docs review: verified the snowflake-proxy reference card against the running service (
snowflake-proxy.serviceactive on ringtail, Prometheus metrics on :9999, v2.11.0 matching nixpkgs) and stamped itlast-reviewed: 2026-06-23. - Recurring reviews (2026-06-29): doc review of the Frigate service card (corrected stale image tag rc2 → 0.17.1-tensorrt, stamped reviewed); service review surfaced Forgejo (see infra entry); weekly Prowler K8s CIS compliance scan all-clear (0 unmuted FAILs, net-zero week-over-week).
- Doc review: stamped observability reference card as reviewed — all five component and seven alerting/runbook wiki-links resolve, and the Pyroscope (blocked on ringtail kernel sysctls) and Faro RUM (not deployed) future sections remain accurate.
- Doc review: automounter card updated for post-retire-minikube reality — consumers table now reflects NFS-direct ringtail workloads, adds the shower share, and flags vestigial mounts (music, torrents, frigate).
- Documented the flyio-proxy Tailscale node name drift (
flyio-proxy→flyio-proxy-1→-2): caused by ephemeral microVM state with no persisted/var/lib/tailscale, benign because routing/ACLs are tag-based and offline nodes auto-GC. Recorded the Fly-volume fix and the decision not to apply it (volume anchors the otherwise stateless proxy to one host). - manage-forgejo-mirrors: document that the old GitHub fine-grained PAT
shows “Last used: never” even after weeks of active syncing (last-used
tracking is unreliable for git-over-HTTPS), and add a
rate_limitauth check as the reliable way to verify a rotated mirror PAT.
AI Assistance
- Retired the “migrate every container to a locally built image” campaign. The reachable wins are done — all remaining upstream images (frigate’s TensorRT build, immich’s CUDA ML stack, the CloudNativePG PostgreSQL operands) are impractical to rebuild in Nix and stay on their upstream registries. AGENTS.md now frames local container builds as guidance for new services rather than a goal of universal localization, and the recurring “pick one non-local container and make it local” task has been dropped.
Miscellaneous
- Pruned dead minikube-era entries from the Prowler mutelist (removed
apiserver.yaml,control-plane.yaml,manual-node-checks.yaml; trimmedcore-pod-security.yaml), leaving only entries that match live k3s resources. No change to scan output (0 unmuted FAILs).
[v1.18.0] - 2026-06-11
Bug Fixes
- Granted the
offline_accessscope on the AuthentikhephOAuth2 provider so hephaestus spokes receive a durable 30-day refresh token. Previously the refresh token was session-bound, so spoke sync would silently fail with a400 Bad Requeston therefresh_tokengrant once the Authentik session lapsed. - Fixed the
tailscale-operatorandtailscale-operator-ringtailArgoCD apps showingUnknownsync status. Their shared base kustomization fetched the upstream operator manifest from the publicforge.eblu.me/mirrors/..., which the AI-scraper mitigation now black-holes (403). Pointed the remote resource at the tailnet hostforge.ops.eblu.meinstead, which the in-cluster repo-server can reach. - Upgraded Jellyfin on indri from 10.11.6 to 10.11.11, picking up the security fixes in 10.11.7 (disclosed CVEs/GHSAs, flagged “upgrade immediately”) and 10.11.10 (three further GHSAs). Noted the recurring gotcha in the service-versions tracking: after a
brew upgrade --cask jellyfin, the re-quarantined.appmakes the launchd-spawned process hang silently until the Gatekeeper first-launch dialog is approved on indri’s GUI console — removing the quarantine xattr over SSH is blocked by macOS TCC.
Infrastructure
- Deployed Anubis v1.25.0 (proof-of-work anti-scraper gateway) on the Fly.io
proxy in front of forge.eblu.me, after an AWS-hosted crawler with no declared
bot UA DoS’d Forgejo by walking the
/eblume/*commit-history surface at ~5.7 req/s. Browsers clear one JS challenge per week; git and API clients pass through untouched; declared AI crawlers are denied. The tailnet path (forge.ops.eblu.me) is unaffected. Tier 2b of the AI scraper mitigation plan. - Completed the external-secrets localization for the ringtail (amd64) cluster. The indri Dagger build (
container.py) only produces an arm64 image; addedcontainers/external-secrets/default.nixto build the amd64 variant on ringtail’s nix-container-builder, and gaveexternal-secrets-ringtaila thin kustomize overlay that reuses the shared manifest and points at the-niximage. Both clusters now run the locally-built external-secrets binary on their native architecture. - Added the hephaestus (
heph) sync hub to indri as a self-updating LaunchAgent managed by Ansible (ansible/roles/heph, tagheph). The hub runshephd --mode serverbehindheph.ops.eblu.me(Caddy TLS), with self-update on a 10-minute interval and the heph-pwa mobile shell served from--web-root. Access is gated by a new Authentik device-code (RFC 8628) OIDC application. Indri is now the canonical hub; other devices (e.g. gilbert) attach as offline-capable spokes. The hub’s store was seeded from gilbert via the data-safe Path A bring-up (copy store, resetmeta.origin). - Registered the heph-pwa redirect URIs (
https://heph.ops.eblu.me/, plushttp://localhost:8787/for dev) on the AuthentikhephOAuth2 provider, enabling the PWA’s new Authorization Code + PKCE “Login with Authentik” flow (and the token-endpoint CORS it needs). Pairs with hephaestus PR #9. - Localized the external-secrets controller image. It now builds from the forge mirror via a native Dagger
container.py(singleall_providersstatic Go binary, faithful to upstream’smake build) and is served fromregistry.ops.eblu.me/blumeops/external-secretsinstead ofghcr.io, bringing another platform component under local supply-chain control. - Localized the Tailscale operator stack: the k8s-operator image (both clusters) and the ProxyClass proxy image (indri, completing parity with ringtail) are now built from the forge mirror instead of pulled from Docker Hub.
- Phase 0 of retire-minikube: the forgejo-runner becomes a native macOS LaunchAgent on indri (new
forgejo_runneransible role), running jobs against Docker Desktop instead of a DinD sidecar in minikube. New runner identityindri-runneradvertising bothk8s(compat) andindrilabels; zot registry mirror moves into Docker Desktop’s daemon.json; runner logs ship to Loki via alloy. - retire-minikube phase 1 complete: prowler migrated to ringtail k3s (Nix-built from nixpkgs at 5.12.3 — a step back from 5.23.0 until nixpkgs catches up; same cis_1.11_kubernetes framework). Weekly CIS scans now target ringtail, k3s-appropriate node mounts, trivy + the image/IaC Dockerfile retired.
- Retired the Prowler container-image CVE scan and IaC scan, keeping only the K8s CIS benchmark scan. The two retired scans generated tens of thousands of un-actioned, un-muted findings every week (~20,000 image findings and growing, mostly unpatchable upstream-image CVEs; ~650 systemic Trivy KSV pod-security warnings) — the weekly
mise run review-compliance-reportsre-surfaced them all as “action needed” though none were ever triaged. The K8s CIS scan is fully mutelisted and runs clean, so it stays. Removed the two CronJobs, the now-unusedtrivyignore.yamlmutelist, and the grouped-findings rendering in the review tool that existed solely for the high-volume scans. - Upgraded Prometheus v3.10.0 → v3.12.0. Picks up fixes for stored XSS (CVE-2026-40179, GHSA-fw8g-cg8f-9j28) and remote-write/remote-read snappy decompression DoS (CVE-2026-42154), plus TSDB performance improvements. No breaking changes affect our deployment.
- retire-minikube phase 1 continued: navidrome migrated from minikube to ringtail k3s (Nix-built 0.61.1, exact version lift-and-shift; data PVC copied, music NFS remounted from sifaka).
- retire-minikube phase 4: ArgoCD self-migrated to ringtail k3s — the last workload off minikube. All 32 ringtail app destinations rewritten to in-cluster, the 13 minikube-only Application definitions deleted (their live workloads run unmanaged until phase 5), the argocd metrics job back in-cluster, and the admin password rotated on the fresh install. Minikube’s ArgoCD is scaled to 0 as rollback.
- retire-minikube phase 2 groundwork: ringtail
blumeops-pggains a managedauthentikrole (password sourced from the same 1Password item the authentik app reads, so the cutover is only apostgresql-hostflip), and borgmatic’s authentik entry moves from port 5432 (minikube) to 5434 (ringtail). The authentik database itself is dump/restored at the cutover window per the plan card. - retire-minikube phase 1 closed out: the seven parked minikube workloads (miniflux, navidrome, torrent, kiwix, unpoller, prowler, the k8s forgejo-runner) are decommissioned — ArgoCD apps cascade-deleted and manifests removed. All seven now serve from ringtail (or, for the runner, as a launchd service on indri). The miniflux database remains on minikube blumeops-pg untouched until the cluster itself retires in phase 2. Also restores the kiwix zim-hash
ignoreDifferencesthat the ringtail app definition dropped in the port (the zim-watcher CronJob patches that annotation at runtime, so without it the app reads permanently OutOfSync). - retire-minikube phase 5: minikube fully decommissioned. The 12
remaining minikube manifest dirs deleted, ansible
minikube/minikube_metricsroles removed, the Caddy L4:5432route and its.pgpassline retired,services-checkrewritten for the single-cluster world (ArgoCD app table now reads ringtail),ensure-minikube-indri-kubectl-configdeleted, the compliance report tooling’s minikube node-verification removed (k3s equivalent tracked in heph), tailnet tagstag:k8s-api/tag:loki/tag:pgswept from pulumi, and the docs sweep (AGENTS.md rule 2 inverted to k3s-ringtail, restart-indri/architecture/cluster/tailscale-operator/indri/ disaster-recovery cards revised, rebuild-minikube-cluster deleted). - retire-minikube phase 3 groundwork: Nix
default.nixports for the five LGTM-stack containers (prometheus v3.12.0 with the embedded mantine UI built from source, grafana 12.4.2 from the official release tarball, loki v3.6.7, tempo v2.10.3, grafana-sidecar 2.6.0), all build-verified on ringtail. Their Dockerfile/dagger build paths are retired. The*-ringtailmanifests stage the move: prometheus-ringtail gains in-cluster CNPG metrics scrapes for both ringtail pg clusters (previously dark), alloy-k8s repoints to the external LGTM names and absorbs the argocd/kube-state-metrics scrapes, and the PVC data copies- cutover follow on this branch.
- Upgraded the nvidia-device-plugin on ringtail from v0.19.0 to v0.19.2 (upstream patch release: CDI/Tegra fixes and dependency bumps, no breaking changes for our manifest-based CDI + RuntimeClass setup).
- Bumped the indri heph hub to v1.2.1, which adds the hub
GET /configendpoint and ships the heph-pwa Login with Authentik flow (Authorization Code + PKCE). Pairs with the Authentikhephprovider redirect URIs registered earlier. - Rebuilt all six migrated phase-1 service images from main (
-f386e2e-nixtags) and repointed the ringtail deployments at them, closing out the branch-built artifacts. - Rebuilt the external-secrets images off
mainand repointed both clusters to the stable main-sha tags (v2.2.0-13895bbarm64 /v2.2.0-13895bb-nixamd64), so the deployed images on indri and ringtail trace to the samemaincommit rather than earlier feature-branch builds. - Rebuilt the locally-built external-secrets image from the
mainbranch so the deployed tag (v2.2.0-0e70a1b) traces to amaincommit rather than the now-merged feature branch, giving a stable provenance reference. - Updated ringtail NixOS flake inputs (nixpkgs
nixos-25.11, disko) to latest viadagger call flake-update. - retire-minikube phase 3 close-out: the five LGTM images rebuilt
from main (
-8b1f89e-nix) and the ringtail apps repointed to them.
Documentation
- Reviewed the five stalest documentation cards (argocd, authentik, grafana, unifi, plan-a-meal): brought ArgoCD’s SSO/dual-cluster/sync-policy story up to date, expanded Authentik’s blueprint and OIDC client inventory to all eight clients, fixed Grafana’s TeslaMate datasource target and dashboard list, and noted UnPoller’s locally-built image.
- Kick off the minikube retirement: umbrella migration plan (retire-minikube) to move all remaining k8s workloads (miniflux, navidrome, torrent, kiwix, unpoller, prowler, the LGTM observability stack, authentik’s database, and ArgoCD itself) from indri/minikube to ringtail/k3s, convert the forgejo-runner to a native launchd service on indri, and decommission minikube.
- Reviewed four never-reviewed reference cards (
cluster,ntfy,tempo,alloy) and corrected drift: minikube is now Kubernetes v1.35.0; ntfy, tempo, and alloy-k8s images are now locally-builtregistry.ops.eblu.me/blumeops/*nix containers (v2.19.2, v2.10.3, v1.16.0) rather than upstream Docker Hub; the Fly.io alloy binary is v1.16.1; and the ringtail workload list reflects the in-progress minikube→k3s migration. - Corrected the 1Password backup how-to: the desktop app’s export menu item is named after the account (“File > Export > Blume/Davis”), not “All Vaults”. Verified an account export contains all four vaults (Private, blumeops, Payrix, Shared).
- Reviewed the tailscale-operator reference card: documented the dual indri/ringtail deployment, corrected the ArgoCD apps list, pinned the upstream version, and added the ProxyGroup Ingress
host:caveat. - retire-minikube phase 2 cutover complete: authentik now reads its
database from ringtail
blumeops-pgin-cluster (row-exact restore, SSO verified). Minikubeblumeops-pgsoaks idle until ~2026-06-18, then retires with cnpg, the Caddy L4:5432route, and its.pgpassline.
AI Assistance
- Retired the
ai-docsmise task and its mandatory session-start rule: the concatenated docs corpus had grown to ~130K tokens, too large to ingest wholesale. Agents now start tasks by finding and reading the relevant docs (grep + wiki-links);ai-sourcesremains for opt-in deep codebase context. Also documented the fullhephCLI task workflow (read, log, complete, create) in AGENTS.md.
Miscellaneous
- Service review: AutoMounter on indri is current at 1.13.0 (App Store auto-updated from the tracked 1.11.0); all sifaka SMB mounts verified healthy. Fixed the stale tracking-file path shown by
mise run service-review.