6.7 KiB
Varaverk — Claude Code Context
Working Rules (read first)
- Dev workspace —
/mnt/cloud-storage/Important Shit/Git/Development/Varaverk/. All editing happens here. - Prod —
/boot/config/plugins/varaverk/. Never edited directly. Only updated viagit pull(daily orchestrator or the pull button in the UI). - No Co-Authored-By in commit messages unless explicitly asked.
- No comments unless the WHY is genuinely non-obvious.
Current workflow: dev/prod split
Edit in dev, push to Gitea, pull prod when ready (daily orchestrator or manual UI trigger). Push is the only bridge — no deploy hooks, no rsync-on-save, no direct path references between dev and prod.
plugin_setup.sh stays pointing at the prod path. Dev never touches /boot/ directly.
Hard limits — do not cross these
- Never create or modify
.claude/settings.jsonin this repo. No workspace hooks, ever. The stale hook that existed here previously firedDeployment/deploy.sh(now deleted) on every file edit and caused unintended deploys. If you think a hook would help, ask first. - Never change
HOST1_STORAGE_MODE_INTERNALinhost1.conf. Claude data belongs in/mnt/user/appdata/claude-code/— not inside this repo. - Never move files between
Configurations/andDeployment/without explicit instruction.Configurations/= live runtime confs (gitignored).Deployment/= templates and setup tooling (tracked).
Project: What Varaverk Is
Self-healing, self-maintaining, mutually-redundant two-server Unraid home media ecosystem. One codebase runs on both servers. No primary/standby — both run independently and cover each other.
HOST1 — unRAID-Gmer4Lfe (gmer4lfe@gmail.com)
- Hardware: Threadripper 1950X, 128 GB RAM, ZFS cache pools
- Domain: Gmer4Lfe.com
- Runs: full arr stack (Sonarr/Radarr/Lidarr), auth stack (source of truth), Emby primary
HOST2 — unRAID-Jayred365
- Hardware: Intel i5 10th gen, 64 GB RAM
- Domain: Gmer4Lfe.us
- Status: being rebuilt — most host2.conf sections scaffolded, not yet fully online
Networking between hosts: Tailscale mesh. No hardcoded IPs — hostnames resolve via Tailscale.
Configuration System (three-file model)
Every script sources all three at startup:
master.conf ← shared: thresholds, toggles, profiles, orchestrator job lists
host1.conf ← HOST1 credentials, shares, container names, keys
host2.conf ← HOST2 credentials, shares, container names, keys
Sparse checkout (git) means each server only pulls its own host*.conf.
HOST1 never sees HOST2 credentials and vice versa.
Rule: thresholds/toggles → master.conf; credentials/paths/container names → host*.conf.
detect_hosts() in common.sh matches $(hostname) against HOST1/HOST2 in master.conf
and sets MY_ID / REMOTE_ID for the rest of the script.
Platform Adapter Layer
Plugin/unraid/adapter.sh isolates all OS-specific calls.
Scripts never branch on OS directly — always call adapter functions.
This is intentional architecture — don't bypass it.
Key Paths
| Path | Purpose |
|---|---|
master.conf |
Shared config — all thresholds, toggles, profiles |
host1.conf / host2.conf |
Per-host credentials, shares, container lists |
common.sh |
Shared functions — detect_hosts(), log(), notify(), etc. |
load_config.sh |
Sources all three conf files + common.sh |
State_Files/ |
Runtime state (watchdogs, fallback, transcode) — survives reboots |
data/ |
Historical logs and stats |
Plugin/unraid/ |
Unraid WebGUI plugin (PHP pages, API endpoints, adapter) |
Orchestrators/ |
Top-level schedulers (array_started, daily, weekly, watchdog) |
Watchdogs/ |
docker_watchdog, system_watchdog, resource_watchdog, stability |
Fallback/ |
Mutual container failover logic |
Rsync/ |
rsync.sh + profile system |
Media/ |
Arr cleanup, discovery, permissions, play state sync |
Tools/ |
Manual one-off tools including claude_startup.sh |
Orchestrator Schedule
| When | What |
|---|---|
| Array start | Orchestrators/array_started.sh → runs ARRAY_START_SCRIPTS |
| Every minute | watchdog_orchestrator.sh → resource → docker → system → stability watchdogs |
| Every 30 min | critical_sync_maintenance.sh → downloaders_reset, play_state_sync, critical rsync |
| Every 4 hours | intermediate_sync_maintenance.sh → arr_sync, arrs_failed_stalled_recovery |
| Daily 1am | daily_sync_maintenance.sh → git pull, permissions, cleaners, arr cleanup, docker updates |
| Sunday 2:30am | weekly_sync_maintenance.sh → full Emby + Critical-Data sync, weekly restarts |
| Sunday 3am+ | monthly_maintenance.sh (self-gated on 30-day uptime) → ZFS scrub, SMART tests |
| Sunday 7am | sunday_morning_coffee_report.sh → ZFS, SMART, certs, backup verify, bandwidth, Emby report |
Rsync Toggle State (current)
RSYNC_ENABLED=true
CRITICAL_RSYNC_ENABLED=true
INTERMEDIATE_RSYNC_ENABLED=true
DAILY_RSYNC_ENABLED=true
WEEKLY_RSYNC_ENABLED=true
FALLBACK_RSYNC_ENABLED=true
Fallback System
fallback.sh runs continuously from array start.
States: NORMAL | FALLBACK | NO_INTERNET | DARK
DDNS rules are absolute:
- Internet loss → stop own DDNS immediately
- Failover → start remote's DDNS as Tier 1 first
- Handback → stop remote DDNS → rsync → start containers → start local DDNS last
Tier delays before activating higher tiers are in host*.conf (HOST1_TIER*_DELAY, HOST2_TIER*_DELAY).
Port Notes
- NPM admin API (
HOST1_NPM_URL) — port 7818. Port 81 is the partnership WebUI port (HOST1_PARTNERSHIP_AUTH_WEBUIS), not the API. Easy to confuse. - HOST1_NETWORK_WATCHDOG_NPM_URL — external HTTPS domain, completely separate from the admin API.
Known Gaps / Active Work
- HOST2 NPM/lldap credentials (
HOST2_NPM_USER,HOST2_NPM_PASS,HOST2_LLDAP_PASS) are empty inhost2.conf— fill in when HOST2 is back online. PARTNERSHIP_ENABLED=false— not yet active.FALLBACK_ENABLED=true— fallback is running.
Claude Code Persistence on Unraid
/root is a RAM filesystem — wiped on every reboot.
Tools/claude_startup.sh runs at array start (via ARRAY_START_SCRIPTS) and:
- Symlinks
/root/.claude→/mnt/user/appdata/claude-code/.claude - Symlinks
/root/.local/share/claude→/mnt/user/appdata/claude-code/local/share/claude - Symlinks
/root/CLAUDE.md→/boot/config/plugins/varaverk/CLAUDE.md(this file)
This file lives on /boot (USB flash) and is always available regardless of array state.
Commit Style
Plain, concise messages. No Co-Authored-By trailers. No bullet-point summaries in the body. One sentence on the why, not the what.