Changelog
All notable changes to bewitch are documented here. See the full CHANGELOG.md on GitHub.
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