Build an Autonomous Cost Anomaly Remediation Agent with Claude API
Detecting a cloud cost spike is the easy part. Build an agent that investigates the anomaly, identifies the specific orphaned resource or misconfiguration causing it with Claude API, and safely remediates the low-risk cases automatically.
Cost anomaly detection tools are common now — they tell you spend jumped 40% yesterday. What they don't do is tell you why, and by the time a human investigates, three more days of the same waste have accumulated. This agent closes that loop: detect, diagnose, and remediate the safe cases automatically.
The Investigation Problem
A cost spike alert tells you almost nothing actionable on its own:
Alert: AWS spend increased 42% ($3,200/day) starting 2026-07-27
Finding the actual cause means cross-referencing Cost Explorer, CloudTrail, and resource inventories — a 20-30 minute investigation a human does manually, every time, for alerts that are often the same handful of root causes repeating.
Diagnosis Agent
import anthropic
import boto3
import json
from datetime import datetime, timedelta
client = anthropic.Anthropic()
ce = boto3.client("ce") # Cost Explorer
def get_cost_breakdown(days: int = 2) -> dict:
"""Pull cost by service, broken down by day, to spot what actually changed."""
end = datetime.utcnow().date()
start = end - timedelta(days=days)
response = ce.get_cost_and_usage(
TimePeriod={"Start": str(start), "End": str(end)},
Granularity="DAILY",
Metrics=["UnblendedCost"],
GroupBy=[{"Type": "DIMENSION", "Key": "SERVICE"}]
)
return response["ResultsByTime"]
def find_recent_resource_changes(hours: int = 48) -> list[dict]:
"""CloudTrail events that could explain a cost spike — new resources,
instance type changes, or anything a runaway script might have created."""
cloudtrail = boto3.client("cloudtrail")
start_time = datetime.utcnow() - timedelta(hours=hours)
events = cloudtrail.lookup_events(
LookupAttributes=[{"AttributeKey": "EventName", "AttributeValue": "RunInstances"}],
StartTime=start_time
)
# Repeat for other cost-relevant event names: CreateDBInstance, CreateVolume, etc.
return [{"event": e["EventName"], "time": str(e["EventTime"]), "user": e.get("Username")}
for e in events["Events"]]Claude Root Cause Analysis
DIAGNOSE_PROMPT = """A cost anomaly was detected. Diagnose the likely root cause.
Cost breakdown by service, last {days} days:
{cost_breakdown}
Recent resource creation events (CloudTrail):
{recent_events}
Identify:
1. Which service/resource type is driving the spike
2. The most likely specific cause (e.g. "forgotten dev instance running since
last Friday", "runaway auto-scaling from a bad HPA config", "a script
left NAT gateways provisioned in an unused VPC")
3. Whether this looks safe to auto-remediate (e.g. an obviously orphaned
resource with no traffic) or needs human judgment (e.g. could be
legitimate new production load)
Respond with ONLY valid JSON:
{{"likely_cause": "...", "affected_resources": ["..."], "safe_to_auto_remediate": true/false, "confidence": "high"|"medium"|"low"}}"""
def diagnose_anomaly(cost_breakdown: dict, recent_events: list) -> dict:
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=800,
messages=[{
"role": "user",
"content": DIAGNOSE_PROMPT.format(
days=2, cost_breakdown=json.dumps(cost_breakdown, indent=2)[:4000],
recent_events=json.dumps(recent_events, indent=2)[:2000],
)
}]
)
text = response.content[0].text.strip()
if text.startswith("```"):
text = text.split("```")[1].replace("json", "", 1).strip()
return json.loads(text)Remediation — Narrow, Reversible Actions Only
SAFE_REMEDIATIONS = {
"unattached_ebs_volume": "snapshot_then_delete",
"idle_load_balancer_no_targets": "delete",
"stopped_instance_over_30_days": "notify_only", # never auto-delete, just flag
"unused_elastic_ip": "release",
}
def remediate(diagnosis: dict):
if not diagnosis["safe_to_auto_remediate"] or diagnosis["confidence"] != "high":
notify_finops_channel(
f"Cost anomaly diagnosed but needs review: {diagnosis['likely_cause']}\n"
f"Affected: {diagnosis['affected_resources']}"
)
return
for resource in diagnosis["affected_resources"]:
resource_type = classify_resource(resource)
action = SAFE_REMEDIATIONS.get(resource_type)
if action == "snapshot_then_delete":
snapshot_id = create_snapshot(resource)
delete_volume(resource)
log_remediation(resource, f"Snapshotted as {snapshot_id}, then deleted")
elif action == "delete":
delete_resource(resource)
log_remediation(resource, "Deleted — no dependents found")
elif action == "release":
release_resource(resource)
log_remediation(resource, "Released")
else: # notify_only, or unrecognized type
notify_finops_channel(f"Flagged for manual review: {resource}")Why the Scope Stays This Narrow
Notice what's on the auto-remediate list: unattached volumes, idle load balancers with zero targets, unused elastic IPs — all reversible or trivially recreatable, all things that generate cost with provably zero traffic. Nothing on the list involves guessing whether a running, traffic-serving resource is "probably fine to remove." A stopped instance sitting idle for 30 days gets flagged, not deleted — someone might be about to restart it for a scheduled batch job. The agent's job is narrowing the investigation from 30 minutes to a diagnosis; the remediation scope is deliberately small enough that "auto" never means "risky."
# Every remediation gets logged with full context for audit
def log_remediation(resource: str, action: str):
audit_log.write({
"timestamp": datetime.utcnow().isoformat(),
"resource": resource,
"action": action,
"reversible": True,
"triggered_by": "cost-anomaly-agent-v1",
})More AI FinOps tooling? Read our Build AI cost allocation tagger with Claude API and Build AI AWS cost anomaly detector with Claude API.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
Build an AI AWS Cost Anomaly Detector with Claude API and Cost Explorer
Step-by-step tutorial to build an AI-powered AWS cost anomaly detector using Claude API and AWS Cost Explorer. Automatically identify unusual spending patterns, find the responsible service, and get plain-English explanations with fix recommendations.
Build an AI Cloud Cost Anomaly Detector with Claude API + AWS Cost Explorer
Cloud costs spike without warning. Build a Python bot using AWS Cost Explorer + Claude API that detects anomalies using Z-score analysis and explains the spike in plain English.
Build an AI Cost Allocation Tagger with Claude API
Build a tool that scans untagged or inconsistently tagged AWS resources, infers the correct team/project/environment tags from naming patterns and context, and opens a PR to apply them — closing the FinOps visibility gap without a manual tagging sprint.