Skip to content

Skills · sre-oncall

slo-spec

Define service level objectives for a service from its critical user journeys — each SLI a good-events / valid-events ratio with both sides defined and measured where the user feels it, a target set from user need and history (checked against dependency SLOs), the error budget computed in minutes and bad requests at current traffic, multi-window burn-rate alerts with the budget consumed when each fires, low-traffic handling, and an error-budget policy with owners. Use when the user asks to "define SLOs", "write our SLIs", "how much error budget do we have", "what burn-rate alerts should page", "is 99.99% realistic", or "write an error-budget policy".

Pack sre-oncallTier standardJob Run and recover the servicev0.1.0

npx skilldrop-cli install slo-spec
Other ways to install

With the sibling skills it hands off to:

npx skilldrop-cli install slo-spec --with-related

The whole pack it belongs to:

npx skilldrop-cli install --pack sre-oncall

By hand, from a clone of the repo:

cp -R packs/sre-oncall/skills/slo-spec ~/.claude/skills/

In Claude Code, with the sre-oncall plugin installed, invoke it as:

/sre-oncall:slo-spec

Try it

A realistic prompt from the skill's acceptance evals:

We need SLOs for our order service before the reliability review next week. Everything I know about it is in order-service.md: the journeys, traffic, what we measure today and the last 90 days. Give us SLIs, targets, error budgets, the alerts that should page, and an error-budget policy.

What a good result looks like

Example output

Larkspur Theatres booking API · the skill's own worked example, source

Worked example

Input

Set SLOs for our booking API. Customers browse showtimes (about 900,000 requests a day) and book seats (about 60,000 bookings a day). Booking calls our card processor, whose SLO is 99.95%; the API returns 200 only after the charge succeeds. Box-office staff use a back-office API, about 800 requests a day, 10:00–22:00. Last quarter from load balancer logs: browse 99.96%, booking 99.87%, back-office 99.4%. Our CTO wants "four nines everywhere". The team lead is Ines Calder; product owner is Raj Bhatt.

Script runs

python3 scripts/slo_math.py --batch slos.json        # browse, booking (with --dep 99.95)
python3 scripts/slo_math.py --name "Box-office API (probe every minute)" \
    --target 99.5 --window 30 --rpd 1440 --alerts "6:6h:1h:ticket"

Output, abridged to the rows used below:

Browse showtimes (availability): 99.9% over 30 days
  = 43.2 minutes of full outage per window (43m 12s)
  = 27,000 bad requests per window at 900,000 requests/day
  14.4x  1h    5m     page      1.44%          2%              2d 2h       540        45
  6x     6h    30m    page      0.6%           5%              5d          1,350      112
  1x     3d    6h     ticket    0.1%           10%             30d         2,700      225

Book seats (end to end): 99.8% over 30 days
  = 86.4 minutes of full outage per window (1h 26m 24s)
  = 3,600 bad requests per window at 60,000 requests/day
  14.4x  1h    5m     page      2.88%          2%              2d 2h       72         6 *
  Hard dependencies in series: 99.95% -> ceiling 99.95%; at their SLOs they spend 25% of this budget
  - 14.4x 1h/5m: only 6 bad events in the 5m short window ... the short window will flap.

Box-office API (probe every minute): 99.5% over 30 days
  = 216 minutes of full outage per window (3h 36m)
  6x    6h    1h     ticket    3%             5%              5d          10.8       1.8 *

Reply

Four nines isn't reachable for booking: every booking needs the card processor, which only promises 99.95%, so 99.99% would be spent five times over by the processor alone. I've set booking at 99.8% (last quarter ran 99.87%), browse at 99.9%, and the back-office API at 99.5% on a synthetic probe, because 800 requests a day is too few to page on.

Assumptions: 30-day rolling window; traffic is the daily average you gave; the 1 s, 10 s and 2 s thresholds are mine [assumption].

JourneySLI (good / valid)Measured atTargetBudget per 30 days
Browse showtimesGood: non-5xx in < 1 s / Valid: all GET /showtimes, excluding health checks and botsLoad balancer99.9%43.2 min · 27,000 bad requests
Book seatsGood: 200 or a bank decline within 10 s / Valid: all POST /bookings, excluding 4xx validation errorsLoad balancer99.8%86.4 min · 3,600 bad bookings
Back-office APIGood: probe gets a correct answer in < 2 s / Valid: one probe a minuteProbe99.5%216 min of failed probes

At its own SLO the card processor spends 25% of booking's budget. Going above 99.95% would need a second processor or an accept-now, charge-later path.

JourneyBurnLong / shortTrips atBudget at fireExhausts inAction
Browse14.4×1 h / 5 m1.44% errors2%2 d 2 hpage
Browse6×6 h / 30 m0.6%5%5 dpage
Browse1×3 d / 6 h0.1%10%30 dticket
Booking14.4×1 h / 15 m2.88%2%2 d 2 hpage
Booking6×6 h / 30 m1.2%5%5 dpage
Booking1×3 d / 6 h0.2%10%30 dticket
Back-office6×6 h / 1 h3% of probes5%5 dticket, 10:00–22:00

Booking's 5-minute short window would hold about 6 failed bookings at the threshold and flap, so it is 15 minutes. The back-office probe still has fewer than 2 failures expected in an hour, so it raises a ticket and never pages; staff will report an outage faster than a page.

Error-budget policy (owner: Ines Calder; to be agreed with Raj Bhatt before it applies)

Budget stateWhat changes
50% spent in the first 15 daysReliability work tops the next sprint
100% spentOnly fixes and security patches ship until the 30-day budget is positive
Card processor spent itRaise it with the processor using the numbers; the freeze still covers risky changes

Exception: the CTO approves a release during a freeze in writing, recorded on the release ticket.

To confirm: the three latency thresholds; whether bank declines reach the API as 200 or 402.

Next step: add the browse and booking alerts to the alerting system and set up the back-office probe.

How it's checked

Measured against plain Claude Code (2026-10-23): it met 61% of its checks, against 42% without it, and a blind judge preferred it. How skills are checked

38 assertions across 5 acceptance evals, and 9 trigger queries. Every skill's checks

What the output must do
  • Opens with the decisions and blockers in the first lines: that 99.99% for checkout is not achievable while every order depends on PayRail at 99.9%, and that the proposed worker timer cannot be the checkout SLI
  • Rejects order_worker_process_seconds as the checkout SLI because it starts after the queue wait, cites the 14 September backlog (about 3 minutes of queue wait while p99 stayed 400 ms) as the evidence, and measures checkout end to end from the load balancer request to the confirmation the customer sees
  • Defines every SLI as good events over valid events with both sides spelled out, including what is excluded from valid (for example card declines or 4xx validation errors), and does not use CPU, pod restarts or queue depth as an SLI
  • Sets a checkout target at or below 99.9% with the reason (PayRail's 99.9% SLO and the history), and says what redundancy or fallback a higher target would need
  • Gives each error budget in minutes and in bad requests at the stated traffic, and the numbers match the formulas (for example 99.9% over 30 days is 43.2 minutes, or 144,000 bad requests at 4,800,000 search requests a day)
  • Alerts use burn rate over a long and a short window (such as 14.4x over 1 h with 5 m, 6x over 6 h with 30 m, 1x over 3 d ticketing), each with the budget consumed when it fires, and none is a raw error-rate threshold
  • Treats the admin API as low traffic: shows that about 600 requests a day gives well under one expected bad request per alert window, and does not copy the customer paging set onto it (uses a longer window, a synthetic probe, or office-hours tickets, with the reason)
  • The error-budget policy names owners from the input (Priya Raman, Tom Okafor, Dana Whitlock) or roles, a release freeze except fixes when the budget is spent, and an exception route; it does not invent people, traffic figures, history or dependency SLOs that are not in the file
  • Answers in the first lines with the budget: 20.16 minutes of full outage and 28,000 bad requests per 28 days
  • Says the current rule (above 0.05% for 5 minutes) is a 1x burn over 5 minutes that pages on about 3–4 failed requests and a negligible share of the budget, and recommends replacing it
  • Recommends multi-window burn-rate alerts with long and short windows, two paging and one ticketing (for example 14.4x over 1 h with 5 m, 6x over 6 h with 30 m, 1x over 3 d with 6 h)
  • States for each alert the error rate that trips it (for example 0.72% for 14.4x) and the budget consumed when it fires, adjusted for the 28-day window (about 2.14%, 5.36% and 10.71%) rather than the 30-day 2/5/10%
  • Numbers are computed, not rounded guesses: no 'about 20 minutes' or 'roughly 30k'
  • Stays a short chat answer: no full SLO document, no error-budget policy section, no sections the question did not ask for
  • Does not invent journeys, dependencies, team names or traffic patterns not in the prompt
  • Opens by advising against 99.99% in plain words: the service missed 99.5% in both windows (about 99.3% and 99.43% achieved), and 99.99% shrinks the budget from 201.6 minutes / 168,000 bad requests to about 4 minutes / 3,360 bad requests per 28 days
  • Says the problem is that nothing changed when the budget was spent (releases continued at 3–4 a week), which a policy fixes and a tighter target does not
  • The policy has thresholds tied to budget states, with what changes at each: reliability work prioritised before the budget is gone, and a release freeze except fixes and security patches when it is spent
  • Names owners from the input (Marta Lindqvist, Owen Achterberg, Helen Varga) or their roles, and says the policy is agreed in advance by engineering and product
  • Includes an exception route: who can approve a release during a freeze, in writing, and how it is recorded
  • Handles budget spent by a dependency: the shared Postgres cluster accounted for about 62% and 30% of the two windows, so the policy escalates to its owner (Kofi Mensah, Data Platform) with the numbers rather than only freezing search releases, while noting that search's own releases also overspent the budget
  • Does not invent incidents, people, dependency SLOs or numbers not in the file
  • Answers the 99.99% question directly with a no (or 'not today'), and grounds it in the inputs: the Halberd gateway's 99.95% SLA alone allows 0.05% failures, five times a 0.01% budget, and there is no secondary acquirer until Corvid in Q2 2027; it may also note that Halberd and the Ledger DB in series (99.95% x 99.95%) come to about 99.90%.
  • Spots that the current rule counts 402 card_declined as errors, and that the 26 card-testing decline spikes caused most of the 31 pages. Its availability SLI treats a correct decline (and other 4xx such as 400/422/409/429) as not-bad, and leaves /healthz probe traffic out of valid events.
  • Measures the availability SLI from the ingress LB metric (lb_requests_total), not the app metric http_server_requests_total, and says why: the LB-only 502s during pod restarts, worth about 0.02% (LB 0.06% vs app 0.04% 5xx on POST /v1/charges).
  • Picks a POST /v1/charges availability target near 99.9% (anything from 99.9% to 99.95% is fine if justified against the ~99.91-99.96% monthly history and the dependency SLAs), and states the 30-day budget correctly. At 99.9% that is 43.2 minutes and about 93,312 bad requests at 36 req/s average (93.3M requests); at 99.95% it is 21.6 minutes and about 46,656.
  • Gives multi-window burn-rate alerts with a page/ticket split, and states for each one the burn rate, the windows, and the share of the 30-day budget used when it fires (e.g. 14.4x over 1h with a 5m short window is 2%, 6x over 6h/30m is 5%, and 1x over 3d as a ticket is 10%). It converts at least the fast-burn threshold into an error rate for the chosen target (14.4x at 99.9% is a 1.44% error ratio).
  • Defines a separate latency SLI for POST /v1/charges, with a threshold taken from the given distribution (e.g. under 2,000 ms, met by 99.12% today, or under 3,000 ms at 99.71%), not an arbitrary p99. It treats GET /v1/charges/{id} as its own SLO with its own budget (about 57,024 bad requests per 30 days at 99.9% and 22 req/s).
  • Flags at least one dependency risk that is not obvious: the idempotency Redis has no SLO and fails closed (503), or the fraud-scoring 99.9% SLO does not cap the charge SLO because it fails open.
  • Invents nothing that isn't in the inputs: no metric names other than lb_requests_total / lb_request_duration_seconds_bucket / http_server_requests_total / http_server_request_duration_seconds_bucket, no traffic figures, dependency SLAs or incident counts beyond those given. Any replacement rule YAML it writes uses those metric names and labels.
  • Tells the user plainly, near the top, that 99.99% is not a realistic or useful target for Tally, with numbers: at ~41,800 requests/month (1,900 x 22) it allows only about 4 failed requests a month (or 4.32 minutes per 30 days), and PeopleCore's 99.5% SLA alone allows up to 0.5% (about 216 minutes a month) with no cache or fallback.
  • Proposes a target based on the history in the notes: about 99.85% in July (61/40,300), 99.94% in August (23/37,900) and 99.67% in September (140/42,600), with the PeopleCore outage driving September. The target lands somewhere around 99.5% to 99.9%, not 99.99%.
  • Catches that PingDeck's 99.95% says almost nothing about users: /health is a static {"ok": true} that doesn't touch Postgres or PeopleCore, and checks are paused during the Sunday reboot. It bases the SLI on nginx access logs in Loki (good = non-5xx over valid requests), or on a deep synthetic check, not on the current /health.
  • Says outright whether the SLI counts requests or minutes, and why that matters here: the weekly 02:00-02:20 Sunday reboot (~87 minutes a month) affects almost no requests under a request-based SLI, but under a time-based one it would use up more than a 99.9% budget (43.2 min) by itself.
  • Handles low traffic explicitly, for example a minimum request count before an alert can fire, long windows (hours/days instead of 5 minutes), or alerting on absolute counts of failed submissions. It notes that with ~16 requests per 5 minutes in business hours, one error looks like a huge burn rate.
  • Fits the alerting to a single developer with no on-call: nothing pages 24/7. Alerts go to Jonah during business hours as notifications or tickets, with month-end (Marisol Teague's close) as the time that matters most.
  • Includes a short error-budget policy that names real owners from the notes (Jonah Okafor, Dana Whitfield, optionally Marisol Teague as stakeholder) and concrete actions such as pausing feature work, or adding an approver cache or fallback for PeopleCore. It stays short and doesn't invent a team, rota or process the notes don't support.
  • Invents nothing that isn't in the inputs: no Prometheus metrics (the user said they don't have Prometheus), no traffic, error or SLA figures beyond those in ops-notes.md, and no additional people or systems. Any Loki/LogQL queries reference only the nginx access-log fields the notes mention (status, path, request_time).
When it should and shouldn't activate

Should activate:

  • Define SLOs for our checkout service: which SLIs, what targets, and the error budget
  • How much error budget is 99.9% over 28 days if we do 3 million requests a day?
  • What burn-rate alerts should page us for a 99.95% availability SLO?
  • Product wants 99.99% for the payments API. Is that realistic when our card processor only promises 99.9%?
  • Write an error-budget policy: what happens when our SLO budget runs out

Should leave to another skill:

  • List the non-functional requirements for the new booking feature: latency, availability, data retention, accessibility
  • What should we instrument in the order service, and which dashboards and log fields do we need?
  • Write the on-call runbook for the payments service, including rollback and escalation
  • Compute our change failure rate and deployment frequency from this deploy log

Hands off to

Related skills

delivery-metrics-report, nfr-spec

Source

SKILL.md · the whole folder on GitHub.