The hamlab-demo site, its Widgets-tab button, the demo_url config key and the make publish
target that fed it are all gone, along with the public read-only token it needed. The
example stays in examples/external-demo as something to read. The installer one-liner
already comes from Gitea releases.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
REQUIRE_SIGNIN_VIEW is off and mitchell/hamlab is public, so anyone can clone it or pull
a release. The other five repos are individually private and 404 to anonymous. Gitea
resolves releases/download/latest/<asset>, so the install one-liner and HAMLAB_URL point
at the newest release and never need changing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A new selfupdate package asks one URL what the newest build is — a Gitea/Forgejo repo
API base, or any directory holding VERSION, SHA256SUMS and hamlab-linux-<arch>, which is
what make release already writes and what install.sh already downloads. The binary is
checked against SHA256SUMS before it goes near the running one, and a token is sent when
the source is behind a login, so a private Gitea serves its own fleet without opening the
instance to everyone. Version ordering is install.sh's vnum rule, so the daemon and the
installer never disagree about which build is newer.
Settings gains an Updates card: installed, published, when it last looked, the source,
release notes, Check for updates, and Install. The rail badges Settings when a newer
build is out. Nothing installs unasked — it restarts the daemon and drops terminals.
scripts/gitea-release.sh (make gitea-release) publishes dist/ as a Gitea release.
Deliberate, and not part of deploy: deploy pushes to the machines this hub owns,
publishing offers the build to every install anywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The timeout killed sudo and left zfs holding the pipe, so the refresh of tank sat on
immich's diff indefinitely. The process group is killed now, and a slow dataset is walked
by mtime instead.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A scan is saved beside the config and read back after a restart. The next scan starts
from it: on a pool with snapshots zfs diff names what changed and only those folders are
read; elsewhere a folder whose mtime is unchanged keeps its list and only its kept files
are stat'ed again. A cancelled scan keeps what it walked and Resume reads the rest.
Forget drops the saved result. The treemap is every file a tile, grouped by folder, with
no nested boxes: the folder chains of a Linux system made a staircase of empty headers.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A pool's member disks are listed under it, not offered apart; the picker shows the
layout, members, size and scan state.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The process table carries each logical CPU's core id from sysfs topology; a row with
no reading still has the temperature cells, so the % column is one column.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pick a disk, not a partition; the scan walks every filesystem it backs, as root when
the host allows, in a helper process that streams the tree back. A tree of folders
largest-first over a treemap of the selected folder, nested to the file and coloured by
kind, plus the thousand largest files. The rail no longer offers the hub-only pages
while a remote machine is being looked at.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
On a phone the list gives way to the pane and Back returns; on a desktop the list stays
beside it and there was no way to put the pane away.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The login is a user name and a password. The old single password becomes the account
named after the OS user on first boot, along with its sessions and the machine-wide look.
Settings gains Users (add, remove, reset a password — your own password confirms) and
Sessions (device, IP, last seen; revoke one or sign out everywhere else). Theme, accents
and the dashboard layout follow the account; the refresh rate, graph history and alerts
stay the machine's. Pairing a machine takes a user on it. Log lines name the actor.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An Apple SSD presents three namespaces and the kernel lists each as a whole disk, so the
dashboard was showing one drive as three. The Disks page has always folded them; now the
dashboard, the Top tab and the disk.* sensors do too.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A link to a hub page no longer reloads onto the last machine; a link from a hub-only page to
a machine's page arrives at that page; a page being left no longer asks about the next page's
selection; the hub holds its machines to the rate it is itself running.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The name a machine was added under stays its identity — the URL, its accent, what the hub's
API calls it — and is what the Machines page shows as 'Added as'. The hostname is read live
rather than at start-up, so renaming a machine reaches the console without a restart.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The process table's columns fit the box they are in, the rate control saves, curves are
timed on the viewer's clock and keep to the stride, the power icon is drawn, and a young
history draws in from the right instead of being stretched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Boxes with their name in the border, dot curves that climb green to red, per-core meters and
temperatures, memory and filesystems, per-interface traffic and the process table. Drawn from
the sensor stream and /api/procs, so it works on every machine the console can see.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Each machine keeps 300 points per curve whatever the window, so memory doesn't follow it;
a wider window means wider points, each the average of its bucket rather than one instant
out of it. The hub passes the setting to every machine it manages.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A named volume is deleted by typing its name, one at a time; the API wants it named
twice; nothing is forced. Prune touches anonymous volumes only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A new stack is a folder in a home (where stacks are already kept: Dockhand's group here,
~/stacks elsewhere) with compose.yaml and an optional root-only .env, validated by compose
before it is kept and deployed the way its neighbours were — inside dockhand, or to a node
over tcp from the hub. New container is the same dialog on a form that writes the compose.
Homes are scanned, so undeployed stacks stay listed. Delete moves a stack's files to
.hamlab-trash; nothing is forced, and volumes and data are never touched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every icon is rendered from web/scripts/logo-source.png by scripts/icons.mjs: trimmed to
the artwork's own edge, transparent corners for the browser icons, a dark ground from the
artwork's palette for iOS (which paints transparency black) and for Android's maskable
icon, where the whole artwork sits inside the 80% safe circle. The login screen no longer
crops the logo to a circle or repeats the wordmark. Service worker cache bumped so
installed apps fetch the new files.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Stacks: deploy with every compose file (labels from inspect, not comma-joined ps);
refuse a stale overwrite; empty list without Docker. Alerts: firing state survives a
restart without re-announcing; vanished alerts are recorded as cleared with the reason;
rule values validated; 200 rules. Docker: 404 for a removed container's logs. Skins: four
palettes lifted to readable contrast. Phone: bigger toggles and swatches. Installer:
deploy republishes; an older published build is never installed silently.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Stacks are found from container labels; the file is resolved on the host or through an
orchestrator's mounts, and compose runs where the file makes sense (inside Dockhand here),
so a redeploy is identical to how the stack was deployed. Save validates with compose and
keeps a .hamlab-bak; Deploy / Update / Restart / Stop run as followed tasks.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Alerts: rules over sensors, watched fleet-wide from the hub; ntfy and webhook channels;
firing count on the rail. Docker: containers by stack with live use, start/stop/restart,
following logs, inspect, images/volumes/networks. Skins: HUD, Nord, Gruvbox, Catppuccin
(+Latte), Dracula, Tokyo Night, Solarized (+Light). Accents: per-machine colour.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>