monitoring-alerting
Skill30 starsChanged 4 months agoMITView on GitHub
Monitoring and alerting design reviewer for production backend services. ALWAYS use when writing Prometheus alerting rules, designing Grafana dashboards, defining SLI/SLO, configuring alert routing (PagerDuty/OpsGenie/Slack), or reviewing existing monitoring setups. Covers SLI/SLO definition, alert rule quality (sensitivity/specificity tradeoff), burn-rate alerting, alert fatigue prevention, dashboard design principles, label cardinality management, and on-call routing configuration. Use even for "just add an alert" — a poorly designed alert either pages at 3AM for non-issues (alert fatigue) or stays silent during real outages (false confidence).
In this repository52 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- api-designSkill
- api-integration-testSkill
- constructive-thinkingSkill
- create-prSkill
- deep-researchSkill
- e2e-testSkill
- fuzzing-testSkill
- git-commitSkill
- go-benchmarkSkill
- go-ci-workflowSkill
- go-code-reviewerSkill
- go-concurrency-reviewSkill
- go-dependency-auditSkill
- go-error-reviewSkill
- go-logic-reviewSkill
- go-makefile-writerSkill
- go-observability-reviewSkill
- google-searchSkill
- go-performance-reviewSkill
- go-quality-reviewSkill
- go-review-leadSkill
- go-security-reviewSkill
- go-test-reviewSkill
- incident-postmortemSkill
- kafka-event-driven-designSkill
- load-testSkill
- local-transcriptSkill
- log-analyzerSkill
- mongo-migrationSkill
- mysql-migrationSkill
- oceanbase-table-designSkill
- oracle-migrationSkill
- pg-migrationSkill
- readme-generatorSkill
- redis-cache-strategySkill
- security-reviewSkill
- stock-analysis-leadSkill
- stock-balance-sheet-reviewSkill
- stock-business-reviewSkill
- stock-earnings-quality-reviewSkill
- stock-industry-reviewSkill
- stock-management-reviewSkill
- stock-peer-comparison-reviewSkill
- systematic-debuggingSkill
- tdd-workflowSkill
- tech-doc-writerSkill
- thirdparty-api-integration-testSkill
- unit-testSkill
- update-docSkill
- writing-plansSkill
- yt-dlp-downloaderSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 5 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 109
PROCEED: Every change has risk level and mitigation.
- Distinctive: line 113
Before delivering output, verify all §8 Output Contract sections present.
- Distinctive: line 125
Force Standard or higher: when any signal appears: SLO definition, burn-rate alerting, PagerDuty/OpsGenie routing, multi-service dashboard, …
- Distinctive: line 132
When context is incomplete, degrade gracefully — never guess traffic patterns.
- Very specific: line 210
If promtool/amtool are unavailable in the environment, state Not run — <tool> unavailable in §8.4 and list the exact commands for the user.
- Very specific: line 235
Check the threshold against traffic before shipping: at 10 QPS a [5m] window sees ~3000 requests, so 1% is ~30 errors — meaningful.
- Distinctive: line 336
Every monitoring review MUST produce these sections.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Monitoring & Alerting Design Review
Quick Reference
| If you need to… | Go to |
| Scope / prerequisites / depth | §1, §2 Gates, §3 Depth |
| Handle incomplete context | §4 Degradation Modes |
| Evaluate the design item by item | §5 Design Checklist |
| Validate rules before shipping | §5.5 Rule Validation |
| Avoid common alerting mistakes | §6 Anti-Examples |
| Score, then format the output | §7 Scorecard, §8 Output Contract |
| SLI/SLO, burn-rate, error budget | references/sli-slo-patterns.md |
| Alert anti-patterns and fatigue | references/alert-anti-patterns.md |
| Routing / grouping / inhibition config | references/alertmanager-config-patterns.md |
§1 Scope
In scope — monitoring and alerting for production backend services:
- SLI (Service Level Indicator) definition and measurement
- SLO (Service Level Objective) target setting and error budget
- Prometheus alerting rules (PromQL,
forduration, severity labels) - Burn-rate alerting (multi-window, multi-burn-rate SLO alerts)
- Grafana dashboard design (layout, variable templating, panel types)
- Alert routing configuration (PagerDuty/OpsGenie/Slack, severity-based routing)
- Alert fatigue audit (noise ratio, actionability, deduplication)
- Label cardinality management (high-cardinality label detection)
- On-call runbook integration (alert → runbook → action mapping)
Out of scope — delegate to dedicated skills:
- Metrics/tracing instrumentation in code →
go-observability-review - Application performance profiling →
go-benchmark - Infrastructure provisioning (Prometheus/Grafana setup) → ops tooling
- Log aggregation pipeline design → separate skill
§2 Mandatory Gates
Execute gates sequentially. Each gate has a STOP condition.
Gate 1: Context Collection
| Item | Why it matters | If unknown |
| Service type (API / worker / batch / data pipeline) | Determines which SLIs are relevant | Must clarify |
| Current SLIs/SLOs (if any) | Building on existing or greenfield? | Assume greenfield |
| Monitoring stack (Prometheus/Datadog/CloudWatch) | Query language and alert config format differ | Assume Prometheus + Grafana |
| On-call routing (PagerDuty/OpsGenie/Slack/custom) | Determines alert destination config | Ask |
| Traffic pattern (steady / bursty / batch / cron) | Affects alert window sizing and threshold | Must clarify |
| Current alert count | Audit scope for alert fatigue | Ask; critical for review mode |
STOP: The request needs service context that is unavailable and unobtainable — no SLI candidates identifiable and the user cannot describe the service. Clarify before proceeding.
PROCEED, at the depth the context supports (this gate selects a §4 mode, it does not require full context):
| Context available | Proceed as | Ceiling |
| Service type and traffic pattern | Full | no restriction |
| Service type only | Degraded | no precise thresholds or window sizes |
| Neither — only alert rules pasted in | Minimal | static rule review only: syntax, anti-patterns, missing annotations. No SLO alignment, threshold, or routing verdicts |
| Greenfield, requirements only | Planning | strategy proposal, no review of existing setup |
Minimal mode is a legitimate entry point, not a gate failure — a pasted alert rule can be checked for a missing runbook or an absolute-count expression without knowing the service. What Minimal must not do is emit a threshold or an SLO verdict; those go to §8.9 as "requires service context". See §4 for the full matrix.
Gate 2: Scope Classification
| Mode | Trigger | Output |
| review | User provides existing alerts/dashboards | Findings + improvement recommendations |
| design | User describes service needing monitoring | Complete SLI/SLO + alerts + dashboard spec |
| audit | User wants alert fatigue / noise analysis | Actionability report + reduction plan |
STOP: Request is about code instrumentation (not alert/dashboard design). Redirect to go-observability-review.
PROCEED: Monitoring/alerting design intent confirmed.
Gate 3: Risk Classification
| Risk | Definition | Required action |
| SAFE | New alert for non-critical service, dashboard addition | Standard review |
| WARN | Modifying existing production alerts, changing routing | Validate no coverage gap introduced |
| UNSAFE | Removing alerts, changing SLO targets, PagerDuty routing change | Impact assessment + rollback plan |
STOP: Any UNSAFE change without impact assessment.
PROCEED: Every change has risk level and mitigation.
Gate 4: Output Completeness
Before delivering output, verify all §8 Output Contract sections present. §8.9 Uncovered Risks must never be empty.
§3 Depth Selection
| Depth | When to use | Gates | References to load |
| Lite | Single alert rule review, dashboard panel addition | 1–4 | None |
| Standard | Full SLI/SLO definition, alert suite for a service | 1–4 | sli-slo-patterns.md |
| Deep | Alert fatigue audit, multi-service monitoring architecture, burn-rate alerting | 1–4 | All three reference files |
Force Standard or higher when any signal appears: SLO definition, burn-rate alerting, PagerDuty/OpsGenie routing, multi-service dashboard, alert fatigue investigation, label cardinality concern.
§4 Degradation Modes
When context is incomplete, degrade gracefully — never guess traffic patterns.
| Available context | Mode | What you can do | What you cannot do |
| Full (service type, SLIs, traffic, stack, routing) | Full | Complete SLI/SLO + alerts + dashboard | — |
| Service type known, traffic unknown | Degraded | SLI selection + alert rules; flag threshold unknowns | Set precise thresholds, window sizes |
| Only alert rules, no service context | Minimal | Static rule review (syntax, anti-patterns) | SLO alignment, routing review |
| No existing monitoring (greenfield) | Planning | Propose monitoring strategy from requirements | Review existing setup |
Hard rule: Never set alert thresholds without knowing the traffic pattern and the evaluation window — a ratio threshold is meaningless without both. At 10 QPS a [1m] window sees ~600 requests, so 1% needs 6 errors; a [10s] window sees ~100, so a single error crosses 1%. At 10K QPS the same 1% means ~100 errors/sec. The rule of thumb: min_errors_to_trip = threshold x QPS x window_seconds; when that number is below ~5, the alert is measuring noise. In Degraded mode, flag all thresholds as "requires traffic data to validate" in §8.9.
§5 Design Checklist
Execute every item. Mark PASS / WARN / FAIL with evidence.
5.1 SLI/SLO Foundation
- SLIs defined for the service — every production service needs measurable SLIs, and each ratio SLI needs both halves defined: which events are valid (denominator — exclude health checks, synthetic probes, client cancellations) and which are good (numerator — decide explicitly how
429/499/4xxare treated). Undocumented exclusions make an SLI unauditable. Standard SLIs by service type:- API service: availability (good/valid ratio), latency as the proportion of requests under a threshold (e.g. 99% < 400ms — not a raw p99 value, which has no countable bad event to burn a budget against), error rate
- Worker/consumer: processing rate, lag, error rate, processing latency
- Batch job: completion rate, duration, data quality
- Data pipeline: throughput, freshness, correctness
- SLOs set with error budget, on a stated basis — each SLI has a target (e.g. "99.9% availability over 30 days") and
error budget = 1 - SLO. Say which basis the budget is in: a time-based SLO converts directly to minutes (0.1% of 30 days = 43.2 min); a request-based SLO's budget is 0.1% of valid requests, which equals those minutes only under uniform traffic. Quoting minutes for a request-based SLO without that caveat promises a downtime guarantee the SLO does not make. SLOs must be agreed with stakeholders, not invented by engineers. - Burn-rate alerting for SLOs — instead of raw threshold alerts, use multi-window burn-rate alerts that fire when error budget is being consumed too fast. This dramatically reduces false positives. Load
references/sli-slo-patterns.mdfor patterns.
5.2 Alert Rule Quality
- Every alert is actionable — when this alert fires, is there a concrete action the on-call can take? If the answer is "look at it and hope it resolves," the alert should be a dashboard graph, not a page. Non-actionable alerts cause alert fatigue.
forduration prevents flapping —foris optional in Prometheus (omitted means fire on the first evaluation where the expression is true). Default to setting it, because absorbing transient spikes is what stops 3AM flapping: typicalfor: 5mfor warning,for: 2mfor critical. Too short on a noisy metric → flapping; too long (e.g.for: 30m) → delayed notification.Whether
foris needed depends on whether the expression already expresses duration — "it looks like a liveness check" is not the same thing.up == 0is true after a single failed scrape, so it needsfor(Prometheus's own canonical example isup == 0+for: 5m); avector(1)watchdog needs none, because it is always firing and is alerted on by its absence. Full decision table, includingabsent()vsabsent_over_time():alert-anti-patterns.md§0.Flag a missing
foras WARN, not FAIL, and name which row above you applied.
5b. Page-worthiness comes from user impact and redundancy, not from the signal — the gap the forward eval exposed: an agent explained that up is telemetry rather than customer impact, then set a single-replica up == 0 to severity: critical on the platform on-call in the same answer. Two questions decide it: how many replicas remain, and how much deadline headroom is left before the SLO is threatened. One of six replicas down is a ticket; all replicas down, a single-instance service, or a failing external probe is a page. State which you used — "paged because 3/3 replicas down" is reviewable, "paged because up == 0" is not. Full table: alert-anti-patterns.md §0.1.
- Severity labels match routing — every alert carries a severity label from a closed, documented set, and every value in that set maps to exactly one routing policy. A policy is not a single destination: it has one primary action receiver (the thing that gets a human to act) plus zero or more secondary receivers for visibility, which is exactly what
continue: truefan-out expresses (alertmanager-config-patterns.md§4). What must be unambiguous is who acts, not how many places see it. The common mapping iscritical→ page,warning→ chat,info→ dashboard, and the common tooling is PagerDuty/OpsGenie + Slack — but that is this skill's default example, not a requirement. Some orgs page from Slack with a bot, splitcriticalinto business hours vs out of hours, or have noinfotier at all. What is actually reviewable: (a) the mapping is written down, (b) no severity value is unrouted, (c) nothing that pages a human is only sent somewhere nobody watches at 3AM. When the user states their own mapping, review against theirs. - Alert includes runbook link — every alerting rule should include an
annotations.runbook_urlpointing to a runbook with: what the alert means, how to diagnose, how to mitigate. Without runbooks, on-call responders waste time Googling their own alerts.
5.3 Dashboard Design
- Dashboard follows USE/RED method — organize dashboards by signal type:
- USE (infrastructure): Utilization, Saturation, Errors (CPU, memory, disk, network)
- RED (services): Rate, Errors, Duration (request rate, error rate, latency)
- Top row: golden signals overview. Detail rows: drill-down by endpoint/consumer/partition.
- Dashboard uses variables for templating — Grafana variables (
$service,$namespace,$instance) allow one dashboard to serve multiple instances. Avoid hardcoded label values in queries. - No unbounded labels in dashboard queries — get the causality right, because it decides where the fix goes. Series count is created at instrumentation time: an unbounded label (
user_id,trace_id, full URL path) attached in application code multiplies series whether or not anything queries it. A query cannot create series — it can only load a huge number at once (slow panels, query-path memory, plausible OOM). So a query over an unbounded label is a symptom to flag, the real fix belongs in instrumentation (go-observability-review), and the dashboard-side fix is to aggregate away (sum by (status_code)) or filter to a bounded set. Usemethod,status_code, route template (/users/:id, not/users/12345).
5.4 Operations & Routing
- Alert routing matches severity — no orphan alerts: every severity value in use resolves to a receiver, and the root route has a catch-all. Verify against the org's own mapping (§5.2 item 6) rather than assuming PagerDuty/Slack. The one non-negotiable: anything defined as page-worthy must reach a channel with an escalation path, not only a chat room.
- Deduplication and grouping configured —
group_bydoes not stop alert instances from firing; Prometheus still evaluates and fires one alert per label set, and they all appear in the Alertmanager UI and API. What grouping changes is notification volume: instances sharing thegroup_bylabels are batched into one notification instead of N.group_waitsets how long to wait for more members of a new group,group_intervalhow long before sending an update for a group that already notified. Without grouping, one incident across N instances becomes N pages. - Inhibition rules prevent alert cascade — if the database is down, suppress all "elevated error rate" alerts from services that depend on it. Without inhibition, one root cause generates dozens of symptomatic alerts.
- Alert fatigue metrics tracked — measure: total alerts/week, alerts-per-on-call-shift, % of alerts that required action, MTTA (mean time to acknowledge). Target: <5 pages/week per on-call, >80% actionability rate.
5.5 Rule Validation (Eat Your Own Dog Food)
A skill that preaches "no false positives, no silent gaps" must validate its rules mechanically, not by eyeball:
- Rules pass
promtool check rules alerts.yml— syntax + PromQL validation before any rule ships. SLO-critical alerts have
promtool test rulesunit tests — Prometheus natively asserts "given this input series, this alert fires (or stays silent)". That is the executable form of the sensitivity/specificity tradeoff, and it is the only thing that catches a wrong window pairing or a wrongfor, both of which parse perfectly. Write at least two cases per SLO-critical alert: one where it MUST fire, one where it MUST stay silent.A third case matters more than either: the alert must stop firing once the burn stops. A brief spike is silent whether the rule is single- or multi-window, so only "burn ended, must stop paging" proves the short-window gate is doing anything. Working example with all five cases (fire / silent / spike absorbed / health-checks excluded / clears after recovery), runnable as-is:
tests/promtool/rules_test.yml.- Routing config passes
amtool check-config alertmanager.yml— validate routing/inhibition changes before deploy.
If promtool/amtool are unavailable in the environment, state Not run — <tool> unavailable in §8.4 and list the exact commands for the user; never claim rules are validated without running them.
A skip is not a pass — for this skill's own suite too: run_regression.sh prints how many external validators ran and says PASS (text layer only) when that is zero. Report the same way.
- Burn-rate arithmetic is derived, never quoted.
budget_consumed = burn_rate x window / slo_window;time_to_exhaust = slo_window / burn_rate. These get confused constantly: for a 30-day SLO a 14.4x burn spends 2% of budget per hour and takes ~50 hours to exhaust it — not 2 hours. Compute both before writing either into a summary (scripts/lint_monitoring_docs.pychecks every such claim here against the formulas).
§6 Anti-Examples
AE-1: Alert on absolute count instead of rate
# WRONG: fires when 10 errors exist (even over 24 hours = normal)
- alert: HighErrorCount
expr: http_errors_total > 10
# RIGHT: rate relative to traffic — and complete, because a RIGHT example is copied
- alert: HighErrorRate
expr: rate(http_errors_total[5m]) / rate(http_requests_total[5m]) > 0.01
for: 5m
labels:
severity: warning
annotations:
summary: "Error ratio above 1% on {{ $labels.job }}"
runbook_url: "https://wiki.example.com/runbooks/high-error-rate"Check the threshold against traffic before shipping: at 10 QPS a [5m] window sees ~3000
requests, so 1% is ~30 errors — meaningful. At 1 QPS it is 3, which is noise (§4).
AE-2: No for duration — flapping on transient spike
# WRONG: fires immediately on any spike, resolves in seconds, pages at 3AM
- alert: HighLatency
expr: histogram_quantile(0.99, rate(http_duration_seconds_bucket[5m])) > 1
# RIGHT: require a sustained condition, and route it
- alert: HighLatency
expr: histogram_quantile(0.99, rate(http_duration_seconds_bucket[5m])) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "p99 latency above 1s on {{ $labels.job }}"
runbook_url: "https://wiki.example.com/runbooks/high-latency"This is a threshold alert on a percentile — fine as a symptom page. It is not an SLI: to
burn an error budget you need the proportion of requests under the threshold instead
(sli-slo-patterns.md §1.1).
AE-3: Alert without runbook — on-call doesn't know what to do
# WRONG: no annotations, no runbook
- alert: DatabaseConnectionPoolExhausted
expr: db_pool_active >= db_pool_max
# RIGHT: include runbook and summary
- alert: DatabaseConnectionPoolExhausted
expr: db_pool_active >= db_pool_max
for: 2m
annotations:
summary: "DB connection pool exhausted on {{ $labels.instance }}"
runbook_url: "https://wiki.example.com/runbooks/db-pool-exhausted"AE-4: user_id in PromQL label — cardinality explosion
# WRONG: unique label per user → millions of time series
- record: user_request_duration
expr: histogram_quantile(0.99, rate(http_duration_seconds_bucket{user_id!=""}[5m]))
# RIGHT: use bounded labels only (method, status_code, endpoint)AE-5: Page-worthy alert routed to chat only — no escalation
# WRONG: two problems. (a) page-worthy severity lands in a chat channel with no
# escalation, where it drowns in messages; (b) `match` is the deprecated form.
route:
receiver: slack-team
routes:
- match: {severity: critical}
receiver: slack-team
# RIGHT: modern `matchers`, and page-worthy severity reaches an escalation path
route:
receiver: slack-team
routes:
- matchers: ['severity = "critical"']
receiver: pagerduty-oncallThe receiver names are this skill's default example — review against the org's own severity → receiver mapping. What is never acceptable is a page-worthy alert whose only destination has no escalation.
AE-6: Monitoring gap reported as "system is stable"
WRONG: "no alerts fired this month, so the system is healthy". RIGHT: "no alerts fired — verify coverage first: are the SLIs measured, are the thresholds right? Absence of alerts ≠ absence of problems."
Extended anti-examples (AE-7 through AE-13) in references/alert-anti-patterns.md.
§7 Monitoring Scorecard
Critical — any FAIL means overall FAIL
- SLIs defined and measured, matching the service type (§5.1) — API: availability + latency + error rate; worker/consumer: lag + processing success rate; batch: on-time completion + correctness; pipeline: freshness + coverage + correctness. Judging a batch job against
availability, latency, error ratefails a well-designed batch job for lacking SLIs it should not have - Every alert is actionable (clear action when it fires, not just "investigate")
- Alert severity labels match routing — every severity value maps to a receiver under the org's own documented mapping, and page-worthy alerts reach a channel with escalation
Standard — 4 of 5 must pass
- SLOs set with error budget and stakeholder agreement
forduration set on every alert that needs damping, or a stated reason it is omitted (deadman, discrete safety event, expression already integrates over time — §5.2 item 5)- Runbook link included in alert annotations
- Dashboard follows USE/RED method with variable templating
- No unbounded labels in alert rules or dashboard queries (and the fix is routed to instrumentation, not just to the query)
Hygiene — 3 of 4 must pass
- Alert grouping and deduplication configured (Alertmanager
group_by) - Inhibition rules prevent alert cascade from single root cause
- Alert fatigue metrics tracked (alerts/week, actionability rate)
- Burn-rate alerting for SLO-critical services
Verdict: X/12; Critical: Y/3; Standard: Z/5; Hygiene: W/4.
PASS requires: Critical 3/3 AND Standard ≥4/5 AND Hygiene ≥3/4.
§8 Output Contract
Every monitoring review MUST produce these sections. Write "N/A — [reason]" if inapplicable.
### 8.1 Context Gate
| Item | Value | Source |
### 8.2 Depth & Mode
[Lite/Standard/Deep] × [review/design/audit] — [rationale]
### 8.3 SLI/SLO Definition (Standard/Deep)
| SLI | Measurement | SLO Target | Error Budget |
### 8.4 Alert Rules
- Per alert: name, expr, for, severity, summary, runbook_url
- Validation evidence: `promtool check rules` / `promtool test rules` output,
or `Not run — <tool> unavailable` + exact commands for the user
### 8.5 Dashboard Spec (Standard/Deep)
- Panel layout, queries, variables, drill-down structure
### 8.6 Routing Configuration
- Severity → destination mapping
- Grouping, deduplication, inhibition rules
### 8.7 Alert Fatigue Assessment (audit mode)
- Total alerts/week, actionability %, recommendations
### 8.8 Runbook Mapping
| Alert | Runbook URL | Last Updated |
### 8.9 Uncovered Risks (MANDATORY — never empty)
| Area | Reason | Impact | Follow-up |Volume rules: FAIL always fully detailed; WARN up to 10 with overflow to §8.9; PASS summary only; §8.9 must document every assumption (especially an unknown traffic pattern).
Scorecard summary (append after §8.9):
Scorecard: X/12 — Critical Y/3, Standard Z/5, Hygiene W/4 — PASS/FAIL
Data basis: [full context | degraded | minimal | planning]§9 Reference Loading Guide
§3's depth table sets the baseline. Load one reference early, regardless of depth, when its
signal appears: sli-slo-patterns.md for SLO or burn-rate work, alert-anti-patterns.md
for alert-fatigue investigation, alertmanager-config-patterns.md for routing, grouping or
inhibition.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

