## Summary - Fix env var name from `ND_SCANSCHEDULE` to `ND_SCANNER_SCHEDULE` (Navidrome uses viper config where dots become underscores) - Use explicit `@every 1h` format for clarity - Reorder CLAUDE.md rules to emphasize running zk-docs first ## Root Cause Navidrome logs showed "Periodic scan is DISABLED" at startup despite the env var being set. The config key is `scanner.schedule`, which translates to `ND_SCANNER_SCHEDULE` (not `ND_SCANSCHEDULE`). ## Deployment and Testing - [ ] Sync navidrome app: `argocd app sync navidrome` - [ ] Verify pod restarts with new env var - [ ] Check logs for "Scheduling scanner" message instead of "Periodic scan is DISABLED" - [ ] Wait ~1 hour and confirm scan runs automatically 🤖 Generated with [Claude Code](https://claude.ai/code) Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/101
3.5 KiB
CLAUDE.md
Guidance for Claude Code working in this repository. See also ai-assistance-guide.
Overview
blumeops is Erich Blume's GitOps repository for personal infrastructure, orchestrated via tailnet tail8d86e.ts.net.
CRITICAL: Public repo at github.com/eblume/blumeops - never commit secrets!
Rules
- Always run
mise run zk-docs -- --style=header --color=never --decorations=alwaysat session start This will refresh your context with important information you will be assumed to know and follow. - Always use
--context=minikube-indriwith kubectl - work contexts must never be touched - Feature branches only - checkout main, pull, create branch, commit often
- Create PRs via
tea pr create- user reviews before deploy, merges after - Check PR comments with
mise run pr-comments <pr_number>before proceeding - Add changelog fragments -
docs/changelog.d/<branch>.<type>.mdTypes:feature,bugfix,infra,doc,ai,misc - Test before applying - dry runs (
--check --diff), syntax checks,ssh indri '...' - Wait for user review before deploying
- Never merge PRs or push to main without explicit request
- Verify deployments -
mise run indri-services-check
Project Structure
./docs/ # documentation (Diataxis, Quartz)
./docs/changelog.d/ # towncrier fragments
./mise-tasks/ # scripts via `mise run`
./ansible/playbooks/ # ansible (indri.yml primary)
./ansible/roles/ # indri service roles
./argocd/apps/ # ArgoCD Application definitions
./argocd/manifests/ # k8s manifests per service
./pulumi/ # Pulumi IaC (tailnet ACLs, cloud)
~/code/personal/ # user's projects
~/code/3rd/ # mirrored external projects
~/code/work # FORBIDDEN
Service Deployment
Kubernetes (ArgoCD)
Most services run in minikube on indri via ArgoCD (app-of-apps, manual sync).
PR workflow:
- Create branch, modify
argocd/manifests/<service>/ - Push, then
argocd app sync apps - Test on branch:
argocd app set <service> --revision <branch> && argocd app sync <service> - After merge:
argocd app set <service> --revision main && argocd app sync <service>
Commands: argocd app list|get|diff|sync <app>
Login: argocd login argocd.ops.eblu.me --username admin --password "$(op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get srogeebssulhtb6tnqd7ls6qey --fields password --reveal)"
Indri (Ansible)
Native services: Forgejo, Zot, Caddy, Borgmatic, Alloy
mise run provision-indri # full
mise run provision-indri -- --tags <role> # specific
mise run provision-indri -- --check --diff # dry run
Routing
| Domain | Mechanism | Reachable from |
|---|---|---|
*.ops.eblu.me |
Caddy on indri (100.98.163.89) | everywhere incl. k8s pods |
*.tail8d86e.ts.net |
Tailscale MagicDNS | tailnet clients only |
Check tailscale serve: ssh indri 'tailscale serve status --json'
Container Releases
mise run container-list # show images/tags
mise run container-release <name> <version> # tag and build
Third-Party Projects
Ask user to mirror on forge first, then clone to ~/code/3rd/<project>/.
Task Discovery
mise run blumeops-tasks # fetch from Todoist, sorted by priority
Credentials
Root store is 1Password. Never grab directly - use existing patterns (ansible pre_tasks, external-secrets, scripts with op CLI). Warn user before any credential access.