Balancebot
See your array. Move your data. Never lose a byte.
An Unraid plugin that turns disk rebalancing from a scripted chore into a visual, drag-and-drop operation — a WizTree-style treemap of every array disk that doubles as a dependency-aware move planner and a safe, resumable copy → verify → delete engine.
The problem
Rebalancing an Unraid array is high-stakes and low-visibility. The existing tooling is a checkbox tree over a log window — it can't show you where your space actually is, can't express migrations that require freeing space before filling it, and asks you to trust an opaque ordering with terabytes of irreplaceable data.
The approach
Make the visualization and the planner the same surface. A canvas treemap gives immediate spatial understanding of each disk; dragging on it builds a plan; a space-dependency simulator proves the plan fits and orders it; and a layered safety system makes execution trustworthy.
The map is the planner
Every array disk is rendered as a squarified treemap — think WizTree or WinDirStat — colored by share, zoomable from disk → share → folder → file. To plan a migration, you drag a folder block from one disk onto another. The source block goes hatched, a ghost block previews where the data will land, and every disk updates its projected free space after the plan in real time.
Behind the visual is a space-dependency simulator. Complex rebalances often require interleaving — you can't move data onto disk B until you've first freed space on it by moving its data to disk C. Balancebot topologically orders the queued moves so every step fits at the moment it executes, respecting a configurable per-disk free-space floor, and flags any step that won't ("step 4 needs 800 GB on disk2 but only 320 GB will be free").
Because this operates on terabytes of irreplaceable data, safety is the spine of the design. Every operation runs copy → verify → delete: the source is deleted only after the destination is verified, so a crash can only ever leave a harmless duplicate, never lost data. On any failure the queue halts with state preserved, and runs are resumable across daemon restarts and reboots.
Features
WizTree-style treemap, per disk
A fast, canvas-rendered, zoomable map of every array disk, colored by share — see where your space went instead of reading du output.
The map is the planner
Drag a folder from one disk onto another to queue a move. Queued data is hatched, incoming data ghosted, and free space is projected live.
Dependency-aware auto-ordering
A space simulator sequences moves so each one fits when it runs — enabling interleaved migrations a flat list can't express. Manual reorder re-validates live.
Verify-before-delete engine
rsync copy → checksum verify → delete, per operation. A crash leaves a duplicate, never a loss.
Halt-and-preserve, resume anywhere
Any error stops the queue with state intact; resume picks up the remaining steps, even after a reboot.
Pre-flight safety checks
Open-file detection (with process names), share include/exclude and split-level conflicts, permissions audit, parity-activity awareness — each graded and overridable.
Dry-run reports
See exactly what every plan would move, byte for byte, before a single file changes.
Scatter / Gather shortcuts
Spread one disk across many, or consolidate a share onto one — built on the same safe engine.
Native-feeling Unraid plugin
One embedded Go+React binary, array lifecycle integration, dark/light theming, flash-backed persistence.
In action
How it's built
Single-binary architecture
A Go daemon (balancebotd) serves a REST API and the entire React SPA, embedded at compile time with go:embed. One file deploys the whole app.
Stdlib-only Go backend
No web framework — Go 1.22+ pattern-based ServeMux routing and standard-library concurrency for the parallel disk walker and scan cache. Deliberately dependency-light for a plugin trusted with root file operations.
Space-dependency solver
The planner simulates free space on every disk after each step to topologically order operations, honoring a reserve floor of max(configurable, 1% of disk) — turning “does this migration even fit?” into a validated, visualized answer.
Canvas treemap from scratch
Squarified treemap layout, devicePixelRatio-aware, with hit-testing for hover and drag, queued-state hatching overlays, and ghost-block previews. No charting library.
Crash-safe execution model
Runs are journaled atomically to flash on step transitions (never on progress ticks, to spare the flash drive). Copy → verify → delete makes every step idempotent; interrupted runs are detected and revalidated before resume.
Pluggable mover with a pure-Go fallback
An rsync-backed mover for production and a dependency-free Go mover for dev/test, selected at runtime — so the whole engine is unit-tested (halt, resume, verify-catches-corruption) on any OS without rsync.
Real plugin packaging
.plg installer + Slackware .txz, rc-style start/stop wired to Unraid's array lifecycle events, PHP wrapper page for the webGUI iframe, config and state persisted under /boot/config.
Status
Feature-complete and fully unit-tested; real-hardware validation on a live Unraid array is in progress. The engine was developed and tested against sandboxed disks with a pure-Go mover — the rsync mover, open-file detection, and permission audits exercise for the first time on real hardware.