Custom recommendation policies
Write your own recommendation from metrics. Pick the resources to watch, combine up to eight metric signals, choose what to recommend, and ZopNight raises and resolves the finding for you.
The built-in rule catalogue covers the patterns we see in every estate. When you want a threshold that’s specific to yours, write it yourself. A custom recommendation policy watches the resources you choose on the metrics you choose. When every signal holds, ZopNight raises a recommendation; when the signals clear, it resolves it.

Governance → Policies → Recommendation: policies with their scope, signals, decision, outcome, and status, plus starter templates.
You manage them at Governance → Policies → Recommendation. Their findings appear on the Recommendations page when you switch the System / Custom toggle to Custom.
Before you start
- Permission to manage policies. The built-in Editor and Admin roles have it; Viewer can only look. See Scopes.
- Metrics. Signals read the metrics ZopNight already collects, so the cloud account needs metrics read access (CloudWatch, Azure Monitor, or Cloud Monitoring). See Cloud permissions.
Start from a template
Under Templates on the list page there are five starting points (you see them only if you can create policies). Each one fills in the whole policy, ready to adjust:
| Template | Watches | Signals | Recommends |
|---|---|---|---|
| Idle databases | RDS tagged env=uat | average CPU below 5% and max connections at 0, over 7 days | Rightsize |
| Over-provisioned VMs | EC2 tagged env=prod | average CPU below 40%, average memory below 50%, and max CPU below 80%, over 30 days | Rightsize |
| Quiet dev servers | EC2 tagged env=dev | average CPU below 10% and average network out below 1 MB/s, over 14 days | Schedule |
| Idle load balancers | Load balancers | average network out below 0.5 MB/s, over 14 days | Custom (“needs-review”) |
| Over-provisioned databases | RDS tagged env=prod | average CPU below 30%, average connections below 10, and max CPU below 80%, over 30 days | Rightsize |
Create a custom recommendation
Click + Create, or pick a template, to open the New custom recommendation wizard. It has five steps.
Start
Name the policy (required, up to 120 characters) and optionally describe what it should catch.
Prefer to describe it in words? Fill with AI gives you a prompt to paste into any AI assistant. Paste the JSON it returns and click Fill from JSON to fill in the rest of the wizard.
Scope: which resources to watch
Choose Whole organisation or One cloud account (then pick the account). To limit it further, click + Narrow with a condition. All conditions must match:
- Resource types
- Cloud provider (AWS, GCP, Azure)
- Name (contains or equals)
- Database engine
- Purchase / lifecycle (on-demand, spot, low priority, preemptible, scheduled, capacity block)
- Tag key and value
With no conditions, the policy watches every resource in scope, and the wizard warns you.
Signals: what to watch
A signal reads like a sentence: average CPU utilization is below 5% over 7 days. Add up to 8. They combine with AND: every signal must hold for the policy to fire.
- Aggregation: average, max, min, p95, or p99. Max and min use the single highest or lowest hour in the window; p95 and p99 ignore the very highest spikes.
- Comparison: is below, is above, or equals (equals works only with max and min).
- Window: 1 to 90 whole days. Each cloud keeps a different amount of history: 90 days on AWS, 60 on Azure, 42 on GCP. A cloud’s resources show as not having enough data when your window is longer than that cloud keeps. Validate warns you about this only if you’ve limited the policy to one cloud account or to certain providers; with a whole-organisation scope it won’t warn (for example, a 60-day window still gets no data from GCP). If the window is longer than every cloud keeps, Validate stops you.
Metrics your scope can’t collect are marked (unavailable).
Outcome: what to recommend
Outcome Files under Savings shown Idle: the resource looks unused, stop it Idle Cost of the hours it sits unused Schedule: usage is predictable, schedule it Schedule Cost of the hours it sits unused Rightsize: the resource is over-provisioned Rightsizing The price difference to one size down Retire: orphaned or unattached, remove it Orphan The whole monthly bill Custom: name your own category (required, up to 40 characters) Your category None (a flag for review) A Rightsize outcome can’t use an is above signal.
Review
Check the summary, then click Validate. ZopNight checks the metrics are available for your scope and the windows fit each cloud’s history. Once it passes, click Create policy (or Save policy when editing).
New findings are severity medium. Templates, Fill with AI, the API, and the MCP tools can set a different severity.
When it runs
- New findings can appear whenever ZopNight refreshes a resource, and across all your resources straight after you create, edit, or turn on a policy. A finding is raised once, when its signals first all hold.
- Old findings are closed when a full check finds the signals have cleared or the resource is no longer in scope. That full check runs when you create, edit, or turn a policy on or off. A finding is also closed if its resource is deleted.
- Missing data never fires. A signal with no data counts as not holding.
A custom finding then behaves like a built-in one, with the same drawer and the same actions. See Recommendations.
How savings are kept honest
Savings on a custom finding follow the same rules as the built-in ones. When ZopNight can’t back up a dollar figure, it shows the finding as advisory with $0 savings and tells you why. This happens when:
- The metrics are stale: the newest data point is more than 48 hours old.
- There isn’t enough data yet: fewer days of data than the signal’s window, or fewer than 7 days for a max, min, p95, or p99 signal.
- It isn’t safe to shrink or stop: CPU peaks reach 80% or more even though the average is low, or memory use averages 50% or more.
- No quiet period has been seen yet: Idle and Schedule need ZopNight to have seen when the resource is actually unused.
- The resource holds data: Idle, Schedule, and Retire on a database or other stateful resource are always advisory. Rightsize is fine, which is why the database templates use it.
- The cost is unknown: the resource’s cost is $0 or ZopNight couldn’t determine it (“We couldn’t determine this resource’s cost”), for any outcome.
- There’s nothing smaller: a Rightsize where no smaller size is available, or where the current or smaller size can’t be priced.
Manage policies
The list shows each policy’s name, what it watches, its signals, the decision (for example A AND B), the outcome, and a Status switch. Click a row to see the full detail.
- Turn a policy off with its switch. Its open findings are closed; turn it back on and they’re raised again.
- Edit from the row menu. Saving re-checks your whole estate.
- Delete from the row menu. This can’t be undone, and the open findings it raised are closed.
From the API or an AI assistant
Developers can manage custom recommendation policies through the ZopNight API, where they’re called watch policies. If a policy was created there with a more complex scope, editing it in the app replaces that scope, and the wizard warns you first.
From an AI assistant, use the MCP server tools list_watch_policies, validate_watch_policy, create_watch_policy, and update_watch_policy.