Repository navigation
Releases: jagbhandal/jaghelm
Release list
JagHelm 3.0.0
2026-10-20 · v3.0.0 · ghcr.io/jagbhandal/jaghelm:3.0.0
Push alerts and the new /api/status now come from one status model, so a Prometheus restart no longer floods the phone; JagHelm asks Prometheus 14 queries per refresh instead of 90, runs on Node 26, and has the redesign's building blocks in place, not yet on screen.
Breaking changes
- Running the server from a checkout (
node server/index.jsornpm start) instead of the image now needs Node 26, the version in.nvmrc. Under Node 22 the Proxmox integration fails every request withfetch failed. The image ships its own Node, so a Docker deployment needs nothing.
Added
/api/servicesgives each container's network traffic as a rate:docker.rxBytesPerSecanddocker.txBytesPerSec, bytes per second over the last 5 minutes.docker.rxMBanddocker.txMBstay as they were, the cumulative total in MiB, until the old endpoints are retired. A rate reads high for up to 5 minutes after a container is recreated./api/integrationsgives each integration a_status:state(ok,backing_offorauth_failed),since(when that state began),failures(failed attempts in a row) andnextAttemptAt(when it will be tried again; null when it is fetched every refresh, or waits for a settings change). Times are milliseconds since the epoch. The dashboard does not read it yet.services.yamlcan map a container to a different Uptime Kuma monitor on each machine, withmonitor_per_node:under its entry (keyed by the node keys undernodes:), andmonitor: falsegives a container no monitor at all.monitor_per_nodewins overmonitoron its node. JagHelm logs one warning for amonitor_per_nodekey that is no node.- DEMO_SCENARIO=healthy serves the demo board with nothing down. The default, incident, has one service down and a failed backup job.
JAGHELM_ICON_CACHE_MAX_MBsets how much the icon cache (icon-cache/in the data dir) keeps, in MB. It defaults to 50. Past it the least recently used icon is deleted, and it is fetched again the next time it is shown.JAGHELM_HOSTsets the address the server listens on. It defaults to0.0.0.0, every IPv4 interface, as before, so nothing changes unless you set it. Withnetwork_mode: host,127.0.0.1keeps JagHelm to its own host, for a reverse proxy there; in a bridge-network container keep the default (seeenv.example). An address the server can't listen on stops it with acannot listenerror.- The redesign's controls are built, in the signed-off look, in light and dark: buttons, icon buttons, text fields, selects, switches, checkboxes, fields with their help and error text, segmented pickers and tabs, each usable by keyboard and screen reader. Nothing on screen uses them yet, and today's screens look as before; the stylesheet the browser downloads grows by about 0.45 KB compressed.
- The redesign's containers are built, in the signed-off look, in light and dark: panels, dialogs, a detail drawer, a confirm that names what it removes by its display name, popovers, tooltips, toasts that screen readers announce, cause-naming banners, empty states and loading placeholders. Each works by keyboard and screen reader and respects reduced motion. Nothing on screen uses them yet, and today's screens look as before; the stylesheet the browser downloads grows by about 1 KB compressed.
- The redesign's status components are built, in the signed-off look, in light and dark: status lamps with a shape for each state (a filled disc for OK, a slashed disc for a warning, a disc with a bar for critical, a hollow ring for no signal and a wrench for maintenance), status words and badges, issue rows, the subsystem strip and the attention panel. A status is always a shape and a word as well as a colour, and screen readers say it. The banners and toasts show their status with the same lamps. Nothing on screen uses them yet, and today's screens look as before; the stylesheet the browser downloads grows by about 1.2 KB compressed.
- The redesign's data components are built, in the signed-off look, in light and dark and both densities: usage meters that stay in the accent colour until a threshold and then turn amber or red, with the threshold marked on the bar; a one-line trend chart whose value and time show under the pointer or with the arrow keys; a heartbeat strip where only failures light up; rows for services and nodes whose name is never cut short before the rest; a list of an item's facts; and a table for the keyboard and screen readers, with numbers lined up on the right. Nothing on screen uses them yet, and today's screens look as before; the stylesheet the browser downloads grows by about 0.6 KB compressed.
- Backups are their own area in
/api/status, beside Jobs, once you say which jobs are backups: list them indisplay-config.jsonasbackupJobs, for example["pve:proxmox-backup"]for the Proxmox backups the PVE webhook reports. A backup whose last run failed is critical, and one that missed its schedule a warning. Their push notifications are unchanged. Jobs not in the list stay jobs, as before. - An Arcane agent that goes offline now shows in
/api/statusas a warning under Integrations, and clears when it is back. Its push notification is unchanged. GET /api/statusserves the server's view of everything JagHelm watches: one overall sentence, the ranked list of issues, a summary per area (Services, Nodes, Power, Jobs, Backups, Integrations), every service, node, UPS, job and integration with its state and the reason for it, and whether Prometheus, Uptime Kuma and the NUT exporter are answering. It sends an ETag and answers 304 while nothing has changed. It sits beside/api/services,/api/upsand/api/cron/status, which keep their shape and meaning, so installed Android apps keep working.- When Prometheus, Uptime Kuma or the NUT exporter stops answering for two refreshes in a row (about a minute), one "Monitoring source down" push says so, and one "Monitoring source recovered" push follows when it answers again. Nothing it watches sends a push while it is down. It follows the Hosts, Services or UPS notification toggle respectively.
- The redesign's chart colours are defined, as signed off: six colours for the lines and bars of different nodes or disks (azure, rose, lime, plum, orange and teal), and a scale of blues for amounts, in dark and light. They stay apart for people with red-green colour blindness, never look like a status colour, and don't change with the accent. Nothing on screen uses them yet; the stylesheet the browser downloads grows by about 0.2 KB compressed.
PATCH /api/integrations/<key>with{ "enabled": true }or{ "enabled": false }enables or disables an integration and changes nothing else in itsservices.yamlentry. The Enable and Disable buttons in Settings use it.
Changed
- The server image is smaller: 235 MB unpacked instead of 270 MB, and 69 MB to pull instead of 75 MB. It now runs on plain Alpine with only the Node binary and its licence notices taken from the Node image, so npm, npx, yarn and corepack are no longer in it (the server and its health check only ever run
node), and the image build fails if one comes back. Dropping npm also drops the 13 fixable high and critical findings in the packages it bundles, so they leave Arcane's weekly vulnerability digest for JagHelm's image too; the 2 left are in Alpine'slibssl3andlibcrypto3(there before too), which Node doesn't use, since it carries its own OpenSSL. The Arcane dry run (scripts/arcane-poll-once.js) is left out of the image too; it runs from a checkout, asdocs/arcane/SETUP.mddescribes. - The server no longer writes two log lines on every refresh cycle, which were most of what it logged. "background cycle complete" and "Loaded monitors from Kuma" are now debug lines (set
LOG_LEVEL=debugto see them; seeenv.example). A cycle is still logged at info when it takes 5 seconds or more, or when the set of refreshes that failed in it changes (Gitea or an integration starting or stopping failing, for example), so a new failure and its recovery each get one line; a refresh that keeps failing still logs its own error every cycle. Loading Kuma's monitors is logged at info when the number of monitors or where they are read from changes, and on the first load after a failed one. Kuma answering with no monitors (for example an error status from its status page) now logs one warning per outage; a Kuma that can't be reached still logs an error every cycle. Containers with no matching Kuma monitor are listed in one line per boot instead of one line each. - JagHelm now asks Prometheus 14 queries per refresh instead of 90 with six hosts, and the number no longer grows with each host added: each reading is one query for every host. A host without a
/filesystem, such as a NAS, is no longer asked for one every refresh before its largest filesystem is read. - The web dashboard no longer polls the server while nobody can see it: a hidden browser tab, the Settings page or an iframe tab pauses it, and coming back to the dashboard refreshes it at once. Each refresh now makes 4 requests instead of 7. The header health dot reads the dashboard's own
/api/servicesresult instead of fetching it a second time, so it holds its last value while polling is paused and updates on return; the first load no longer fetches everything twice. Sparkline history, cron job status and Gitea activity refresh in turn, each every third refresh (every 90 seconds at the default 30-second interval), and the cron and Gitea panels show the "updated … ago" stale note after 3 minutes without an update instead of 1 minute. Weather refreshes every 10 minutes instead of on every refresh. /api/historynow sends anETagand answers a matchingIf-None-Matchwith304 Not Modified, and/api/cron/statussendsCache-Control: private, max-age=60.- An integration that fails is no longer fet...
JagHelm Android 1.3.0
2026-10-20 · mobile-v1.3.0
The UPS cell no longer shows MAINS while on battery, the app stops refreshing in the background, and Active issues rows open their detail screen.
Changed
- The app stops refreshing while it is in the background and refreshes at once when you come back to it, so it no longer uses data and battery while closed and no longer opens on data up to one refresh old.
- Refreshes after the first load ask the server only for what changed: an unchanged service list or UPS reading comes back as a short
304 Not Modifiedinstead of the full data. Tapping the status bar still fetches everything. - The countdown in the status bar now matches when the next refresh really happens, including after a slow refresh or a change to the refresh interval.
- The node detail screen shows both TEMP and DISK for a node that reports both, such as the Pi, so you can see its temperature and how full its disk is.
- Tapping a row under Active issues on the Overview opens its detail screen: a down or unknown service opens that service, and a UPS or cron row opens the incident with its cause. Back returns to the Overview. A service's row no longer opens the service's web page directly; use Open on the service screen.
- TalkBack reads an unknown service's row as "unknown" instead of spelling out "UNKN".
Fixed
- The UPS cell no longer shows MAINS while the UPS is on battery. It reads the UPS status the way push and the web dashboard do: on battery and low battery show ON BATTERY with an alert, and an unknown status shows NO SIGNAL instead of a battery alarm.
- A node card shows DISK instead of TEMP once its disk is 90 % full or more, so a nearly full disk on a node that reports its temperature is no longer hidden.
Asset: jaghelm-android-1.3.0.apk · SHA-256 7c179a224e91c18d09f5476062d5c7f61f410f14921aae567770dd29555f0cec
Download the APK on your Android device and open it to install. Updates install over earlier versions and keep your settings.
JagHelm 2.3.0
2026-10-18 · v2.3.0 · ghcr.io/jagbhandal/jaghelm:2.3.0
A weekly Arcane vulnerability digest by mobile push, sent only when there is something new.
Added
- A weekly Arcane vulnerability digest by mobile push. For the environments listed in
ARCANE_VULN_DIGEST_ENVS(empty by default, which leaves it off), once a week (Sunday 14:00 UTC by default;ARCANE_VULN_DIGEST_DAYandARCANE_VULN_DIGEST_HOUR) JagHelm reads the scan results Arcane has stored and pushes only when something is new: critical or high findings with a fix in the images your containers use, known-exploited (KEV) entries, or an image scan that has newly gone stale or failed. Each digest is recorded as a run of thearcane-vuln-digestscheduled job, which goes overdue when digests stop. It needs scanning turned on in Arcane and thevulnerabilities:readgrant on JagHelm's Arcane key (a global grant in Arcane v2.16.1, so the list decides what is read); preview it withnode scripts/arcane-poll-once.js --vuln-digest. Seedocs/arcane/SETUP.md.
docker pull ghcr.io/jagbhandal/jaghelm:2.3.0
Image signed with cosign (keyless). Full changelog: v2.2.0...v2.3.0
JagHelm 2.2.0
2026-10-18 · v2.2.0 · ghcr.io/jagbhandal/jaghelm:2.2.0
Overdue detection for Arcane's image watcher, no more ghost cards from Arcane's helper containers, and the deprecated Watchtower webhook is removed.
Added
- Overdue detection for Arcane's image watcher: each check it runs on its own is recorded as a run of the
arcane-checkscheduled job per environment, which goes overdue when checks stop. The expected interval isARCANE_IMAGE_CHECK_HOURS(default 6); seedocs/arcane/SETUP.md.
Removed
POST /api/watchtower/eventand theJAGHELM_WATCHTOWER_SECRETandJAGHELM_WATCHTOWER_DISCORD_WEBHOOKsettings, deprecated in 2.1.0. Use the Arcane integration (docs/arcane/SETUP.md); the env vars can be deleted.- The Watchtower dashboard integration, which was already marked unsupported (it could not be saved, tested or polled).
Fixed
- Arcane's short-lived internal helper containers (volume, backup and scan helpers) are no longer discovered, so they no longer appear as grey "unknown" cards or turn a node's health dot yellow after they exit.
docker pull ghcr.io/jagbhandal/jaghelm:2.2.0
Image signed with cosign (keyless). Full changelog: v2.1.0...v2.2.0
JagHelm Android 1.2.0
2026-10-18 · mobile-v1.2.0
The update notification toggle is now labelled Updates.
Changed
- The Watchtower notification toggle is now labelled Updates, since it covers every update notification, including Arcane's. The setting itself is unchanged, so older app versions and the server keep working.
Asset: jaghelm-android-1.2.0.apk · SHA-256 e0c1edbe2b2365715cccaf12914679d75606519ae17ca8dc43ccf0a477ec2946
Download the APK on your Android device and open it to install. Updates install over earlier versions and keep your settings.
JagHelm 2.1.0
2026-10-17 · v2.1.0 · ghcr.io/jagbhandal/jaghelm:2.1.0
JagHelm can now read an Arcane manager and send its update, held-back, prune, agent and release notifications by mobile push.
Added
- Arcane update notifications by mobile push, covering applied and failed updates, held-back updates, Arcane agent outages and new Arcane releases, plus overdue detection for Arcane's scheduled update and prune runs. Set
ARCANE_URLandARCANE_API_KEYto enable it; seedocs/arcane/SETUP.md.
Deprecated
POST /api/watchtower/eventandJAGHELM_WATCHTOWER_SECRET/JAGHELM_WATCHTOWER_DISCORD_WEBHOOKare deprecated in favour of the Arcane integration and will be removed in 2.2.0.
Security
- Outbound requests no longer forward
X-API-KeyorX-Api-Tokenheaders when a server redirects to a different origin, matching the existing handling ofAuthorizationand cookies. An API-key integration (Immich, Overseerr, NextDNS, Sonarr, Radarr, Lidarr, Readarr, Prowlarr, Bazarr) configured with anhttp://URL that redirects tohttps://now needs thehttps://URL, since the key is dropped on any origin change.
docker pull ghcr.io/jagbhandal/jaghelm:2.1.0
Image signed with cosign (keyless). Full changelog: v2.0.0...v2.1.0
JagHelm 2.0.0
2026-10-16 · v2.0.0 · ghcr.io/jagbhandal/jaghelm:2.0.0
Watchtower update notifications, overdue detection for scheduled jobs, and token-based Nextcloud authentication.
Breaking changes
- Nextcloud authenticates with a serverinfo token. Username and password are no longer accepted. On the Nextcloud host run
occ config:app:set serverinfo token --value "$(openssl rand -hex 32)", then enter the token in the integration's API Key (NC-Token) field.
Added
- Watchtower update notifications via Discord and mobile push, including containers held back by monitor-only labels. Point Watchtower's webhook notifications at
POST /api/watchtower/eventand setJAGHELM_WATCHTOWER_SECRET(sent assecretin the body) to enable it; setJAGHELM_WATCHTOWER_DISCORD_WEBHOOKto also post to Discord. - Overdue detection for scheduled jobs: reporters can declare an expected interval, and JagHelm alerts when a job stops reporting.
- Scheduled jobs can be removed from the dashboard, together with their history.
/api/healthreports the build commit alongside the version.
Changed
- Version tags now point to the exact image built from
main; releases no longer rebuild, and published tags never move.
Fixed
- Nextcloud polling no longer triggers Nextcloud's brute-force protection.
ghcr.io/jagbhandal/jaghelm:1.4.0pointed to the 1.5.0 build; it now points to the 1.4.0 build.
Security
- The Gitea integration sends its API token in the
Authorizationheader instead of the URL, keeping it out of Gitea's request logs. - Scheduled-job report names must be plain strings, and reserved names such as
__proto__are rejected. - Dependencies updated to resolve published high-severity advisories.
docker pull ghcr.io/jagbhandal/jaghelm:2.0.0
Image signed with cosign (keyless). Full changelog: v1.5.0...v2.0.0
JagHelm Android 1.1.0
2026-10-16 · mobile-v1.1.0 · Requires JagHelm server 2.0.0 or later
A connection screen when the server can't be reached, overdue scheduled jobs on the Overview, and Watchtower notification settings.
Added
- Connection screen with retry when the server can't be reached at startup, replacing an indefinite blank screen.
- Sign-in gives up after 10 seconds with a clear message instead of waiting indefinitely.
- Overdue scheduled jobs appear on the Overview with how long since they last reported.
- Notification toggle for Watchtower update events.
Fixed
- The app reports its real version when registering for notifications.
Security
- Dependencies updated to resolve published advisories.
Asset: jaghelm-android-1.1.0.apk · SHA-256 8c90590b1e58ee0cff77103e8454de580dbdeb13f60689c48764e9c3d0e79c02
Download the APK on your Android device and open it to install. Updates install over earlier versions and keep your settings.