slo-design
Skill0 starsChanged 2 months agoApache-2.0View on GitHub
Design SLIs, SLOs, error budgets and burn-rate alerts that page a human only when users are actually affected. Use when defining reliability targets for a service, replacing threshold alerts that cause fatigue, choosing what to measure, deciding availability targets, or building alerting that survives contact with production.
In this repository26 other files it gives its agents.
- AGENTS.mdAGENTS.md
- aws-production-debuggingSkill
- github-actions-debuggingSkill
- postgresql-troubleshootingSkill
- container-image-reviewSkill
- docker-debuggingSkill
- incident-triageSkill
- postmortem-analysisSkill
- production-debuggingSkill
- kubernetes-networkingSkill
- kubernetes-production-readinessSkill
- kubernetes-resource-debuggingSkill
- kubernetes-troubleshootingSkill
- linux-network-debuggingSkill
- linux-performanceSkill
- linux-troubleshootingSkill
- dns-troubleshootingSkill
- http-debuggingSkill
- tls-debuggingSkill
- observability-debuggingSkill
- prometheus-troubleshootingSkill
- secrets-management-reviewSkill
- technology-jobSkill
- terraform-reviewSkill
- terraform-safe-changesSkill
- terraform-troubleshootingSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 4 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 112
Run this before proposing any number.
- Distinctive: line 258
Check these at the end of the first quarter:
- Distinctive: line 260
Did the SLI move during real incidents?: If it stayed flat through an outage, it measures the wrong thing.
- Distinctive: line 264
Was the budget ever close to exhausted?: Never close means the target is too loose to inform any decision.
≈ “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
SLO Design
Define what "working" means for a service, in terms a user would recognise, and alert only on that.
Purpose
Use this when:
- Defining reliability targets for a service.
- Alert fatigue is a problem, or an incident was missed by the alerts that existed.
- Choosing between competing reliability work and feature work.
- A new service is being onboarded to production.
Do not use this when:
- You are debugging a live problem — use
incident-triageorobservability-debugging. - The metrics needed do not exist yet — get instrumentation working first with
prometheus-troubleshooting.
What this skill assumes: request-level metrics with status and duration, and enough history to know current performance. Setting a target without knowing the current number produces an SLO that is either already violated or trivially met.
Operating Procedure
- Identify the user and the journey. Who is affected, doing what? "The API" is not a journey; "a customer completing checkout" is.
- Choose SLIs from the user's perspective. Measured as close to the user as practical.
- Measure current performance over at least 4 weeks, including a peak period.
- Set the SLO just below achievable reality, not at an aspirational number.
- Derive the error budget and state what happens when it is exhausted. An SLO with no consequence is a dashboard, not a target.
- Write burn-rate alerts, not threshold alerts.
- Review quarterly. An SLO that has never been close to violation is too loose to be useful.
The current performance number is Observed. The target is a Recommendation with a business trade-off attached — always present it that way, never as a technical fact.
Investigation
Step 1 - pick the SLI
A good SLI is a ratio of good events to valid events. Ratios are naturally normalised, work across traffic levels, and make the error budget arithmetic straightforward.
SLI = good events / valid events| Journey type | SLI | Measured where |
| Request/response | Fraction of requests with status < 500 and duration < threshold | Load balancer or gateway |
| Pipeline / batch | Fraction of records processed within the freshness target | Pipeline output |
| Storage | Fraction of reads returning correct data within the latency target | Client |
| Scheduled job | Fraction of runs that completed successfully on schedule | Scheduler |
Three rules that decide whether the SLI is worth anything:
- Measure as close to the user as you can. Server-side metrics miss the failures that never reached the server — DNS, TLS, load balancer, the client's own network. Those are real outages your dashboards will show as perfect.
- Exclude what the user did not do. A 400 from an invalid client request is not your failure. Define valid events explicitly.
- Combine availability and latency into one SLI where you can. A request that takes 30 seconds is a failure even with a 200 status; users do not distinguish.
# Availability-and-latency SLI in one expression
(
sum(rate(http_request_duration_seconds_bucket{le="0.5",status!~"5.."}[5m]))
)
/
(
sum(rate(http_request_duration_seconds_count[5m]))
)The numerator counts requests that were both fast enough and not server errors. Note this requires a histogram bucket boundary at exactly your latency threshold — choose the SLO threshold from the buckets you have, or add the bucket first.
Step 2 - measure before you target
# 28-day achieved SLI
sum(increase(http_requests_total{status!~"5.."}[28d]))
/ sum(increase(http_requests_total[28d]))Run this before proposing any number. Then:
| Current achieved | Sensible SLO |
| 99.95% | 99.9% |
| 99.5% | 99.0% or 99.5%, with work planned |
| 97% | 99% is a project, not a target — say so |
Setting an SLO above current performance means starting in violation, which teaches the team to ignore it. Setting it far below means it never triggers anything.
Step 3 - the error budget
99.9% over 30 days = 43.2 minutes of budget
99.95% = 21.6 minutes
99.99% = 4.3 minutesTwo things make this useful, and without both the SLO is decoration:
- A policy. What changes when the budget is exhausted? The standard answer: feature deploys pause and reliability work takes priority until the budget recovers. Agree this with whoever owns the roadmap, in advance, in writing.
- Honesty about the cost. Each extra nine costs roughly an order of magnitude more. 99.99% over 30 days is 4.3 minutes — less than one unattended restart. If the team cannot respond in four minutes, the number is fiction.
1 - (
(1 - (sum(increase(http_requests_total{status!~"5.."}[30d]))
/ sum(increase(http_requests_total[30d]))))
/ (1 - 0.999)
)This is the fraction of budget remaining. Put it on the dashboard; it is the number that drives decisions.
Step 4 - burn-rate alerts
A threshold alert ("error rate > 1%") fires for a 30-second blip and stays quiet through a slow leak that consumes the whole month's budget. Burn-rate alerting fixes both.
Burn rate is how fast you are consuming budget relative to steady state. Burn rate 1 exhausts the budget exactly at the end of the window; burn rate 14.4 exhausts it in 2 days.
| Severity | Burn rate | Long window | Short window | Budget consumed before firing |
| Page | 14.4 | 1h | 5m | 2% |
| Page | 6 | 6h | 30m | 5% |
| Ticket | 3 | 1d | 2h | 10% |
| Ticket | 1 | 3d | 6h | 10% |
(
sum(rate(http_requests_total{status=~"5.."}[1h])) / sum(rate(http_requests_total[1h])) > (14.4 * 0.001)
)
and
(
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > (14.4 * 0.001)
)The two-window construction is the important part. The long window gives significance — it will not fire on a brief spike. The short window gives reset speed — the alert clears promptly once the problem stops, instead of hanging for an hour after recovery. Using either alone gives you a noisy alert or one that never clears.
0.001 here is 1 - SLO for a 99.9% target. Substitute your own.
Step 5 - check the alert would have caught real incidents
Take the last three incidents and ask: would this alert have fired, and how early? This is the only honest test of an alerting design, and it routinely reveals that the proposed page would have been silent for the incident everyone remembers — usually because the SLI was measured server-side and the outage was in front of the server.
Decision Tree
Designing an SLO
├── Can you measure the user journey end to end?
│ ├── Yes → SLI at that boundary
│ └── No → nearest proxy, and write down what it misses
├── What does failure look like to the user?
│ ├── Errors → availability SLI
│ ├── Slowness → latency SLI, or a combined one
│ ├── Stale data → freshness SLI
│ └── Wrong data → correctness SLI (hardest; usually needs sampling)
├── What is achieved today?
│ ├── Unknown → measure for 4 weeks before setting a target
│ └── Known → set the SLO just below it
├── Is there a policy for budget exhaustion?
│ ├── No → the SLO will be ignored; get agreement first
│ └── Yes → implement burn-rate alerts
└── Would the alert have caught your last three incidents?
├── No → the SLI is measured in the wrong place
└── Yes → ship it, review in a quarterCommon Causes
| Failure of an SLO programme | Symptom | Fix |
| Target set aspirationally | Permanently in violation, so ignored | Set below achieved performance |
| SLI measured server-side only | Perfect dashboards during a real outage | Measure at the edge or from a synthetic client |
| No error-budget policy | Nothing changes when it is exhausted | Agree the policy before the first breach |
| Too many SLOs | Nobody knows which one matters | One or two per user journey |
| SLO on a component, not a journey | CPU SLOs; users unaffected but the alert pages | SLO on user-visible behaviour |
| Threshold alerts kept alongside | Fatigue continues | Delete the thresholds you replaced |
| 100% target | Any blip is a violation | 100% is not a reliability target |
Safety
Read-only
Everything in this skill: querying historical metrics, computing achieved performance, writing alert expressions and evaluating them. Nothing here changes a running system.
Potentially disruptive
The outputs have operational consequences even though the analysis does not:
- Deploying new alert rules — a mistuned burn-rate alert pages people at 03:00. Validate the
expression against historical data first (
promtoolor a range query over the last month) and confirm how often it would have fired. - Removing old alerts as part of the migration — this is the risky half. Run the new alerts in parallel for at least one full incident cycle before deleting the old ones, or you will discover the coverage gap during an outage.
- Adopting an error-budget policy — pausing feature deploys is a real organisational change. Agree it with the people it affects rather than announcing it.
Destructive
This skill proposes no destructive operations.
Verification
An SLO is verified by how it behaves, over time, against real events.
Before: 47 alerts/week, 3 of them actionable; the last outage was reported by a customer first
After: 4 alerts/week, 4 actionable; the last outage paged 6 minutes before the first reportCheck these at the end of the first quarter:
- Did the SLI move during real incidents? If it stayed flat through an outage, it measures the wrong thing. This is the single most important check.
- Did the page fire, and early enough? Compare page time against the first customer report.
- Was every page actionable? A page nobody acts on is noise regardless of its design.
- Was the budget ever close to exhausted? Never close means the target is too loose to inform any decision.
- Did the policy get applied? A budget breached with no consequence means you have a dashboard, not an SLO.
Anti-Patterns
Bad: Target 99.99% because it sounds appropriately serious. Better: That is 4.3 minutes a month. Every deploy, dependency hiccup and certificate renewal eats into it. Pick the number the team can actually defend and staff.
Bad: Alert when error rate exceeds 1%. Better: That fires on a 30-second blip and stays silent through a week-long 0.9% leak that eats the entire budget. Burn-rate alerting covers both.
Bad: An SLO on CPU utilisation. Better: Users do not experience CPU. Resource metrics are for diagnosis; SLOs are for user-visible behaviour. Keep the CPU dashboard, do not page on it.
Bad: One SLO per microservice. Better: Users experience journeys, not services. Twenty service SLOs page twenty teams for one user-visible failure and nobody owns the whole thing.
Bad: Measure availability at the application, where you have the best metrics. Better: The best-instrumented place is behind everything that commonly breaks. A DNS or load balancer failure shows as 100% availability at the application while nobody can reach it.
Bad: Set the SLO to 100%. Better: 100% means no budget for deploys, no maintenance, and any single dropped request is a breach. It also removes the entire mechanism the SLO exists to provide.
Composition
prometheus-troubleshooting— when the metrics needed for the SLI are missing or wrong.observability-debugging— once an SLO alert fires and you need to find the cause.postmortem-analysis— error budget spend is the natural input to a postmortem.kubernetes-production-readiness— an SLO with an alert is a readiness requirement.
References
- Google SRE Workbook: Implementing SLOs — the source of the multi-window burn-rate table used here.
- Google SRE Workbook: Alerting on SLOs — the derivation of the burn-rate thresholds.
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.

