Realmwatch
~ a high-fantasy map of every device in your homelab ~
Realmwatch is what Zabbix would look like if it grew up in a wizard's tower.
It speaks fluent collectd, Netdata, SNMP, nftables, Home Assistant, Docker,
KVM, LLDP, and Tailscale — but where most monitors render that into spark
lines, realmwatch paints it onto a treasure map. A failing UPS is a Ward
losing its sigil. A roaming phone is a familiar slipping between towers.
A firewall counter is a dragon at the gate. Underneath the theming sits a
serious operational toolkit: live SVG topology, server-sent events,
role-based auto-discovery, trigger-dependency alert suppression, event
acknowledgement, declarative onboarding actions, an AI oracle that speaks,
an in-tree MCP server, an RPG game layer where every event grants XP,
and a unified realm CLI with 40+ verbs that exposes every capability through one
ergonomic, git-style command.
a stub. the real canvas holds 130 nodes and twelve VLANs.
Beyond the map
The monitor learned to play, to speak protocol, and to fill terminal blocks.
The Game Layer
Absorbed from os.realm.watch this May. Five plugins on a sidecar
SQLite at ~/.realmwatch/game.db. Every realm event becomes XP,
intrusions become bestiary entries, alerts become accept/complete quests,
and the codex chronicles it all.
realm quest list | accept | completerealm progression level
The Astral Conduit
A FastMCP server lives in-tree at plugins/mcp/launcher.py.
Claude Code attaches with one command and gains 30+ tools across realm
status, fleet ops, quests, combat-ward, codex, and progression.
Stdio today; SSE on /mcp/sse planned.
claude mcp add realmwatch \
~/Projects/realmwatch/plugins/mcp/launcher.py
Tide Singers
realm wave install spawns live monitors as
Wave Terminal
blocks. Three TUIs ship: WAN bandwidth (gatekeeper br-lan.38),
palace-daemon health, live journal tail. Each resizes cleanly and
goes red-bordered when its source falls quiet.
Eight workings, freshly bound
Zabbix-class features, transcribed into the realm.
When a node's upstream gateway is already in a problem state, every child node's alert is hushed at the dispatch stage. The classic alert storm becomes a single, accurate warning.
realm alerting whyPlace the Watchman's Seal on an event and the channel falls quiet. Subsequent matching alerts are absorbed while a human owns the problem.
realm event ack · close · comment — full state machine in the events table30+ typed node roles — gateway, ap, hypervisor, nas, vm — each carrying default discovery providers, default sublabel format, and a tag set. New hosts inherit the right treatment automatically.
realm role list · realm role nodesPer-node parameters — CPU thresholds, ping intervals, oracle prompts — stored as runes that any rule can resolve. Override per role, per node, or per environment.
realm macro set · get · explain — resolved at rule evaluationSchedule a Veiled Hour and both the Herald's Watch and the Town Crier fall silent. Recurring, one-shot, by node pattern or by role.
realm maintenance list / active / checkEvery interface, every container, every disk becomes its own minor entity. Plugins declare discovery prototypes once (sublabel, fantasy template, alert clauses with {{#MACRO}} placeholders) and the engine materializes one rule per discovered instance — auto-created, auto-linked, auto-cleaned-up when it vanishes.
realm discovery prototypesHosts announce themselves at the gate. Metadata (OS, OUI, hostname) drives automatic role and tag assignment. Heartbeats track liveness.
Declarative rules: if OUI matches OpenWrt, then role=ap, then add tag wireless. New hosts walk into the realm and emerge already classified.
One command, forty verbs
A git-style dispatcher. Drop a file, gain a subcommand.
$ realm status ┌─ REALM STATUS ──────────────────────────────────────────────┐ │ uptime 14d 03:22 events (24h) 1,847 │ plugins loaded 47 / 47 sse subscribers 4 │ nodes online 127 / 131 maintenance 1 active │ alerts pending 2 unack oracle backlog 0 │ player level 14 (Archmage) open quests 3 │ mcp tools 32 exposed wave blocks 3 attached └─────────────────────────────────────────────────────────────┘ $ realm role show gateway fantasy_name : The Warding Citadel default_tags : critical, infrastructure, alerting:loud discovery : netdata, snmp, latency, firewall sublabel : "{ip} · {os} · {fw}" $ realm watch --filter alert [19:42:11] ▲ ward-stone ward.firewall.drop.spike suppressed-by gatekeeper [19:42:18] ● scrying-stone ward.recovered.cpu cleared · +12 xp [19:42:24] ▼ dragon-at-gate ward.tls.expiry.soon acked by jp · quest accepted [19:42:31] ● aether-tower ward.roaming.client familiar slipped between towers $ realm wave install ✓ spawned bandwidth block 8a3c… title: WAN br-lan.38 ✓ spawned palace block 1f02… title: Palace · familiar ✓ spawned daemon block b771… title: palace-daemon journal $ _
40+ subcommands. Bash and zsh completion query the live filesystem — no registry.
Forty-seven plugins, every one optional
The core is a rendering engine. Everything else is a drop-in scroll.
Quick start
Python 3.12 (uv) · Node for esbuild · stdlib http.server · SQLite WAL
# Clone the realm $ git clone https://github.com/jphein/realmwatch.git $ cd realmwatch # Install Python (uv) + Node deps $ make install $ make build # esbuild src/main.js → realm-map.js $ make dev # python3 map_server.py — :80 + SSE + plugins # Install the realm CLI into ~/.local/bin (no sudo) $ make cli-install $ realm status # Optional: attach Claude Code to the Astral Conduit (MCP) $ claude mcp add realmwatch \ ~/Projects/realmwatch/plugins/mcp/launcher.py # Optional: spawn live Wave Terminal dashboards $ realm wave install