Savings & optimization
Plutus surfaces five separate optimization signals: savings recommendations, waste detection, commitment utilization, commitment-expiration alerts, and credit burn-down. Each answers a different question, and each has a boundary worth knowing before you act on it.
Savings recommendations
Section titled “Savings recommendations”The /savings page lists three kinds of item side by side, each labeled with its source. There
is no deduplication between the two recommendation sources:
- Provider recommendations — read directly from each cloud’s own recommendation engine (AWS Cost Explorer rightsizing, Azure Advisor, GCP Recommender). Plutus doesn’t compute these; it fetches, stores, and displays what the provider already computed.
- Plutus’s own rightsizing engine — runs nightly over resource inventory, utilization telemetry, and resource-grain cost. Unlike the provider passthrough, this one is Plutus’s own analysis.
- Waste findings — shown with the type “Waste (cleanup)”. See Waste detection.
Two recommendations for the same resource can disagree — AWS’s rightsizing recommendations might
say “downsize to m5.large” while Plutus’s engine says “no clear saving here” for the same
instance. That disagreement is shown, not resolved, because it’s informative: it usually means
the two engines are looking at different observation windows or weighting peaks differently.
Why recommendations decline rather than guess
Section titled “Why recommendations decline rather than guess”Plutus’s own engine is written to decline a recommendation rather than guess:
- It needs at least 14 days of utilization telemetry. Shorter windows can miss a fortnightly or weekend-heavy cycle. A resource with too few days or too few samples per day gets no recommendation.
- A low average never overrides a high peak. A resource is declined if its p99 utilization is 60% or higher, or its maximum reaches 90% or higher. An instance that averages 15% CPU but spikes to 95% during a daily batch job is not a rightsizing candidate, even though the average alone would suggest one. The engine looks at the percentile distribution, not just the mean.
- A saving it can’t size is not emitted. A resource with no cost data for the window gets no recommendation, because “downsize this” with no dollar figure isn’t a saving.
What the engine recommends when none of those apply depends on sustained utilization, measured as the mean of each day’s p95:
- Under 20% — downsize.
- Under 3% — terminate. The saving is the resource’s whole cost.
Downsize savings are sometimes an estimate. Where Plutus finds the resource’s instance type in its price catalogue, the saving is the price difference to the next size down. Where it can’t find a match (no import for that region, an instance type the catalogue doesn’t have, or a provider it doesn’t cover), Plutus assumes the next size down costs half as much. Those recommendations say so on the row, so an estimate is never presented as a quoted price.
Every Plutus-sourced recommendation shows the observation window, sample count, and percentiles it rested on, so you can check the evidence rather than take the recommendation on faith. A provider recommendation doesn’t carry this — it shows whatever detail the provider’s own API returned.
Worked example: two EC2 instances both average 10% CPU over the past 30 days.
- Instance A’s utilization samples are tightly clustered — its mean daily p95 is 12%, its p99 is 15%, and it never passes 25%. That is under the 20% downsize threshold and well under both peak limits, so Plutus recommends downsizing, with the observation window and sample count shown.
- Instance B has the same 30-day average, but its p95 is 85% — a recurring weekly job spikes it. Its peak is over the 60% p99 limit, so Plutus emits no recommendation for instance B, even though the two instances look identical on average.
A provider engine looking only at the average might recommend downsizing both.
Waste detection
Section titled “Waste detection”Waste findings appear on /savings with the type “Waste (cleanup)”. They’re AWS-only, because
the resource inventory they read is written only by the AWS sync. Plutus runs its own rules over
that inventory, independent of the rightsizing recommendations above — waste detection asks “is
this resource plausibly wasted spend at all”, not “should this resource be a different size.”
The rules cover: unattached EBS volumes, unassociated Elastic IPs, load balancers with no targets, orphaned snapshots, idle NAT gateways, and long-stopped instances. Each finding carries the evidence that produced it (for example, how long a volume has been unattached).
Severity reflects confidence, not the size of the saving. A $4/month unassociated Elastic IP can be a high-severity finding if the evidence is unambiguous, while a $200/month idle NAT gateway might be lower severity if there’s a plausible reason it’s kept around (for example, a disaster-recovery VPC that’s meant to sit idle). Don’t read severity as a ranking of dollar impact — sort by the savings estimate itself if that’s what you need.
Dismissal is per (resource, rule) pair, not per resource: dismissing “unattached volume”
findings for a volume you’re intentionally keeping doesn’t suppress a different rule (say,
“orphaned snapshot”) that later fires on the same resource. A dismissal takes an optional note
and an optional expiry — set an expiry when the reason is temporary (for example, a
volume you’re keeping through the end of a migration) so the finding reappears once it passes.
Commitment utilization
Section titled “Commitment utilization”/commitment-utilization answers a third, distinct question from the two above: not “what should
you change” or “is this wasted”, but how much of what you’ve already bought is actually being
used. It covers AWS Reserved Instances and Savings Plans, and Azure Reservations.
It’s a small number of periodic snapshots — one row per commitment type per month — rather than an open-ended list. A commitment you bought at 100% intended utilization that’s now running at 60% is losing money on the unused 40%, and this page is where that shows up. It doesn’t recommend a fix; it reports the number.
Both savings recommendations and commitment utilization ride as a non-fatal extra step after
your normal cost sync. If Plutus’s access is missing a permission these need, your cost sync
still completes — you just see nothing on /savings or /commitment-utilization for that
account until the permission is granted.
Azure Reservations
Section titled “Azure Reservations”Azure reservation utilization needs two things beyond a working Azure cost connection:
- Billing Account ID filled in on the Azure connection — the same field credit-balance tracking uses. Without it, the reservation step is skipped. The Billing Profile ID is optional: if you enter one, it narrows the scope to that profile.
- Reservations Reader at billing scope, granted to the service principal Plutus connects with. This is genuinely broader than the subscription-scoped Cost Management Reader the rest of the Azure connection uses, because Azure keeps reservation utilization under the billing account rather than the subscription. Until it’s granted, the reservation step is skipped and cost sync is unaffected.
Two figures read differently for Azure than for AWS, because Azure’s utilization API reports percentages and hours and no dollar amount at all:
- Committed and unused amounts are derived, from each reservation order’s own purchase price spread across the hours it covers. They’re a reconstruction, not a number Azure quoted.
- Net savings isn’t reported for Azure. There’s no clean equivalent in what the API returns, so it’s left empty rather than estimated.
Azure savings plans (a separate, newer product from reservations) aren’t covered, and GCP isn’t covered on either commitment mechanism.
Commitment-expiration alerts
Section titled “Commitment-expiration alerts”A separate, calendar-driven alert: an under-utilized commitment approaching its end date. This one covers AWS Reserved Instances and Savings Plans, and Azure Reservations. The alert names the product, so an Azure reservation reads “Azure Reservation”, not “Reserved Instance”. Azure savings plans and GCP commitments aren’t covered.
Plutus checks once a day and alerts when a commitment is both:
- under 80% utilized, and
- exactly 30, 14, 7, or 1 days from its end date.
A commitment alerts at most once per threshold it crosses — four alerts across its final month at worst, not a daily reminder. Neither the 80% cutoff nor the threshold days are configurable.
Alerts go to whichever channels are subscribed to the account-wide Commitment expiring trigger, and appear on the timeline like any other event. See Budgets & alerts.
Three boundaries worth knowing:
- AWS end dates come from a different pair of AWS APIs than the utilization page uses
(
DescribeReservedInstancesandDescribeSavingsPlans) — the utilization APIs carry no per-commitment identity or end date at all. That needs two IAM permissions,ec2:DescribeReservedInstancesandsavingsplans:DescribeSavingsPlans, which aPlutusCostReaderrole deployed before this shipped doesn’t have. Re-apply the current Terraform module or CloudFormation template to pick them up. As everywhere else on this page, a missing permission degrades quietly and never fails your cost sync. - Azure expiration alerts need the same setup as Azure reservation utilization — the Billing Account ID on the connection and Reservations Reader at billing scope. Plutus tracks end dates without it, but an alert needs a utilization figure, so without the Billing Account ID no alert fires.
- A commitment with no resolvable utilization figure is skipped, not alerted on. An “expiring, utilization unknown” alert would be guessing.
- The check matches the threshold day exactly. If the daily run doesn’t happen on the exact day a commitment is 30 days out, that one alert is missed — the 14, 7, and 1-day thresholds still fire normally.
Credits & burn-down
Section titled “Credits & burn-down”Where a cost source has a credit balance (a startup program grant, a prepaid commitment, a promotional credit), Plutus tracks balance, burn rate, and projected exhaustion date per cost source.
Credits are shown beside spend, not netted into it — your cost charts show gross spend, and the credit balance is a separate figure next to it. Budget and overage enforcement also counts gross spend; a credit balance doesn’t pause an alert or budget threshold.
A runway that can’t be computed is absent, never zero or infinite. If there isn’t enough burn-rate history to project an exhaustion date, or the balance figure itself isn’t available, the runway simply doesn’t render — it’s not shown as “0 days remaining” (which would read as an emergency that isn’t real) or as no limit at all (which would hide a real one).
Price catalogue & what-if
Section titled “Price catalogue & what-if”GET /api/prices and GET /api/prices/compare serve an effective-dated catalogue of list
prices, refreshed weekly for the regions your connected accounts actually spend in, up to 12.
Coverage is deliberately narrow: AWS EC2 and RDS, and Azure virtual machines. GCP Compute Engine
prices are imported only where Plutus has GCP pricing access configured, so don’t assume a GCP
price will be present.
A comparison across incompatible units, price types, or currencies doesn’t guess at an answer —
it returns comparable: false with a reason. Comparing an hourly on-demand rate in USD against
a monthly reserved rate in EUR isn’t a single number you can trust, so Plutus doesn’t produce
one.
What this doesn’t do
Section titled “What this doesn’t do”Every mechanism on this page is read-only advice. Plutus never resizes an instance, cancels a reservation, deletes an unattached volume, or purchases a commitment on your behalf. Automated remediation is a deliberate absence, not a gap waiting to be filled — granting write access to a customer’s cloud account is a trust position Plutus doesn’t ask for.