Azure Cost Calculator
Deterministic Azure cost estimation using the public Retail Prices API. Never guess prices — always query the live API via the scripts.
Runtime Detection
Choose the script runtime based on what is available:
| Runtime | Condition | Pricing script | Explore script |
|---|---|---|---|
| Bash (preferred) | curl and jq available | scripts/get-azure-pricing.sh | scripts/explore-azure-pricing.sh |
| PowerShell | pwsh available | scripts/Get-AzurePricing.ps1 | scripts/Explore-AzurePricing.ps1 |
Both produce identical JSON output. Bash flags use --kebab-case equivalents of PowerShell -PascalCase parameters (e.g., -ServiceName → --service-name).
Declarative Parameters
Service reference files specify query parameters as Key: Value pairs. To execute a query, translate each parameter to the detected runtime's syntax:
- •Bash:
--kebab-caseflags (e.g.,ServiceName: Virtual Machines→--service-name 'Virtual Machines') - •PowerShell:
-PascalCaseflags (e.g.,ServiceName: Virtual Machines→-ServiceName 'Virtual Machines')
String values with spaces require quoting when passed to scripts. Numeric values (Quantity, InstanceCount) do not.
Workflow
Phase 1 — Analysis (no API queries)
- •
Parse — extract resource types, quantities, and sizing from user's architecture
- •
Locate each service reference: a. File search — search for files matching
references/services/**/*<keyword>*.mdb. Category browse — if search returns 0 or ambiguous results, read the category index in references/shared.md c. Broad search — list or searchreferences/services/**/*.mdto see all available files d. Discovery — if no file exists, use the explore script to find the service in the API - •
Read matched service files; check
billingNeedsand follow dependency chains (e.g., AKS → VMs → Managed Disks) - •
Classify each parameter using the Disambiguation Protocol in shared.md:
- •Specified — user provided value (use verbatim)
- •Never-assume gap — required parameter missing (must ask)
- •Safe-default gap — optional parameter missing (use default, disclose)
- •
Specification Review — present a summary:
Service Specified Missing (will ask) Defaults (will assume) - •If any never-assume parameter is missing → ask user before proceeding
- •If only safe-default gaps remain → disclose defaults and proceed to Phase 2
- •Single-service shortcut: skip this table for single-service estimates where all parameters are specified
Phase 2 — Estimation
- •Query — run the pricing script for each service using parameters from service files + user input + resolved defaults
- •Calculate — apply cost formulas from service files; multiply by quantities
- •Present — output the estimate with:
- •Assumptions block (see Disambiguation Protocol in shared.md) — listed before cost numbers
- •Line items: service, unit price, quantity/hours, monthly cost
- •Grand total: re-sum all line-item monthly costs independently; if discrepancy, use re-summed value
Post-Estimate Iteration
After presenting the estimate, the user may request changes (switch region, add RI, resize instances, add/remove services). Re-run only the affected queries — do not restart the full workflow.
Reference Index (load on demand)
| Condition | Read |
|---|---|
| Always (entry point) | references/shared.md — constants, category index, alias lookup |
| Query returned 0 results or wrong data | references/pitfalls.md — troubleshooting and traps |
| User asks about Reserved Instances or savings plans | references/reserved-instances.md |
| Non-USD currency or non-eastus region | references/regions-and-currencies.md |
| User requests private endpoints or private access — confirm PE intent with user | references/services/networking/private-link.md — PE pricing, references/services/networking/private-dns.md — DNS zone pricing |
| Category Index + file search both failed | references/service-routing.md — full 140+ service map |
| First time running scripts or unfamiliar with parameters | references/workflow.md — script parameters and output formats |
Critical Rules
- •Never guess prices — always run the script against the live API
- •Infer currency and region from user context — if unspecified, ask the user or default to USD and eastus
- •Ask before assuming — if a required parameter is ambiguous or missing (tier, SKU, quantity, currency, node count, traffic volume), stop and ask the user
- •Default output format is Json — never use Summary (invisible to agents)
- •Lazy-load service references — only read files from
references/services/directly required by the user's query. Use the file-search workflow (Step 2) to locate specific files. - •PowerShell: use
pwsh -File, notpwsh -Command— on Linux/macOS, bash strips OData quotes from inline commands - •Use consistent output categories — group line items by category directory names from
references/services/(compute, databases, networking, etc.) - •Scope to user-specified resources — only include resources explicitly stated in the user's architecture. Companion resources from
billingNeedsare included automatically.
Service File Metadata
YAML front matter fields. Optional fields use default elision — omitted means the default applies.
| Field | Required | Default | Action |
|---|---|---|---|
billingNeeds | — | omit | Read and price listed dependency services |
billingConsiderations | — | omit | Ask user about listed pricing factors before calculating |
primaryCost | ✔ | — | One-line billing summary for quick cost context |
apiServiceName | — | omit | Use instead of serviceName in API queries |
hasMeters | — | true | false → skip API, use Known Rates table |
pricingRegion | — | regional | global → Region: Global; api-unavailable → skip API; empty-region → omit region |
hasKnownRates | — | false | true → file contains manual pricing table |
hasFreeGrant | — | false | true → apply free grant deduction from Cost Formula |
privateEndpoint | — | false | true → aggregate PE costs via networking/private-link.md |
Universal Traps
These apply to EVERY query:
- •
serviceNameand all filter values are case-sensitive — use exact values from service reference files - •Unfiltered queries return mixed SKU variants — always filter with
productName/skuNameto the specific variant needed - •Multi-meter resources need separate queries — run one query per meter with
-MeterName
Batch Estimation Mode
When estimating 3 or more services, use these rules to reduce token consumption:
- •Partial reads — read only lines 1–45 of each service file (YAML front matter, trap, first query pattern).
- •Front matter routing — use YAML metadata to skip unnecessary work:
- •
hasMeters: false/pricingRegion: api-unavailable→ skip API; use Known Rates orprimaryCost - •
pricingRegion: global→Region: Global;empty-region→ omit region - •
apiServiceName→ use instead ofserviceNamein queries - •
hasFreeGrant: true→ apply grant deduction;privateEndpoint: true→ add PE line item
- •
- •Full read triggers — no query pattern in partial read, non-default config, 0/unexpected results, or
billingConsiderationsapplies. - •Parallel queries — run independent service queries in parallel.
- •Skip redundant references — read shared.md and pitfalls.md once at the start, not between services.
- •Progressive distillation — after each service query returns, emit a summary row before proceeding:
| Category | Service | Resource | Unit Price | Unit | Qty | Monthly Cost | Notes |Multi-meter services get one row per line item. After all queries complete, assemble the final estimate from the accumulated rows. Do not re-read service files already distilled unless a full read trigger is needed. During Post-Estimate Iteration, replace the distillation row(s) for any re-queried service.