Why this matters beyond the homelab: A notification system that works when you write it and a notification system that still works six months later after three new tools got added are not the same system. This was the gap between them, and closing it meant deciding what the fleet’s alerts should sound like, not just where they should land.
The drift
The original Discord Ops Plan was written back in March: 28 channels across 7 categories, color-coded embeds, a defined scroll order for triaging alerts at 2am. It was the source of truth. By September it wasn’t describing reality anymore.
Grafana’s native alerting had started dumping raw, uncolored, flapping CPU and disk warnings straight into #metrics-bridge, bypassing the color and enrichment convention entirely, and firing at a threshold the original spec never called for (~86% with no pending period, when the spec said 90% sustained for 5 minutes). Proxmox lifecycle events and backup completions were landing in #fleet-log, a channel designed to be a manual human changelog, instead of their intended homes. The bot layer had changed underneath the plan too: the old bot was archived, a new discord.js bot had taken over as the infrastructure observer, and an AI agent had been added that the original plan never accounted for. Three new channels existed that weren’t in the document at all.
None of this was a channel-count problem. The 28-channel split exists on purpose, to isolate alert types by source and noise profile, and the fix was never going to be collapsing it down to something simpler. The fix was reconciling what the plan said with what was actually happening.
The routing contract
v3.1 resolves the drift with an explicit contract: Grafana critical alerts (disk-full, node-down, service-down) go to #fleet-status, Grafana warnings (CPU/memory/disk thresholds) go to #metrics-bridge, all Wazuh security alerts go to #alert-triage with an @mention added for high-severity ones. That last rule also resolves a conflict that had crept in separately: an earlier automation had split Wazuh alerts by severity across two different channels, which the new plan collapses back into one, correctly triaged channel.
Grafana and UptimeKuma post directly to Discord rather than routing through the automation layer. That’s deliberate: if the automation host goes down, the two most important early-warning systems keep reporting anyway.
The persona problem
Once the routing was fixed, the tone wasn’t. Four completely different tools were posting alerts, each with its own default identity, its own formatting, its own voice. Getting a coherent experience out of that without writing a unified alerting service meant treating the identity as a presentation layer, not a process.
Every alerting tool’s webhook got renamed to the same shared identity, “Admiral Ackbar,” with the same avatar. Grafana, UptimeKuma, and the automation layer’s own event notifications each just needed their existing username-override setting pointed at that name. No new service, no new SPOF, each tool still posts direct exactly as it did before, they just all show up looking like the same voice. The two agent bots that already have their own established identities were explicitly excluded from this and keep posting as themselves.
The voice itself is severity and type-keyed: critical alerts lead with “It’s a trap!”, warnings with “Stay on target.”, informational messages with “Sensors report.”, resolutions with “All clear, Fleet.” Specific failure types (node down, disk full, a failed integrity check) get their own lead phrase on top of the severity default. The phrase leads, then a severity tag and the actual data follow, so a scroll through the channel at 2am stays scannable without losing the substance.
The lesson
An ops runbook drifts the moment a second person, or a second tool, or a second bot gets added and nobody updates the document. The fix isn’t writing a better document, it’s building the review into the sprint cadence so drift gets caught in months, not in whatever crisis eventually forces someone to actually read the old plan against the live system. And a consistent voice across a fleet’s alerts is worth designing on purpose: it’s the difference between four tools shouting at you and one voice you’ve learned to trust.