URL: https://mkdocs.justinsforge.com/memory/general/reference_forge_monitor/
forge-monitor, unified fleet monitor¶
Procedural (zero-LLM) monitor that revived the three logs dead since the 2026-04-28 Phoenix refactor. Built 2026-06-09 per forge-monitor-build-brief-2026-06-09; plan at forge-monitor-2026-06-09.
Pieces¶
| Piece | Path |
|---|---|
| Script | scripts/forge_monitor.py (stdlib-only python3, --dry-run, --no-log) |
| Units | scripts/forge-monitor.{service,timer}.unit, installed at /etc/systemd/system/forge-monitor.{service,timer} (system level, oneshot + OnUnitActiveSec=5min, OnFailure=forge-unit-failure-notify@%n) |
| Policy data | data/monitor_expected_state.json (tracked in git): expected CT states, disk/auth thresholds, business URLs, Console mounts, Finn data mounts (mounts_finn: /mnt/storage, /mnt/pve/workspace; added 2026-07-01 after /mnt/storage silently hit 97%) |
| Alert state | data/forge-monitor-state.json (gitignored runtime state) |
| Output | logs/monitor-security.log, logs/monitor-infra.log, logs/monitor-business.log |
Log-line contract (consumers parse this; do not change)¶
Consumers: scripts/forge_hook_session_start_since_last.sh (boot briefing) and scripts/forge_fleet_status.sh (/fleet-status, mtime freshness: <15 min healthy).
- healthy:
[YYYY-MM-DD HH:MM:SS] CHECK: <domain> OK (<n> checks) - failing:
[ts] ALERT: <domain>: <detail>(CRITICAL:once escalated) - first healthy cycle after failure:
[ts] RESOLVED: <domain>: all checks healthy again - CHECK/RESOLVED lines must never contain ALERT/CRITICAL/ERROR/FAIL.
Checks (29 total as of 2026-07-10)¶
- infra (14): Console failed units; Finn
pct listvs expected map (CT 110 minecraft never alerts in either state, see reference_minecraft_server); root disk on Console + Finn + 7 LXCs (warn >=85%); Finn data mounts;/mnt/workspacemount stat. - security (5): sshd auth-failure counts from journal on Console + Finn (15-min window, warn >10); Finn failed units; cloudflared process on Console + Finn.
- business (7): HTTPS reachability (<500 within 10s counts as up, CF Access redirects fine) for usage, tasks, hyperframes, mkdocs, dashboard, erpnext, fitness (finances removed 2026-07-10, app retired).
- wellness (3): data-freshness tripwires for Eight Sleep, Garmin, Hevy.
commit_hygiene removed 2026-07-10: auto-memory and auto-dream keep the repo perpetually dirty, so the check sat red for weeks and paged noise. Justin explicitly does not want commit-hygiene pages; do not re-add without asking him.
One combined SSH round trip to Finn covers pct/disk/journal/units/cloudflared. Sequential subprocess calls only (no threads near subprocess). Read-only toward Finn and LXCs.
Alerting¶
Canonical dedup + all-clear state machine (feedback_alert_dedup_allclear_pattern.md), per check key: first fail pages warning; sustained >30 min escalates critical; same level re-pages only after 60 min; recovery after any page sends info RECOVERED. Pages via scripts/forge_notify.sh. Unit crash itself pages via forge-unit-failure-notify@.
Human paging layer (2026-07-10): humanize(key, detail, phase) in forge_monitor.py translates each check key into a plain-English Telegram page (what broke, why it matters, "Tap Spawn fixer"), with the terse machine detail kept as a trailing Details: line. Domain LOG lines are untouched (log-line contract above). container_names in monitor_expected_state.json maps CT ids to names so pages say "CT 113 (forge-openwebui)", keep it in sync when adding containers. New check keys without a template fall back to Fleet check failing: <key>, add a branch in humanize() when adding checks.
Ops¶
systemctl list-timers forge-monitor.timer
systemctl status forge-monitor.service
python3 scripts/forge_monitor.py --dry-run --no-log # side-effect-free run
Tune thresholds and URL list in data/monitor_expected_state.json, no code edit needed. Mount repair stays with forge_monitor_mount_watchdog.sh; forge-monitor observes and pages only.
[Claude Code, forge-monitor build session 2026-06-09]