# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Working principles 1. Don't assume. Don't hide confusion. Surface tradeoffs. 2. Minimum code that solves the problem. Nothing speculative. 3. Touch only what you must. Clean up only your own mess. 4. Define success criteria. Loop until verified. ## Commands ```bash # Run tests pytest -q # all tests pytest tests/test_threshold.py # single file pytest -k test_name # single test # Lint and type check tox -e lint # flake8 over hbd/ and tests/ tox -e mypy # mypy over hbd/ # Install for development pip install -e ".[all,dev]" # Run server python -m hbd.server.cli serve -c .hb.yaml -f -v # Generate a password hash hbd passwd ``` Tests live in `tests/` (pytest, imported as a package). A second directory `test/` contains only TLS fixtures (`.pem` files), not test code. Line length: 111 characters (`black`, `flake8`, both configured). ## Architecture The system has two components: `hbc` (client) and `hbd` (server), both in the `hbd` Python package. ``` hbd/ common/ # proto.py (encode/decode), utils.py client/ # hbc: plugins/, main.py, config.py, plugin.py server/ # hbd: all server modules ``` ### Server module map | Module | Role | |---|---| | `cli.py` | Argument parsing, entry point, daemon startup | | `main.py` | Asyncio runtime: starts UDP, HTTP, WebSocket; pickle save/load | | `hbdclass.py` | `Host` and `Connection` domain objects; DNS queue | | `udp.py` | UDP datagram listener; processes `HTB` and `PLG` messages; sets/resets overdue timers | | `http.py` | aiohttp web server; all REST API routes (`/api/0/`) and page routes | | `ws.py` | WebSocket broadcast to connected dashboard clients | | `notify.py` | Notification dispatch (Pushover, email, Mattermost, Matrix, Signal, SMS); `eventlog()` is the single choke-point for all alert events | | `threshold.py` | Threshold evaluation against plugin metrics; state transitions (OK/WARNING/CRITICAL/UNKNOWN) | | `monitor.py` | Timer cleanup on shutdown (reachability is event-driven via timers in `udp.py`, not polled) | | `data.py` | Shared in-memory message ring buffer | | `journal.py` | JSONL message journal with size-based rotation | | `users.py` | Session management, password hashing (PBKDF2), role checks | | `config.py` | Config loading and defaults | | `configio.py` | Config file read/write via `ruamel.yaml` (preserves comments) | | `settings.py` | Settings sections for the web UI settings page | | `dns.py` | `nsupdate` integration for dynamic DNS | | `oauth.py` | OAuth2 login (Gitea) | ### Key data flows **Heartbeat received:** `udp.py` decodes the `HTB` datagram → updates `Connection` state in `hbdclass.py` → resets overdue asyncio timer → broadcasts via `ws.py` → `notify.py` fires connectivity alerts on state change. **Plugin data received:** `udp.py` decodes `PLG` datagram → stores on `Host` → `threshold.py` evaluates against configured thresholds → `notify.py` fires threshold alerts on state transitions. **State persistence:** `Host.hosts` dict + `data.msgs` ring + active sessions are pickled every 5 minutes and on clean shutdown. Asyncio timers are stripped before pickling (`Connection.__getstate__`). **Config reload:** SIGHUP → `configio.py` re-reads YAML → live-updates hosts, thresholds, users, notification channels. Port/cert/pickle/journal changes require a full restart. ### Client plugin system Plugins in `hbd/client/plugins/` subclass `InfoPlugin` (collected once, on demand) or `MonitorPlugin` (periodic). `initialize()` returns `False` to self-disable. Data is sent as `PLG` UDP messages. `hbc_mini.py` (scripts/) and `hbc_mini.c` (scripts/c/) are standalone single-file clients with no external dependencies. ### Protocol All UDP messages: `!: `. Encoding in `hbd/common/proto.py`. Lists/dicts encoded as JSON with `@` prefix; booleans as `1`/`0`. ### Web UI Jinja2 templates in `hbd/server/templates/`. Static assets in `hbd/server/static/`. Live pages (`/live`, `/plugins`) use WebSocket connections for real-time push. ### CI Gitea Actions workflow at `.gitea/workflows/release.yml`.