Fix 1 — Monitor partner card (common.php + monitor.php):
vv_remote_hosts_stats() no longer skips hosts with no API key.
Returns no_api_key:true entry instead. Monitor JS renders
"API key not configured — complete Onboard to enable" instead
of a blank space.
Fix 2 — rawconf push not alarming pre-onboard (config.php + scheduler.php):
Probe failures (Tailscale not found, plugin not installed) now carry
ready:false. JS treats ready:false results silently — button shows
"✓ Saved" not "push failed: HOST2" before SSH is set up.
Only genuine post-onboard failures (ready not false) show as errors.
Fix 3 — Partnership Onboard button (partnership.php):
Disabled with tooltip when no partner hostname is in master.conf.
When partner configured but not onboarded, adds explanation note:
"Onboard will generate your SSH key, exchange it with the partner..."
No partner configured: "Edit master.conf and set HOST2."
scheduler.php: after host1.conf save in setup mode, redirect to
?tab=partnership&vv_onboard=1 instead of Monitor.
HOST2+ still redirects to Monitor (they don't manage the partnership).
partnership.php: detects vv_onboard=1 URL param after actions render.
Adds pulse animation + box-shadow to the Onboard button and scrolls
it into view. One-shot — gone when user navigates away.
Varaverk.page: also shows wizard when local host.conf is missing
(handles master.conf pushed by HOST1 before HOST2 installs plugin).
pages/setup.php: three wizard flows
- Standard: blank master.conf, fill hostnames, redirect to scheduler
- Host2/state file: state file detected, pull master.conf from HOST1 via SSH
- Conf-only: master.conf already filled (was pushed), just create local host.conf
api/setup.php:
- save action: writes master.conf + host.conf, creates varaverk_setup.db state file,
redirects to ?tab=scheduler&vv_setup=master.conf
- pull action: resolves HOST1 Tailscale IP, queries HOST1 SCRIPTS_DIR, SCPs
master.conf, creates local host.conf, redirects to ?tab=scheduler&vv_setup=hostN.conf
include/config.php: vv_setup_state_read/write/push helpers.
vv_push_setup_state() pushes varaverk_setup.db to /boot/config/ on all known
remotes — no plugin-readiness probe needed (flash is always accessible).
api/rawconf.php: calls vv_push_setup_state() alongside master.conf push.
pages/scheduler.php: setup mode via ?vv_setup=<conf> URL param.
Auto-opens the specified conf file on page load (DOMContentLoaded).
vvSaveRawConf: in setup mode, skips confirm dialog and forces sequence:
master.conf save → auto-open hostN.conf
hostN.conf save → redirect to Monitor (setup complete)
Plugin/varaverk.plg: URL updated to github.com/FailedProxy/Varaverk
Configurations/host.conf.template:
Full host conf structure with HOSTN/hostn placeholders.
All personal values blank, all sections documented.
Covers identity, rsync, docker, fallback, media, monitors,
transcodes, arrs, system watchdog, resource manager.
Varaverk.page: checks if HOST1 is blank before rendering tabs.
If blank → shows setup wizard, returns early (tabs never render).
pages/setup.php: first-run wizard UI.
Auto-populates hostname from hostname -s.
Role selection: primary (HOST1) or partner (HOST2+).
Partner slot selector for HOST3+.
api/setup.php: handles wizard form POST.
Writes HOST1/HOST2 (and HOST3+) into master.conf preserving all
other content. Creates host*.conf from template with HOSTN/hostn
replaced and SSH key path pre-filled from hostname convention.
Never overwrites an existing host*.conf.
Plugin/varaverk.plg:
- Method="install update": git clone (fresh) or pull (update)
Validates Unraid, checks array is started via shfs mount, clones
to SCRIPTS_DIR (read from varaverk.cfg, default /mnt/user/appdata/Varaverk),
creates Plugin/unraid symlink, inits varaverk.cfg, bootstraps master.conf
from template on first install.
- Every boot: lightweight boot.sh recreates symlink if missing (no git ops).
- Method="remove": removes web symlink, leaves appdata intact.
Configurations/master.conf.template:
- Full master.conf with personal values blanked: HOST1/HOST2 empty,
GITEA_REPO_PATH empty, personal container names in profiles cleared,
FALLBACK_ENABLED=false, CRITICAL/DAILY rsync defaults corrected to true.
New users fill in HOST1, HOST2, then proceed to partnership setup.
Single SSH probe per remote checks all three conditions in one call:
- plugin cfg exists (varaverk.cfg present with SCRIPTS_DIR)
- Configurations/ dir exists at that path
- master.conf already present on remote
Any failure skips that host entirely rather than pushing blind.
Uses the discovered SCRIPTS_DIR as the SCP destination, not ours.
Instead of assuming the remote uses the same appdata path as the local
host, SSH-grep their varaverk.cfg first and SCP to their actual
Configurations/ dir. Falls back to /mnt/user/appdata/Varaverk if the
plugin isn't installed or the file can't be read.
vv_push_master_conf() in config.php: finds all remote HOST* entries,
resolves Tailscale IPs, SCPs master.conf to each.
rawconf.php calls it after a successful write when file=master.conf.
Scheduler save button shows sync status: "✓ Saved · synced to HOST2"
or "✓ Saved · push failed: HOST2" on error.
Also fix path bug in partnership_transfer.sh — was SCPing to
appdata root instead of Configurations/.
VaraverkSettings.page (Settings → Other Settings) now owns SCRIPTS_DIR.
The inline Advanced-mode field and vvSaveSettings() in the Scheduler tab
were a second path to the same write — removed.
- Tools and Custom: args input always visible (translucent at rest, full on hover)
- Orch children: args input hidden when orch is on, shown when orch is off
(same toggle as the cron field — orch off = standalone mode)
- vvRunJob/vvDryRun: pick up .vv-script-args value, POST as extra_args
- run.php / dryrun.php: accept extra_args, validate against shell metacharacters,
append to run_job.sh invocation (flows through SCRIPT_ARGS to the script)
- CSS: .vv-script-args — 30% opacity at rest, 100% on hover/focus
PHP architecture:
- Extract common.php from monitor.php — shared system functions (vv_system_info,
vv_memory_breakdown, vv_remote_hosts_stats, disk/GPU/UPS/network/docker/parity, etc.)
now live in one place; monitor.php and watchdog.php both require common.php
- Add unraid_api.php as explicit include (was implicit via config.php chain)
- confform.php: add missing require_once config.php (implicit dep made explicit)
- Delete orphaned pages/docs.php and pages/config.php (absorbed into scheduler)
Watchdog page:
- Add Storage watchdog card (growth + log strikes, baseline age, suppress ceilings)
- Add Network watchdog card (NPM strikes, DDNS domain/container, NPM URL)
- One host per row layout — all 5 watchdog cards equally spaced via inner grid
- Watchdog now uses Unraid API for local system stats; remote nodes with API key
but no SSH get system info from vv_remote_hosts_stats() with api_only flag
- SSH bundle: /proc/meminfo passed as raw section instead of awk-parsed header
fields — fixes RAM showing 0 on remote hosts where awk quoting was unreliable
- vv_wd_local_system() rewritten as thin wrapper over vv_system_info() + vv_memory_breakdown()
Monitor page:
- Watchdog card: add stability strikes, storage watchdog strikes, network NPM status,
live system stats (rootfs/log/tmp %, RAM free, load, CPU temp, zombies, NIC, sshd)
- Row height: switch from max-height on cards to minmax(0, calc(...)) on grid track —
all cards in a row now fill to the tallest card's height correctly (fixes Pools card
being shorter than neighbours)
Scheduler page:
- Add Tools section above Custom Scripts — lists Tools/*.sh with run/dry-run/cron/log
- vv_tools_scripts() function in scheduler.php include
Tools:
- Add docker_prune_images.sh — removes dangling Docker images; --dry-run and --status modes
- Replace pill view with per-container rows showing full detail
- docker inspect batch call: networks+IPs, port mappings, bind mounts
- Container icon from template XML, name links to WebUI if configured
- Network IP badges (blue), port mapping badges (yellow)
- Bind mount paths shown src→dst, collapsible expand for >3 paths
- Large folders (>7 containers) auto-span full width
- Status badge: RUNNING/STOPPED/PAUSED/EXITED with colour
- Stopped containers dimmed, icons load from template XMLs
- Primary store moved to /boot/config/plugins/varaverk/docker_folders.json
- No dependency on folder.view3 plugin being installed
- Auto-imports folder.view3 JSON on first run if it exists (one-time bootstrap)
- Mirrors writes to folder.view3 JSON only if that plugin's directory is present
- Toolbar shows '⇄ folder.view3' badge when sync is active
- New Docker tab (between Scheduler and Watchdog)
- Reads /boot/config/plugins/folder.view3/docker.json — fully compatible with folder.view3 plugin
- Writes changes to both docker.json AND HOST*_DOCKER_FOLDER_MAP in host*.conf simultaneously
- Edit mode: rename folders (inline input), delete folders, move containers via popover picker, create new folders
- Drift banner: highlights containers where conf desired state doesn't match json actual state
- Sync conf→JSON: apply conf desired state to json (fixes drift after onboard)
- Sync JSON→conf: capture manual json edits back into conf
- Ungrouped section shows all containers not assigned to any folder
- Onboard scripts can read HOST*_DOCKER_FOLDER_MAP to auto-place new containers
Scheduler UI:
- Arrange mode: drag scripts between orchs and reorder within arrays; right
panel shows unassigned script pool; Save Arrangement commits to master.conf
- + Folder: named collapsible subfolders for Custom Scripts stored in schedule.json
- Rsync children: hide Run/Dry Run/Log/location when orch is ON; show standalone
location + cron controls when orch is OFF; cron only fires when both filled
- Non-conf-managed children (transcode): toggles now show enabled when orch is on
- Right panel height sync: fix ResizeObserver feedback loop via align-self:flex-start
on left panel and left.offsetHeight in vvFitRight
- How do I use this: updated to cover arrange, folders, rsync standalone, transcode
New API endpoints:
- board.php, clearlock.php, movescript.php, rawconf.php, readscript.php
- reorderarray.php, rsync_standalone.php, savefolders.php
run.php / dryrun.php: accept optional --location= arg for standalone rsync calls
- vv_script_children() now calls vv_script_suggested_cron() per child,
adding suggested_cron and suggested_label to each child entry
- Orch rows (non-event) and regular script child rows render a faint
.vv-cron-hint span to the left of the cron input showing the suggested
cron from the script's # Schedule: header
- Clicking the hint fills in the cron input (data-cron + onclick)
- Tooltip shows full "suggested_cron — label" string on hover
- .vv-cron-hint: color #444, brightens to #888 on hover
- Right panel title: "Suggested Schedules" → "Scheduler Information"
- Removed top hint paragraph; info now lives in the panel itself
- Added three collapsible info sections (open by default) at top of panel:
Controls — toggle, cron, run, dry run, log, stop, verbose, config
Orchestrators — enabled/disabled behavior, child cron rules, event triggers
Children & Advanced — toggle semantics, independent cron, rsync flag badge
- Bullet lists use CSS columns:2 with column-fill:balance for even distribution
- "Suggested Schedules" divider separates info from parsed schedule blocks
- Added vvToggleSug() for DOM-traversal-based accordion (no ID dependency)
- Rsync/rsync.sh children in Advanced now show as conf_flag type when the
parent orch controls a *_RSYNC_ENABLED tier flag; toggle writes true/false
to master.conf instead of comment/uncommenting a SCRIPTS array entry
- Added vv_conf_flag_value() and vv_conf_flag_set() helpers in scheduler.php
- Added api/flag_toggle.php endpoint (validates *_RSYNC_ENABLED pattern)
- Added api/stop.php: kills process group, sweeps stuck locks, updates stat
- vv-flag-badge CSS (amber, monospace) to distinguish from event/script rows
- vvSaveChild() routes conf_flag children to flag_toggle.php unconditionally
- vvApplyOrchState() keeps conf_flag toggle at real flag value; disables when orch off
- vvSaveAll() skips conf_flag children (immediate-save only)
When orch is ON (god mode):
- Children's toggle state is read from master.conf comment status
- Toggling a child comments/uncomments its line in the *_SCRIPTS array
- Child crons are suppressed in vv_cron_rebuild — orch is the sole trigger
- Children not found in any *_SCRIPTS array are shown disabled (read-only)
When orch is OFF:
- All children flip to off; schedule.json updated immediately
- A child with a cron value + enabled toggle gets its own independent cron entry
- A child with no cron does nothing when enabled
New: vv_conf_script_map() — cached per-request scan of master.conf arrays
New: vv_parse_conf_array_full() — includes commented entries (disabled scripts)
New: vv_conf_toggle_script() — comments/uncomments a script line in master.conf
New: api/conf_toggle.php — endpoint for child toggle → master.conf write
Two hardcoded event-triggered entries appear at the top of the scheduler
(array_started.sh / array_stopping.sh). They show an ⚡ Array Start /
⚡ Array Stop badge instead of a cron field and are enabled/disabled via
the normal toggle.
Static event scripts fire them via Unraid's event system:
- event/disks_mounted/array_start_jobs → runs in background (non-blocking)
- event/disks_unmounting/array_stop_jobs → runs foreground (blocks until done)
vv_cron_rebuild() skips @array_* entries so they never land in the cron file.
Scripts executed on each event are managed in master.conf via
ARRAY_START_SCRIPTS and ARRAY_STOP_SCRIPTS arrays.
Auto Scroll now pauses automatically when user scrolls up and resumes
when they reach the bottom — no separate Scroll Lock needed.
Lidarr discovery no longer hard-skips single-seed candidates; they
score low on breadth but can still reach threshold on merit.
Before update_cron was wired in, the plugin wrote directly to
/etc/cron.d/varaverk. That file persisted after the migration and
caused duplicate job firing (two watchdog instances at :00/:15/:30/:45).
The second instance hit the lock, exited with warn, and overwrote the
stat file — killing the running indicator while the first was still live.
vv_cron_rebuild() now unlinks the legacy file after every update_cron
call. Since rebuild_cron (boot event) calls vv_cron_rebuild(), the
cleanup runs on every reboot and every schedule save.
run_job.sh was overwriting the log on every cron fire, making it
impossible to see run history. Switch to append mode, print a
── YYYY-MM-DD HH:MM:SS ── separator before each run, and trim to
the last 1000 lines after each run to keep logs bounded.
Add api/status.php — reads all scheduled jobs' stat files and returns a
{id: status} map. The scheduler page polls it every 3s and lights up the
dot on any job whose stat shows status=running, clearing it when done.
Replace single vvRunningId with vvRunningSet (Set) so multiple jobs can
show as running simultaneously. vvSetDot/vvClearDot handle per-job dots
and the header dot for the active job. Remove stale-count detection from
vvFetchRight — status poll is now the single source of truth.
Create varaverk.plg on flash (/boot/config/plugins/varaverk/varaverk.plg).
On boot, rebuild_cron copies it to /var/log/plugins/ so update_cron natively
picks up varaverk.cron and merges it into /etc/cron.d/root.
With the .plg in place the dev-mode direct-inject fallback in vv_cron_rebuild()
is no longer needed and has been removed.
dcron uses the filename in /etc/cron.d/ as the username, so a file named
'varaverk' ran jobs as a non-existent user and was silently ignored.
Switch to writing /boot/config/plugins/varaverk/varaverk.cron and calling
update_cron (which merges all plugin .cron files into /etc/cron.d/root).
In dev mode (no varaverk.plg registered), fall back to injecting our entries
directly into the live root crontab via crontab -c /etc/cron.d -.
run_job.sh: new wrapper called by scheduler cron for every job.
Writes /var/log/varaverk/<id>.json (status/start/end/exit/pid)
and /var/log/varaverk/<id>.log (latest run output, overwritten).
Maps exit 0→ok, 1→warn, 2+→error so watchdog "took action" runs
show warn not error.
scheduler: cron now calls bash run_job.sh instead of inline bash -c.
Added vv_job_stat_path(). LOG_DIR moved to config.php (shared).
monitor: vv_scripts_status() now reads /var/log/varaverk/*.json and
*/*.json — no User Scripts tmpScripts dependency at all.
Stale running detection via /proc/<pid> check.
Returns error_count in addition to running/ok/warn counts.
pages/monitor.php: added error pill (red ✗), error icon/color in
list, duration shown next to age for each script entry.
Layout:
- Switch from three flex rows to single CSS grid (repeat(8,1fr)) — eliminates
gap-count discrepancy between rows; span 1/2/4/8 cards are now pixel-identical
across all rows regardless of how many cards share the row
New cards:
- Scripts card: last-run status (ok/warn/running/unknown), clickable filter pills,
7-row scroll, flex:1 matching Power/Parity
- Streams card: live per-second progress counters, color-coded play buttons
(blue=live, orange=transcoding, green=direct, yellow=paused), server badges
with counts, left-fill column layout (3 per col)
- Transcode card: NVMe indicator, active session count + scrollable list,
session rows with server icon + title + type + method
Dynamic thresholds:
- vv_disk_thresholds() reads /boot/config/plugins/dynamix/dynamix.cfg
- Disk utilization bars: green/orange/red based on warning/critical settings
- Temperature colors: hot/max for HDD, hotssd/maxssd for SSD/NVMe
- Thresholds update every poll cycle; changing Unraid settings takes effect automatically
Other:
- SSD path detection uses findmnt FSTYPE to exclude tmpfs/ramfs (fixes RAM
being reported as SSD transcode target)
- varaverk.css h3: add white-space:normal + overflow:hidden to neutralise
any Unraid global h3 styles that could force card width