agentleFS
AWSKnown publisheraws/tools-for-devops-agent/skills/eos-cost-analysis/SKILL.md

eos-cost-analysis

Skill137 starsChanged 10 days agoApache-2.0View on GitHub

Use this skill whenever a user asks about End of Standard Support (EOS)

The file

Show its rules and text

We split this skill into the rules it gives an agent

28 rules. About 0 are common, 22 are distinctive, and 6 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈22

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    NEVER guess or estimate EOS dates — always verify from AWS documentation, per exact engine + version

    line 80
  2. Distinctive:

    NEVER reuse one version's EOS date for another version, even within the same service — verify each version independently

    line 81
  3. Distinctive:

    NEVER fabricate pricing rates — retrieve live rates from the AWS Pricing API (Step 3.2)

    line 82
  4. Very specific:

    When calling the Pricing API, ALWAYS extract only pricePerUnit — never dump the full PriceList (responses are very large)

    line 83
  5. Very specific:

    If a version's EOS date is not found, mark it UNVERIFIED and set the dependent fields as in references/billing-rules.md, section 6

    line 84
  6. Distinctive:

    All output is AI-generated and must be independently verified before taking action

    line 85
  7. Distinctive:

    Read-only operations only — do not modify any resources

    line 86
  8. Distinctive:

    If user specifies a service (e.g., "EKS EOS") → analyze that service only

    line 93
  9. Distinctive:

    If user says "all services" or "full EOS analysis" → analyze all 5 supported services

    line 94
  10. Distinctive:

    If unclear, ask: "Which service would you like me to analyze?

    line 95
  11. Distinctive:

    If user says "only this account" or specifies an account ID → limit to that account

    line 101
  12. Distinctive:

    If user specifies regions → use those

    line 104
  13. Distinctive:

    Large-scope warning: if the scope is large (e.g., >10 accounts, or all services × all regions × many accounts), add a heads-up that this …

    line 111
  14. Distinctive:

    Default behavior: all services, all associated accounts, all regions — proceed WITHOUT asking, unless the user narrows it.

    line 112
  15. Very specific:

    PAGINATION (MANDATORY): All discovery APIs paginate.

    line 120
  16. Very specific:

    Look up the vCPU count for each instance class using documentation search (verify_aws_claim) or the AWS Pricing API product attributes

    line 164
  17. Distinctive:

    If an instance class is not in this list, verify its vCPU count rather than guessing

    line 166
  18. Distinctive:

    After discovery completes, present a summary that makes COVERAGE provable — a reader must be able to confirm every discovery path actually …

    line 215
  19. Distinctive:

    Search AWS documentation for the EXACT engine + version combination discovered (e.g., the specific engine family AND version number as …

    line 233
  20. Distinctive:

    Search AWS documentation: "[service] version lifecycle" / "[service] supported versions calendar"

    line 234
  21. Distinctive:

    Verify the EOS date for EACH distinct version SEPARATELY.

    line 238
  22. Distinctive:

    If two versions appear to have the same EOS date, double-check — identical dates across clearly different versions/engines is a red flag …

    line 241
  23. Distinctive:

    If documentation search returns no result for a specific version:

    line 247
  24. Distinctive:

    Do NOT substitute a similar version's date as a proxy

    line 250
  25. Very specific:

    Use verify_aws_claim (or AWS documentation search): "[service] upgrade from [version] to latest"

    line 325
  26. Very specific:

    Every cost uses one formula (references/billing-rules.md, section 1): monthly_cost = billed_units_per_hour × es_rate × 730.

    line 354
  27. Distinctive:

    Every affected resource has TWO cost figures.

    line 372
  28. Distinctive:

    If deprecated Lambda runtimes were found:

    line 480

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

EOS Cost Analysis

Discover AWS resources approaching End of Standard Support, calculate Extended Support charges, and generate an actionable cost-impact report.

When to Use This Skill

  • User asks about End of Support cost exposure, Extended Support charges, or version-deprecation cost
  • User wants to know which resources are incurring or will incur Extended Support charges
  • User wants an EOS cost or inventory report / posture assessment across accounts
  • User wants a cost-impact report for deprecated service versions
  • Proactive scheduled checks for EOS posture across the organization

This skill scopes the EOS cost and inventory picture. It is not an upgrade-execution skill — for EKS pre-upgrade readiness and upgrade planning, use eks-upgrade-readiness; for OpenSearch domain health beyond version lifecycle, use analytics-opensearch-expertise.

Supported Services (Phase 1 — Extended Support Charges)

ServiceBilling UnitDiscovery API
Amazon EKSPer cluster/houreks:ListClusters, eks:DescribeCluster
Amazon RDS/AuroraPer vCPU/hour per billed instance; per ACU-hour for Aurora Serverless v2rds:DescribeDBInstances, rds:DescribeDBClusters
AWS LambdaNo direct ES charge (security risk only)lambda:ListFunctions
Amazon ElastiCachePer node/hour (Redis OSS v4–v6 only)elasticache:DescribeCacheClusters, elasticache:DescribeReplicationGroups, elasticache:DescribeServerlessCaches
Amazon OpenSearchPer Normalized Instance Hour, or equal to instance cost during an extension periodopensearch:ListDomainNames, opensearch:DescribeDomain

Which resources are billed, in what unit and how many units are defined in references/billing-rules.md. Follow it for every classification and cost.

IAM prefix note: the use_aws calls above use opensearch because that is the correct API client name, but the corresponding IAM actions live under the es: prefix (es:ListDomainNames, es:DescribeDomain, es:DescribeDomains). The AIDevOpsAgentAccessPolicy managed policy already grants the discovery actions for all five services.

Extended Support Pricing

Pricing is ALWAYS retrieved live from the AWS Pricing API (pricing:GetProducts) — see Phase 3, Step 3.2. The API is the single source of truth; the rates below are a validation reference only (sanity-check the API result against them; never substitute them for the API value).

Validation reference rates (us-east-1)

ServiceYear 1-2 rateYear 3 rateBilling unitTier behavior
EKS$0.50/cluster/hour$0.50/cluster/hourper cluster/hourFlat — no Year 3 escalation. This is the ES premium on top of the $0.10 standard cluster cost.
RDS$0.10/vCPU/hour$0.20/vCPU/hourper vCPU/hourYear 3 = 2× Year 1-2
Aurora Serverless v2$0.085/ACU-hour for Aurora PostgreSQL 13—per ACU-hourRead the Yr3 usagetype when it applies
ElastiCache$0.165/node/hour for cache.r6g.large (rate depends on node type, e.g. $0.054 for cache.t3.medium)$0.330/node/hour for cache.r6g.largeper node/hourYear 3 = 2× Year 1-2
OpenSearch$0.0065/NIH (m7g.medium.search = 2 NIH per hour); during an extension period, the instance's own hourly price (m7g.medium.search $0.068)—per NIH or per instance-hourNo Year 3 escalation
Lambda———No Extended Support charge (deprecated runtimes are a security risk only)

After Year 3, AWS may force-upgrade the resource. Cost framing: these rates represent the AVOIDABLE Extended Support premium (what the customer eliminates by upgrading). For EKS, the $0.50/hour is the ES surcharge on top of the $0.10 standard cluster cost the customer pays regardless — report the premium as the cost exposure/savings opportunity, not the standard cost.

Prerequisites

  • Discovery APIs (listed per service above) and the CloudWatch metric reads for Aurora Serverless v2 usage are covered by the AIDevOpsAgentAccessPolicy managed policy
  • The Pricing API actions pricing:GetProducts, pricing:GetAttributeValues and pricing:DescribeServices for live Extended Support pricing, granted by the EnableEosCostAnalysis parameter of the skill-policies CloudFormation template
  • For organization-wide analysis: resources across all associated accounts (via Agent Space cloud source associations)
  • For EOS date validation and upgrade guidance: verify_aws_claim or AWS documentation search

Constraints

  • NEVER guess or estimate EOS dates — always verify from AWS documentation, per exact engine + version
  • NEVER reuse one version's EOS date for another version, even within the same service — verify each version independently
  • NEVER fabricate pricing rates — retrieve live rates from the AWS Pricing API (Step 3.2)
  • When calling the Pricing API, ALWAYS extract only pricePerUnit — never dump the full PriceList (responses are very large)
  • If a version's EOS date is not found, mark it UNVERIFIED and set the dependent fields as in references/billing-rules.md, section 6
  • All output is AI-generated and must be independently verified before taking action
  • Read-only operations only — do not modify any resources

Phase 1: Scope Definition

  1. Identify target service(s) from the user request:
    • If user specifies a service (e.g., "EKS EOS") → analyze that service only
    • If user says "all services" or "full EOS analysis" → analyze all 5 supported services
    • If unclear, ask: "Which service would you like me to analyze? (EKS, RDS, Lambda, ElastiCache, OpenSearch, or all)"
  2. Determine account scope:
    • Default: ALL associated accounts — Scan resources in ALL AWS accounts connected to this Agent Space (primary + all secondary cloud sources)
    • The agent has access to multiple accounts through its cloud source associations — discover resources in EACH account, not just the primary
    • To identify available accounts: attempt resource discovery in all accounts the agent has access to. The Agent Space configuration determines which accounts are available.
    • If user says "only this account" or specifies an account ID → limit to that account
  3. Determine region scope:
    • If user specifies regions → use those
    • Otherwise → scan all commercially available regions
    • Optimization: first check which regions have resources for the target service using a quick List call in each region
  4. State scope and estimate scan size, then proceed (do NOT block on a prompt):
    • Announce: "Analyzing [service(s)] across [N accounts] in [regions]."
    • Estimate scan size before starting: roughly services × accounts × regions List calls (plus per-resource Describe calls). Report the rough magnitude so the user knows what to expect.
    • Large-scope warning: if the scope is large (e.g., >10 accounts, or all services × all regions × many accounts), add a heads-up that this may take a while and involve hundreds of API calls — but still proceed automatically.
    • Default behavior: all services, all associated accounts, all regions — proceed WITHOUT asking, unless the user narrows it. Only the scope announcement and size estimate are required; no confirmation gate.

Phase 2: Resource Discovery

For each account and region in scope, call the appropriate service APIs.

PAGINATION (MANDATORY): All discovery APIs paginate. You MUST follow pagination tokens to retrieve ALL resources — never rely on the first page. Continue calling with the NextToken / Marker / nextToken until no token is returned:

  • lambda:ListFunctions → NextMarker (default page size 50)
  • rds:DescribeDBInstances / rds:DescribeDBClusters → Marker
  • eks:ListClusters → nextToken
  • elasticache:DescribeCacheClusters → Marker
  • elasticache:DescribeReplicationGroups → Marker
  • elasticache:DescribeServerlessCaches → NextToken
  • opensearch:ListDomainNames → returns all in one call (no pagination)

Under-counting due to skipped pages is a correctness failure. Always exhaust pagination.

EKS Discovery

use_aws: eks:ListClusters (region: <region>)
→ For each cluster name:
  use_aws: eks:DescribeCluster (name: <cluster_name>, region: <region>)
  → Extract: clusterName, version, arn, createdAt

Record: account_id, region, cluster_name, cluster_arn, kubernetes_version

RDS Discovery

RDS Extended Support applies to both standalone RDS instances AND Aurora clusters. Query BOTH APIs — Aurora version/engine data comes from the cluster API, not the instance API.

use_aws: rds:DescribeDBInstances (region: <region>)   # standalone RDS + Aurora member instances
→ For each instance:
  → Extract: DBInstanceIdentifier, Engine, EngineVersion, DBInstanceClass,
             MultiAZ, DBInstanceArn, DBClusterIdentifier,
             ReadReplicaSourceDBInstanceIdentifier

use_aws: rds:DescribeDBClusters (region: <region>)    # Aurora clusters (authoritative engine version)
→ For each cluster:
  → Extract: DBClusterIdentifier, Engine, EngineVersion, DBClusterArn,
             DBClusterMembers (instance identifiers)

Filter: In scope are the engines and major versions on the RDS and Aurora Extended Support pages (references/billing-rules.md, section 2): today mysql, postgres, aurora-mysql and aurora-postgresql. Other engines (mariadb, oracle-*, sqlserver-*) have no Extended Support charge or Pricing API usagetype, so list them in the discovery summary as out of scope and do not price them. Billed instances: Count every instance on an affected version (primary, standbys, readable standbys, read replicas) by deployment shape, per references/billing-rules.md, section 3. A Multi-AZ DB instance adds one unlisted standby; cluster members, Aurora included, are listed individually and are never doubled. For Aurora, use the cluster's EngineVersion as the authoritative version (instance-level version may lag). A db.serverless instance is priced in ACU-hours (section 5), not vCPUs. Record: account_id, region, resource_id, engine, engine_version, instance_class, multi_az, cluster_id, read_replica_source, billed_instances, arn

Instance class to vCPU mapping (required for cost calculation):

  • Look up the vCPU count for each instance class using documentation search (verify_aws_claim) or the AWS Pricing API product attributes
  • Common mappings: db.t3.micro=2, db.t3.small=2, db.t3.medium=2, db.r5.large=2, db.r5.xlarge=4, db.r5.2xlarge=8, db.r5.4xlarge=16, db.r6g.large=2, db.r6g.xlarge=4, db.r6g.2xlarge=8
  • If an instance class is not in this list, verify its vCPU count rather than guessing

Lambda Discovery

use_aws: lambda:ListFunctions (region: <region>)
→ For each function:
  → Extract: FunctionName, Runtime, FunctionArn, LastModified

Filter: Include functions whose runtime is deprecated or approaching deprecation. Do NOT pattern-match against a hardcoded runtime list — deprecated runtimes change frequently. Instead, collect the DISTINCT set of runtimes in use, then verify each one's deprecation status at runtime via documentation search (verify_aws_claim: "AWS Lambda [runtime] deprecation date" / "AWS Lambda runtime deprecation schedule"). Flag any runtime that is past its deprecation date or has a deprecation date within 6 months. Record: account_id, region, function_name, runtime, arn, last_modified

ElastiCache Discovery

use_aws: elasticache:DescribeCacheClusters (region: <region>, ShowCacheNodeInfo: true)
→ For each cluster:
  → Extract: CacheClusterId, Engine, EngineVersion, CacheNodeType, NumCacheNodes, ARN

use_aws: elasticache:DescribeReplicationGroups (region: <region>)   # for clustered/replicated deployments
→ Extract group-level engine version where applicable

use_aws: elasticache:DescribeServerlessCaches (region: <region>)    # ElastiCache Serverless — SEPARATE resource type
→ For each serverless cache:
  → Extract: ServerlessCacheName, Engine, MajorEngineVersion, FullEngineVersion, ARN

Serverless caches are a distinct resource type — they are NOT returned by DescribeCacheClusters. You MUST call DescribeServerlessCaches separately so every cache is accounted for. Serverless uses MajorEngineVersion / FullEngineVersion (there is no node type / node count), and the Pricing API has no Extended Support usagetype for serverless caches, so never price one as nodes (references/billing-rules.md, section 2). Filter: Discover all engines, but only Redis OSS v4, v5 and v6 have Extended Support (references/billing-rules.md, section 2). Valkey and Memcached are out of scope: list them in the discovery summary as supported, with no charge. Record (node-based): account_id, region, cluster_id, engine, engine_version, node_type, num_nodes, arn Record (serverless): account_id, region, serverless_cache_name, engine, engine_version, is_serverless=true, arn

OpenSearch Discovery

use_aws: opensearch:ListDomainNames (region: <region>)
→ For each domain name:
  use_aws: opensearch:DescribeDomain (DomainName: <name>, region: <region>)
  → Extract: DomainName, EngineVersion, ARN, and every node group in ClusterConfig:
             InstanceType/InstanceCount, DedicatedMasterType/Count, WarmType/Count

Engine family split (date-bleed risk): EngineVersion comes back prefixed as either OpenSearch_2.x or Elasticsearch_7.x. These are TWO different engine families with COMPLETELY different EOS calendars — an OpenSearch version's EOS date must never be applied to an Elasticsearch version, or vice versa. Parse the prefix, treat Elasticsearch_* and OpenSearch_* as separate engines during EOS validation (Phase 3), and verify each independently. The Pricing API usagetype may also differ between the two families — resolve it per family, don't assume one covers both. Record: account_id, region, domain_name, engine_family (OpenSearch|Elasticsearch), engine_version, node groups (type and count each), arn

Discovery Summary

After discovery completes, present a summary that makes COVERAGE provable — a reader must be able to confirm every discovery path actually ran, even when it found nothing chargeable:

  • APIs called per service — explicitly confirm which discovery APIs were invoked, especially the ones that are easy to skip: elasticache:DescribeServerlessCaches, elasticache:DescribeReplicationGroups, rds:DescribeDBClusters. If an API was not called for a region, say so.
  • Total resources found per service (count of ALL discovered, not just affected).
  • Every discovered resource must be accounted for, including SUPPORTED ones. Do NOT silently drop supported resources — list them (at minimum a per-service, per-engine count of SUPPORTED resources) so the reader can tell "scanned and supported" apart from "never scanned". A bare "12 supported" with no breakdown is not acceptable.
  • Unique versions detected (with counts) and their classification.
  • Accounts and regions with resources.

This visibility is what lets a reviewer distinguish a genuine clean result (e.g., serverless caches found but on supported engines) from a coverage gap (serverless never queried). The final report (Phase 5) MUST carry this through: include a "Discovered but SUPPORTED (no charge)" section listing those resources or per-engine counts.


Phase 3: EOS Classification and Pricing Validation

Step 3.1 — Validate EOS Dates

For each unique version discovered, verify its End of Standard Support date independently:

  1. Search AWS documentation for the EXACT engine + version combination discovered (e.g., the specific engine family AND version number as reported by the discovery API — do not generalize).
  2. Search AWS documentation: "[service] version lifecycle" / "[service] supported versions calendar"
  3. Extract: eos_date (end of standard support), es_end_date (end of extended support)

CRITICAL — Per-version verification (avoid date bleed):

  • Verify the EOS date for EACH distinct version SEPARATELY. Never reuse one version's date for another version, even within the same service.
  • Many AWS services have MULTIPLE engine families or generations with completely different lifecycles (for example, a service may have a legacy engine line and a newer engine line that share a console but have separate support calendars). Treat each engine family + version as its own lookup.
  • Match the EOS date to the EXACT version string returned by discovery. If discovery returns an engine name and a version number, both must match the documentation entry you cite.
  • If two versions appear to have the same EOS date, double-check — identical dates across clearly different versions/engines is a red flag that a date was incorrectly copied.

Sanity checks before accepting an EOS date:

  • Does the date make chronological sense given the version's release date? (Older versions should have earlier EOS dates than newer ones of the same engine.)
  • Is a version that is clearly several generations behind the current release being reported as "supported with a future EOS date"? If so, re-verify — it may already be past EOS.

If documentation search returns no result for a specific version:

  • Mark as UNVERIFIED and set the dependent fields per references/billing-rules.md, section 6
  • Note in the report: "EOS date could not be confirmed from AWS documentation — verify manually"
  • Do NOT substitute a similar version's date as a proxy

Step 3.2 — Get Extended Support Pricing (AWS Pricing API)

Use the AWS Pricing API (pricing:GetProducts) for authoritative, real-time Extended Support pricing. Do NOT use documentation search or model knowledge for pricing.

CRITICAL — Response size: The Pricing API returns large JSON. ALWAYS use the exact usagetype patterns below and extract ONLY pricePerUnit. Never dump the full PriceList into context.

Pricing API constraints:

  • Region: call the Pricing API in us-east-1 (its endpoint region)
  • Requires pricing:GetProducts and pricing:GetAttributeValues (plus pricing:DescribeServices for the empty-result fallback below)
  • The regionCode filter targets the region you're pricing for (e.g., us-east-1), separate from the API endpoint region

Per-service pricing lookup:

ServiceServiceCodeUsage Type PatternRegion PrefixBilling UnitYear 3
EKSAmazonEKS{PREFIX}-AmazonEKS-Hours:extendedSupportYes, in every region (USE1- in us-east-1)per cluster/hourFlat (no escalation)
RDSAmazonRDS{PREFIX}-ExtendedSupport:Yr1-Yr2:{EngineVersion} / {PREFIX}-ExtendedSupport:Yr3:{EngineVersion}; Aurora Serverless v2 adds ASv2 (references/billing-rules.md, section 5)None in us-east-1, prefixed elsewhere (USW2-, EU-, APS3-...)per vCPU/hour; per ACU-hour for ASv22× Yr1-2
ElastiCacheAmazonElastiCache{PREFIX}-ExtendedSupportYr1_Yr2-NodeUsage:{nodeType} / {PREFIX}-ExtendedSupportYr3-NodeUsage:{nodeType}Yes, in every region (USE1- in us-east-1)per node/hour2× Yr1-2
OpenSearchAmazonES{PREFIX}-OpenSearchExtendedSupport (NIH mode); {PREFIX}-ESInstance:{type} (extension-period mode, references/billing-rules.md, section 4)None in us-east-1, prefixed elsewhere (EU-, APS3-...)per NIH/hour or per instance-hourSingle tier (no escalation)
Lambda—No Extended Support charge———

Whether us-east-1 carries a prefix depends on the service, so never assume. Checked against the live Pricing API:

  • RDS and OpenSearch have NO prefix in us-east-1 (ExtendedSupport:Yr1-Yr2:MySQL8.0, OpenSearchExtendedSupport) and a prefix in every other region (APS3-ExtendedSupport:Yr1-Yr2:MySQL8.0, EU-OpenSearchExtendedSupport). Outside us-east-1 the bare form returns 0 products, which would silently turn the resource into PRICING_UNAVAILABLE or $0.
  • EKS and ElastiCache carry a prefix everywhere, USE1- in us-east-1.
  • RDS {EngineVersion} is the engine plus its major version, not the bare engine: MySQL8.0, MySQL5.7, PostgreSQL13, AuroraMySQL2, AuroraMySQL3, AuroraPostgreSQL13. Build it from the discovered Engine and major EngineVersion, and confirm it with pricing:GetAttributeValues. If no usagetype exists for that engine and version, mark the cost PRICING_UNAVAILABLE instead of guessing.

Region prefix mapping (EKS, RDS, ElastiCache, OpenSearch):

The AUTHORITATIVE way to get the region prefix is the Pricing API — do NOT rely on a hardcoded prefix for any region you are not certain about. For ANY region outside the common set below, call pricing:GetAttributeValues on the usagetype attribute (filtered by ServiceCode) and match the prefix for your target regionCode. This is the DEFAULT method, not a fallback, and it applies to every service.

Common prefixes (safe to use directly; still verify via API if a lookup returns empty). These apply to every service except where the list above says there is no prefix in us-east-1:

  • us-east-1 → USE1 | us-east-2 → USE2 | us-west-1 → USW1 | us-west-2 → USW2
  • eu-west-1 → EU (not EUW1, which returns nothing) | eu-west-2 → EUW2 | eu-central-1 → EUC1
  • ap-northeast-1 → APN1 | ap-southeast-1 → APS1 | ap-southeast-2 → APS2
  • ca-central-1 → CAN1 | sa-east-1 → SAE1

Regions you MUST resolve via the API (prefixes vary / are not reliably guessable — includes ap-south-1, eu-north-1, eu-south-1, me-south-1, af-south-1, ap-east-1, and any region not listed above): call pricing:GetAttributeValues and read the actual usagetype prefix rather than guessing. Never construct a usagetype from an unverified prefix — a wrong prefix silently returns empty and causes a resource to be under-costed as $0.

Lookup procedure per affected resource:

  1. Build the usagetype string using the pattern + region prefix + resource attribute (engine version / node type as applicable). Take the prefix from the rules above: none for RDS and OpenSearch in us-east-1, USE1- for EKS and ElastiCache in us-east-1, and for any other region resolve it via pricing:GetAttributeValues (do not guess). For example ExtendedSupport:Yr1-Yr2:AuroraMySQL2 in us-east-1 but USW2-ExtendedSupport:Yr1-Yr2:AuroraMySQL2 in us-west-2.
  2. Call pricing:GetProducts:
    use_aws: pricing:GetProducts (
      region: "us-east-1",
      ServiceCode: "<ServiceCode>",
      Filters: [
        {Type: "TERM_MATCH", Field: "usagetype", Value: "<constructed usagetype>"},
        {Type: "TERM_MATCH", Field: "regionCode", Value: "<target region>"}
      ]
    )
    Apply a jmespath_filter at the API call to return ONLY the price, so the large PriceList JSON never enters context. Pricing API returns each product as a JSON-encoded string in PriceList; filter/parse down to the pricePerUnit.USD value inside the on-demand price dimensions rather than pulling the whole payload. Filtering at the call level is more reliable than asking the model to extract it afterward.
  3. Extract ONLY pricePerUnit.USD and the price dimension's unit (for example vCPU-hour, ACU-hour, Hrs) — ignore everything else. The unit decides what you count in Phase 4 (references/billing-rules.md, section 1)
  4. If the exact usagetype returns empty, call pricing:GetAttributeValues for the usagetype attribute to discover the correct format, then retry. If it is still empty, use pricing:DescribeServices to confirm the ServiceCode and the exact attribute names for that service before constructing another GetAttributeValues/GetProducts call — a wrong ServiceCode or attribute name also returns empty.

Validate the returned rate against the reference table in the Extended Support Pricing section (us-east-1 validation reference). The API result is authoritative — the table is only a sanity check. If the API rate is wildly different from the reference (orders of magnitude), re-check the usagetype before trusting it; never replace the API result with the reference number.

Step 3.3 — Classify Each Resource

Compare each resource's version against the validated EOS dates:

StatusConditionInclude in Report?
IN_EXTENDED_SUPPORTEOS date is past, ES end date is futureYES — currently incurring charges
APPROACHING_EOSEOS date is within 6 months from todayYES — will soon incur charges
PAST_EXTENDED_SUPPORTBoth EOS and ES end dates are pastYES — critical, may be force-upgraded
SUPPORTEDEOS date is more than 6 months away, or the engine is out of scopeNO — exclude from cost report (list in the discovery summary)
UNVERIFIEDNo EOS date confirmed for the exact engine and versionYES — listed separately, kept out of the totals

Step 3.4 — Search Upgrade Recommendations

For each affected version:

  1. Use verify_aws_claim (or AWS documentation search): "[service] upgrade from [version] to latest"
  2. Extract: recommended target version, key breaking changes, migration guide URL

Phase 4: Cost Calculation

Step 4.1 — Determine pricing tier

Extended Support pricing tiers are based on how long a resource has been past End of Standard Support. The tier structure differs by service:

  • Calculate months since EOS: months_since_eos = (today - eos_date).months
  • Year 1-2 — months_since_eos < 24 (months 0–23 past EOS): base rate
  • Year 3 — months_since_eos >= 24 (month 24 onward past EOS): elevated rate

Boundary is exclusive at 24: month 23 is still Year 1-2, month 24 is the first Year 3 month. No month falls in both tiers.

Tier behavior by service (rates themselves come from the Pricing API; see the validation reference table):

  • EKS: flat — no Year 3 escalation
  • RDS: Year 3 = 2× Year 1-2
  • ElastiCache: Year 3 = 2× Year 1-2 (per node, varies by node type)
  • OpenSearch: single tier — no escalation

Use the exact rate returned by the Pricing API for the resource's tier (Step 3.2). Query the Yr3 usagetype pattern for resources 24+ months past EOS.

When the Year 3 usagetype is not yet published: for a resource whose Year 3 window starts in the future (e.g. it is currently in Year 1-2 but will cross 24 months later), the Yr3 usagetype may not exist in the Pricing API yet and will return empty. This is expected, not a lookup failure — do NOT mark it PRICING_UNAVAILABLE. Use the current Year 1-2 rate for the current cost, and for the Year 3 projection derive it from the service's documented escalation (RDS and ElastiCache: 2× the Year 1-2 rate; EKS and OpenSearch: no escalation, so Year 3 = Year 1-2). Clearly label such a projected Year 3 figure as derived (not API-returned) and note the date the Year 3 rate begins.

Step 4.2 — Calculate per-resource monthly cost

Every cost uses one formula (references/billing-rules.md, section 1): monthly_cost = billed_units_per_hour × es_rate × 730. es_rate is the per-tier rate the Pricing API returned for the resource (Step 3.2), never a hardcoded value, and billed_units_per_hour is counted in that rate's unit:

Servicebilled_units_per_hour
EKS1 per cluster
RDS / Aurora provisionedvCPUs of the instance class × billed instances (section 3): one standby added for a Multi-AZ DB instance, read replicas counted, cluster members (Aurora included) each counted once and never doubled
Aurora Serverless v2Average ACUs consumed (CloudWatch ServerlessDatabaseCapacity, section 5), else USAGE_DEPENDENT
ElastiCacheNodes on Redis OSS v4–v6
OpenSearchNIH mode: Σ node groups of instance_count × normalization factor from the section 4 table (medium = 2, large = 4, xlarge = 8, …). Extension-period mode: instances, at the instance type's own hourly rate
Lambda0 (flag as security risk only)

Notes:

  • The EKS ES rate is the Extended Support premium (the avoidable cost). The standard cluster cost applies regardless and is NOT part of the exposure.
  • For RDS, map instance class to vCPU count (e.g., db.r6g.xlarge = 4 vCPUs).
  • For OpenSearch, take the charge mode for the version and date from section 4, and never derive a normalization factor from instance count or by extrapolation.

Step 4.2b — Reactive (current) vs Proactive (projected) cost

Every affected resource has TWO cost figures. Compute both so the report shows what the customer pays now AND what they will pay if they do nothing:

  • Current monthly ES cost (reactive) — what the resource is incurring RIGHT NOW.
    • IN_EXTENDED_SUPPORT / PAST_EXTENDED_SUPPORT: the Year 1-2 or Year 3 rate from Step 4.2. This is real spend today.
    • APPROACHING_EOS: $0 — not yet in Extended Support, incurring nothing today.
  • Projected monthly ES cost (proactive) — what the resource WILL cost once it enters Extended Support, if not upgraded first.
    • APPROACHING_EOS: compute the full Year 1-2 ES cost using the SAME per-resource formula (Step 4.2), as if it were already in ES. This is the cost that starts on its EOS date (within the next 6 months).
    • IN_EXTENDED_SUPPORT / PAST_EXTENDED_SUPPORT: projected = current (already incurring). If the resource will cross into Year 3 (>= 24 months) within the projection window, project the Year 3 (elevated) rate and note the escalation.
    • UNVERIFIED, PRICING_UNAVAILABLE and USAGE_DEPENDENT resources: set the fields per references/billing-rules.md, section 6; keep them out of the totals and count them separately.

This split is the whole point of the skill: reactive = stop the bleeding on resources already in ES; proactive = show the cost cliff approaching in the next 6 months so the customer can upgrade before it hits. Report both, never collapse them into one number.

Step 4.3 — Assign urgency

UrgencyCondition
CRITICALIN_EXTENDED_SUPPORT or PAST_EXTENDED_SUPPORT (already incurring charges)
HIGHAPPROACHING_EOS within 3 months
MEDIUMAPPROACHING_EOS within 3–6 months
UNVERIFIEDUNVERIFIED status (no confirmed EOS date): verify manually

Step 4.4 — Aggregate totals

Calculate:

  • Total current monthly ES cost (reactive) — sum of current cost across resources already in/past ES (excludes APPROACHING_EOS, which is $0 now)
  • Total current annual ES cost (current monthly × 12)
  • Total projected monthly ES cost (proactive) — sum of projected cost across ALL affected resources (includes APPROACHING_EOS at their future ES rate). This is the monthly run-rate if nothing is upgraded in the next 6 months.
  • Incremental cost cliff — projected monthly − current monthly = the additional spend that switches on as APPROACHING_EOS resources cross their EOS dates
  • Top 10 most impacted accounts (by projected monthly cost)
  • Cost by service breakdown (current and projected)
  • Cost by urgency breakdown
  • Not in totals: counts of UNVERIFIED, PRICING_UNAVAILABLE and USAGE_DEPENDENT resources, each listed

Phase 5: Report Generation

Step 5.1 — Present Summary

## EOS Cost Impact Summary

| Metric | Value |
|--------|-------|
| Current Monthly ES Cost (incurring now) | $X,XXX |
| Current Annual ES Cost | $XX,XXX |
| Projected Monthly ES Cost (if no upgrades in next 6 mo) | $X,XXX |
| Incremental Cost Cliff (projected − current) | $X,XXX/month |
| Affected Resources | N |
| Affected Accounts | N |
| Services Analyzed | [list] |
| Regions Scanned | N |

### By Urgency
- CRITICAL: N resources — $X,XXX/month (currently incurring charges)
- HIGH: N resources — $X,XXX/month (entering ES within 3 months)
- MEDIUM: N resources — $X,XXX/month (entering ES within 3-6 months)

### By Service
- EKS: N clusters — $X,XXX/month
- RDS: N instances — $X,XXX/month
- ElastiCache: N nodes — $X,XXX/month
- OpenSearch: N instances — $X,XXX/month
- Lambda: N functions — $0 (security risk, no ES charge)

### Top Impacted Accounts
1. [account_name] ([account_id]) — $X,XXX/month
2. ...

Step 5.2 — Generate CSV Artifact

Produce a CSV artifact with these columns:

  • account_id — AWS account ID
  • account_name — Account name (if available from Organizations)
  • resource_arn — Full ARN of the resource
  • resource_name — Human-readable identifier (cluster name, instance ID, function name)
  • region — AWS region
  • service — AWS service (EKS, RDS, Lambda, ElastiCache, OpenSearch)
  • version — Current version/engine version/runtime
  • instance_class — Instance type (for RDS, ElastiCache, OpenSearch) or N/A
  • billed_units — Billed units per hour and their unit (e.g. 12 vCPU-hour for 6 billed instances × 2 vCPUs, 8 NIH, 4 ACU-hour)
  • eos_date — End of Standard Support date, or UNVERIFIED
  • eos_status — IN_EXTENDED_SUPPORT / APPROACHING_EOS / PAST_EXTENDED_SUPPORT / UNVERIFIED
  • es_year — Which pricing year the resource is in: 1-2 or 3. For resources not yet in Extended Support (APPROACHING_EOS), use the sentinel N/A (they are not incurring ES charges yet, so no pricing year applies).
  • current_monthly_es_cost — Monthly ES cost being incurred RIGHT NOW ($0 for APPROACHING_EOS; the Year 1-2/Year 3 rate for resources already in/past ES)
  • projected_monthly_es_cost — Monthly ES cost once the resource enters Extended Support (full ES rate for APPROACHING_EOS; equals current for resources already in ES, or the Year 3 rate if it escalates within the window)
  • es_start_date — Date the projected cost begins (the EOS date for APPROACHING_EOS; blank/N/A if already incurring)
  • annual_es_cost — Annual ES cost based on projected_monthly_es_cost × 12 (the forward-looking run-rate)
  • urgency — CRITICAL / HIGH / MEDIUM / UNVERIFIED
  • recommended_target — Recommended upgrade version
  • upgrade_guide_url — Link to AWS migration documentation

Sort by projected_monthly_es_cost descending (surfaces the biggest future exposure first).

Title the artifact: "EOS Cost Impact Report — [date]"

Step 5.3 — Provide Upgrade Recommendations

For each affected version, include:

  • Current version → Recommended target version
  • Key considerations or breaking changes
  • AWS documentation link for the upgrade path
  • Estimated effort: mention sequential upgrade requirements if applicable

Step 5.4 — Lambda Security Risk Section (if applicable)

If deprecated Lambda runtimes were found:

## Security Risk: Deprecated Lambda Runtimes

These functions are running on deprecated runtimes that no longer receive
security patches. While no Extended Support charge applies, they represent
a security and compliance risk.

| Function | Runtime | Last Modified | Account |
|----------|---------|---------------|---------|
| ... | python3.8 | 2023-... | ... |

Error Handling

ErrorBehavior
Role assumption fails for a linked accountSkip that account, note in report: "Account [ID] skipped — role assumption failed"
Service API returns AccessDeniedSkip that service/region, note: "Insufficient permissions for [service] in [region]"
Documentation search returns no EOS dateMark version as UNVERIFIED (status, urgency and cost fields per references/billing-rules.md, section 6), include in report with note
Pricing API returns no product after the GetAttributeValues usagetype retrySet current_monthly_es_cost and projected_monthly_es_cost to "PRICING_UNAVAILABLE", do not estimate
No usage data for a usage-priced resource (Aurora Serverless v2)Set the cost fields to USAGE_DEPENDENT with the rate and capacity range
No resources found for a serviceReport: "No [service] resources found in scope"
Rate limiting (throttling)Retry with exponential backoff (1s, 2s, 4s), max 3 retries
Timeout on large organization (1000+ accounts)Report partial results, note which accounts were completed

Tips

  • Start with a single service for faster results — EKS is the simplest (flat per-cluster rate)
  • RDS has the most complex pricing due to vCPU mapping and counting every billed instance (standbys and read replicas)
  • Lambda has no cost impact but deprecated runtimes are a security risk worth flagging
  • Year 3 doubles the rate for RDS and ElastiCache (EKS and OpenSearch stay flat), so a resource 24+ months past EOS costs twice what it did in Year 1-2
  • Verify EOS dates from AWS documentation at runtime — deprecation schedules shift, so confirm each engine + version rather than trusting cached knowledge

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.