Changelog
All notable changes to bewitch are documented here. See the full CHANGELOG.md on GitHub.
0.9.1 #
2026-10-09
Fixed #
- Go 1.26.9 — fixes standard-library vulnerabilities in
net/http,net/textprotoandcrypto/tlsthat were published after 0.9.0 was built - Release builds verify the Go toolchain's checksum — the download check had been silently skipped. Checksums are now pinned in the build, and the build fails if they don't match
0.9.0 #
2026-10-09
Added #
- A sandboxed NVMe SMART helper (
bewitch-smart.timer) — recent kernels needCAP_SYS_ADMINfor the NVMe health log; the helper holds it so the daemon doesn't. Enabled automatically [custom_source.tls]for self-signed HTTPS services (certificate fingerprint pin, CA file, or skip-verify)- Proxmox VE support — a "Running on Proxmox VE" docs page, an example Proxmox API source file (guests, LVM-thin usage, quorum), and
/etc/pveexcluded from disks by default - ZFS support — datasets (including a ZFS root) are listed as disks with space and I/O, and SMART is read from each pool's disks. They were previously missing entirely
Changed #
- Go 1.26.8 (fixes standard-library vulnerabilities), DuckDB 1.5.6, dependency updates, and CI actions moved off the deprecated Node 20
- Docs site:
/docs/now shows the latest stable release, development docs live at/docs/dev/, and each release has a frozen copy at/docs/v<version>/ - Tarball installer: systemd units now point at
/usr/local/bin, where it installs the binaries
Fixed #
- Compaction no longer breaks restarts — compaction dropped the database's schema-version record, so the next start replayed migrations and refused to start ("database is dirty"). Migrations are now safe to re-run, and a database already in that state repairs itself on upgrade
- Writes made during compaction are no longer lost — rule changes, alert acknowledgements, preferences and fired or resolved alerts recorded while compaction was copying went to the database file being replaced. They now wait for the swap. Scheduled and manual compactions also no longer drop the
all_*archive views - Archiving no longer stalls after upgrades — Parquet files written before a schema change made every later archive run fail (silently, for months on affected hosts). Columns now match by name across all archive reads, merges, views, snapshots and unarchive
- Power monitoring works under the packaged service — it previously recorded nothing, because RAPL powercap counters are root-only since kernel 5.10. It now reads them through perf events using
CAP_PERFMON - SMART works on Ubuntu 22.04 and other older-systemd hosts — the service's
ProtectClockimplied a device allowlist that blocked every disk - Disk I/O on LVM, LUKS and
/dev/disk/by-*mounts no longer always reads 0 (#3) - NVMe SMART no longer shows a fake "healthy" all-zero reading when the health log can't be read, and neither do USB flash drives without SMART (#3)
- History charts on non-UTC hosts — memory, disk, network, temperature, power, GPU and process windows were shifted by the host's UTC offset (on UTC+1, the last hour of memory was empty)
- Process history ranks by total CPU per process name — one-off bursts used to outrank steady processes, and processes sharing a name produced duplicate points
- Email alerts with
use_mail_cmdwork under the packaged service — they're delivered to the local MTA over SMTP on127.0.0.1:25, becauseNoNewPrivilegesblocks Postfix's setgidpostdrop - Notifier commands no longer leak child processes or hang after their timeout
- No more phantom
/var/lib/bewitchand/var/tmpdisks from the service's sandbox mounts - Mounts that aren't block devices (e.g. Proxmox's
/etc/pveon/dev/fuse) are no longer probed for SMART (#3) - ZFS ARC counts as cache, not used memory — the kernel leaves it out of available memory, so ZFS hosts showed most of RAM as used
0.8.0 #
2026-06-11
Added #
- Custom HTTP data sources — a new "Services" tab that polls local services (Pi-hole, Home Assistant, Docker, etc.) and surfaces chosen numeric metrics and status badges, with history charts and Prometheus export
- Per-process disk I/O (read/write bytes-per-second) and per-process network I/O via eBPF (TCP rx/tx bytes-per-second, toggleable via config)
- Tool-free AMD GPU backend reading
amdgpusysfs directly (no external tool required) - ECC memory alerting with ECC presence detection
cpu.stealalert metric — per-core steal time is now persisted and alertable- Notification send-failure count in daemon self-metrics
Changed #
- Redesigned the process tab as a bounded, scrolling table over an always-visible chart, with coloured process states and pin/lightweight row markers
- Fired-alert multi-select clear (
DELETE /api/alerts/{id}); the alerts footer now shows only the focused panel's shortcuts; clear rebound toc(xstays the screenshot key) - Process pin patterns now match against the full cmdline, not just
comm - Chart-range help pinned to a fixed footer for CPU/Memory/Disk views
- Security hardening of the local API surface, packaging, and CI
- Client config falls back to defaults silently and supports a per-user config file
- Floored the scheduler tick to avoid runaway wakeups on coprime collector intervals
- Cached the runtime-pins preference read off the collection path
Fixed #
- Services chart no longer blanks on metric (re)select; long Services metric names no longer wrap the list
- Client lockout caused by the config/socket-dir tightening
0.7.0 #
2026-06-07
Added #
- Prometheus
/metricsendpoint — exposes hardware/ECC/power/SMART/GPU metrics in OpenMetrics format for scraping into an existing Prometheus/Grafana stack (honours bearer auth on TCP) - Shoutrrr notifications — Discord, Telegram, ntfy, Slack, Gotify, webhook and more from a single
shoutrrr_urlsconfig list - SMART history & alerting — SMART data is now persisted to a
smart_metricstable and alertable viasmart.reallocated,smart.pending,smart.uncorrectable,smart.percent_used(NVMe wear) andsmart.unhealthy, with a "Disk health (SMART)" category in the alert form - Daemon self-metrics — write-queue depth, dropped batches, process-info cache size, heap/RSS, goroutines and per-collector backoff state on both
GET /api/statsand/metrics(bewitch_self_*);bewitch statsgains a "Daemon health" section - Stateful alert lifecycle — alerts fire on the rising edge, suppress while breaching, and send a recovery/all-clear notification when they resolve, plus a dead-man's-switch alert that fires when metric collection stalls
- Per-rule threshold aggregate (avg/max/min) so a rule can catch a transient spike or a sustained floor, not just the average
- New collectors: system load average (1/5/15 min), per-NIC dropped packets (rx/tx), and filesystem inode usage
- "Daemon unreachable" indicator in the TUI status bar
Changed #
- Hardened the TCP API — multi-statement SQL is rejected, a plaintext (non-TLS) listener with no auth token is now a fatal startup error, request bodies are capped, and slow-loris timeouts are set
cpu.aggregatealerts now use true utilization (100 - idle, including steal) rather than just user+system of core 0- The alert form only offers hardware categories (SMART/GPU/temperature) the host actually reports, so unfireable rules can't be created
- Per-view keyboard shortcuts render in a fixed footer that stays visible as content scrolls
- A missing config file is no longer fatal — the daemon starts with defaults
Fixed #
- The four process/threshold/predictive/variance alert rules that advertised behaviour the engine didn't implement (sustained
process_down, target force-enrichment, honest threshold wording, predictive already-breached firing) now work as described - RAPL power counters no longer vanish on counter wrap, and duplicate power zones discovered via flat powercap symlinks are deduped
- The alert form's threshold hint is now metric-aware (previously showed a stale CPU label for SMART rules)
- The variance rule is guarded to memory-only metrics instead of silently running under another label
- Database compaction is now reader- and restart-safe
- The query API no longer swallows row scan/iteration errors
- Rune-safe truncation in TUI and REPL table rendering
- TUI viewport content is rendered once per message instead of twice
0.6.0 #
2026-06-04
Added #
- Active alerts are now surfaced in the TUI status bar
- Alert rules can be edited in place —
ein the alerts view, orPUT /api/alert-rules/{id}— instead of delete-and-recreate - Alerts view now shows a full rule detail pane, delete confirmation, and surfaced create/update errors
Changed #
- DuckDB memory is capped via a configurable
[daemon] db_memory_limit(default512MB) with spill-to-disk, instead of DuckDB's ~80%-of-RAM default that could exhaust low-memory hosts - Parquet archival now runs incrementally (per-day, resumable) and no longer pauses the daemon for the whole run
- Alert rule names must now be unique, enforced by a database index; any pre-existing duplicates are auto-renamed on upgrade
Fixed #
- Alert rules created via the API or TUI never fired — the type-specific config row was linked with
rule_id=0(the DuckDB driver has noLastInsertId()), so the engine's join never matched. Rules created before this fix must be recreated. - Deleting an alert rule now also clears its fired alerts, instead of leaving orphaned, undismissable "active" alerts
bewitchdmemory leak that could OOM-kill small/low-RAM hosts — the process-info cache is now bounded by an always-on eviction sweep regardless of retention settings- Process
rss_byteswas stored 1024× too large (≈1 TB reported for a ~1 GB process); now correct for new samples - Enabling Parquet archival no longer freezes the daemon on large databases
0.5.2 #
2026-05-26
Fixed #
- Unbounded
process_infocache growth on hosts with high process churn - Background goroutines (scheduled jobs, checkpoint loop) now stop cleanly on daemon shutdown instead of running against a closing DB
- Notification sends bounded by an 8-slot semaphore
- Intel GPU reader accumulation buffer capped at 1MB
0.5.1 #
2026-04-28
Added #
bewitch statssubcommand for at-a-glance system footprint- Auto-generated API reference docs page
- Uninstall script (
uninstall.sh) supporting both APT and tarball installs, withKEEP_DATA=1to preserve the database - Documented
bkeybinding (bits/bytes toggle) on the network view
Changed #
- Installer auto-starts
bewitchdafter install — quick start reduced from 4 steps to 2 - Internal refactors to consolidate duplicated plumbing across collectors, API handlers, REPL, and TUI client
0.5.0 #
2026-04-02
Added #
- Screen capture to PNG via
xkey with configurable[tui.capture]settings capture-viewssubcommand for batch screenshot capture- Dev docs channel with automatic publishing for pre-release versions
Changed #
- Restart bewitchd automatically on package upgrade via
dh_installsystemd
Fixed #
- DuckDB WAL replay crash by checkpointing after migrations
- History chart flicker on tab switch via per-view chart cache
- Empty history charts when switching hardware sub-tabs
- Docs version dropdown not showing latest stable release
0.4.0 #
2026-03-30
Added #
- GPU collector with Intel iGPU (
intel_gpu_top) and NVIDIA (nvidia-smi) support - Actionable hints in GPU view when monitoring tools are missing
- Per-collector API cache push for immediate data freshness
- Load live data and hardware history immediately on startup
- Show enriched processes above the fold in process view
- Copy-to-clipboard button on docs code blocks
- E2E installation testing workflow
Fixed #
- Stale history chart shown on view switch cache miss
- Maintainer email in Debian packaging
- Dev version ordering (full timestamp instead of git SHA)
Changed #
- Enhanced installer with optional dependency prompts, dev channel, and version stamping
0.3.1 #
2026-03-16
Fixed #
- Memory history chart empty on systems without swap
- Disk NULL handling in history scan
- Removed unnecessary
-configflag from docs site command examples
0.3.0 #
2026-03-14
Changed #
- Renamed Go module from
github.com/rosstogithub.com/duggan - Deduplicated schema definitions using runtime introspection
- Removed webhook, ntfy, and gotify notifiers in favour of simpler notification channels
Fixed #
- Sequence references breaking after compaction
Added #
- Local
mailcommand support for email notifications (postfix/sendmail, no SMTP config needed) - Version pulled from
VERSIONfile for install script and docs
0.2.0 #
2026-03-14
Added #
- Braille charts with unified chart rendering across all views
- Hardware tab consolidating temperature, power, and ECC sub-sections
- Versioned docs for tagged releases
- Dev build pipeline for bleeding-edge apt channel
Fixed #
- Nil map panic in
updateNetSparklines - Archive error when metric tables have no matching rows
- Various Cloudflare Pages Functions deployment issues
0.1.2 #
2026-03-13
Added #
- Initial public release
- Metric collectors: CPU, memory, disk, network, ECC, temperature, power, process
- DuckDB storage with schema migrations
- TUI with dashboard, per-metric views, and historical charts
- Alert engine with threshold, predictive, and variance rules
- SQL REPL with dot-commands and data export
- Remote access with TLS (TOFU) and bearer token auth
- Parquet archival and data pruning
- Debian packaging with systemd service
- APT repository with signed metadata