tududi speaks the OpenAI chat completions API for its daily brief and
task/project insights, so it can use the Ollama box directly instead of a
hosted provider -- nothing about the task list leaves the network.
LLM_API_KEY has to be set even though Ollama ignores it; without a key
the generation endpoints answer 503 and the UI shows a not-configured
state. It is a secret so the value can be swapped for a real one if the
provider ever changes.
gemma4:e4b was checked against the JSON-only replies these features parse
and answered correctly in about five seconds.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The deploy job only waited on the deployments that existed when it was
written, so a broken rollout of either new app would have been reported
as a successful deploy.
Also records the two new secrets in the bootstrap table, and the two
traps found while adding these: dashwise publishes :latest for amd64
only, and a server-side dry run of a brand new namespace reports every
resource inside it as missing until the namespace exists.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two self-hosted apps behind traefik, both keeping their state on the
GlusterFS volume that is mounted on every node:
- dashwise (home.wittyoneoff.com) is an all-in-one image running its web
server, a bundled PocketBase and valkey side by side. Only port 3000 is
published: the frontend resolves its backend as window.location.origin
and every PocketBase call is made server-side, so 8090 stays inside the
pod. It is on the service so the PocketBase admin UI can be reached with
kubectl port-forward.
- tududi (tududi.wittyoneoff.com) stores a SQLite database and user
uploads. Both are VOLUMEs in the image, so both are backed by the claim
-- as one volume mounted twice with subPath, because naming the same
claim as two volume entries wedges kubelet, which is what happened with
limesurvey.
Both images are pinned to tags that publish an arm64 manifest. dashwise
:latest and :stable are amd64 only and would not start on these nodes.
Namespaces and secrets are applied out of band, as with the other apps.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
From fork commit 054b3a5c0: the AI summary error box now names the
reason, so a failure can be diagnosed from a phone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
From fork commit 0cc374886: the AI summary request is also repeated when
the LLM server answers 5xx, which is the failure that arrives at once
rather than as a timeout.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
From fork commit 4a582c0a1: the AI summary request is repeated once when
the LLM server does not answer in time, which is what happens while an
idle Ollama loads the model back into memory.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
From fork commit c7e8bba48: password inputs are styled like text inputs
(the AI summary API key field rendered white) and the field description
is shortened.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
From fork commit 8edc36875: the AI Summary preferences tab is only shown
when the plugin is activated in settings.yml, users can configure an API
key for their own LLM server, and grounding is on by default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
New multi-arch image (amd64+arm64) built from searxng fork ce400f993:
the ai_summary plugin can now authenticate to the LLM server with an
ai_summary.api_key, sent only to the configured base_url.
secret.example.yaml documents the ai_summary block, including the new
optional api_key.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The space made it an invalid tzdata name, so the container silently fell
back to UTC. Standard searxng container config, unrelated to the
ai_summary fork changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The manifest pinned :ai-summary-20260727, two builds behind the running
deployment. Applying this repo would have rolled the instance back past
the OpenAI chat-completions switch and the Brave-iOS streaming fallback.
kubectl diff against the live deployment is now empty.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
unbound was bundled inside apps/pihole/ and invisible in the apps/
listing. Now apps/unbound/ (deployment + service + kustomization); it
stays in the pihole namespace, whose Namespace object remains owned by
apps/pihole. No resource changes — server-side dry-run clean (36
resources).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An unset secret expands to empty, base64 -d writes a zero-byte kubeconfig,
and kubectl falls back to localhost:8080 with a misleading connection
error. Guard both jobs and echo the current context after configuring.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A fresh node pull of pihole:latest silently upgraded v5->v6 (Core v6.2.2).
v6's default listeningMode=LOCAL drops DNS from non-attached subnets, which
killed all cross-node svclb DNS the moment the pod rescheduled off its old
node. v6 also ignores the WEBPASSWORD env.
- image pinned by digest (Core v6.2.2)
- FTLCONF_dns_listeningMode=ALL
- admin password via FTLCONF_webserver_api_password <- pihole-admin secret
- tcpSocket:53 readiness probe so rollout status waits for FTL
Applied to the cluster via kubectl replace; DNS verified answering on all
four node IPs, admin API auth verified.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- .gitea/workflows/deploy.yaml: PRs run a server-side dry-run; pushes to
main apply the kustomization and wait for all rollouts. Modeled on
socktop-webterm's pipeline; uses the same KUBECONFIG secret convention
and gitea-deployer ServiceAccount.
- rbac/gitea-deployer.yaml: ClusterRole/Binding (admin bootstrap, outside
the root kustomization) — repo resource kinds only, no secrets access,
no delete verbs, no RBAC escalation. Applied to the cluster 2026-07-26.
- One-time env->secretKeyRef migration executed against the cluster;
README updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Captured 2026-07-26 from rpi-master (k3s v1.30.3) and cleaned of runtime
fields. Six apps as per-app kustomizations: vaultwarden, searxng,
home-assistant, nginx, pihole(+unbound), unified-streaming.
Intentional divergences from live state:
- pihole WEBPASSWORD and USP_LICENSE_KEY moved from inline plaintext env
to secretKeyRef (secrets gitignored; templates in secret.example.yaml)
- HA ingress defaultBackend fixed (pointed at nonexistent service)
- unifiedstreaming-svc kept as ClusterIP (LoadBalancer could never bind
port 80 behind svclb-traefik)
Validated against the live cluster with kubectl apply --dry-run=server:
no immutable-field conflicts; one-time kubectl replace procedure for the
two env->secretKeyRef migrations documented in README.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>