Cloud / FinOps

A FinOps agent for AWS cost optimization

An agent that finds the savings hiding in an AWS account: six read-only tools, no arithmetic delegated to the model, no ability to mutate anything.

Role
Design and development — personal project, public code
Period
July — August 2026
Tools, all read-only
6
IAM actions required
4
Cost arithmetic left to the LLM
0
  • Python
  • Strands Agents SDK
  • Amazon Bedrock
  • boto3
  • AWS CDK
  • pytest

github.com/mallow66/aws-finops-agent

Context

The costs of an AWS account drift naturally: instances sized generously at launch and never revisited, detached EBS volumes nobody remembers to delete, Elastic IPs allocated and never associated — billed all the same, since February 2024, at a flat rate per address. Detecting this waste is not hard, it is tedious: it means cross-referencing Compute Optimizer recommendations, the EC2 inventory, and the pricing API, then putting a figure on every case. Exactly the kind of work that slips from sprint to sprint.

That makes it good terrain for an LLM agent — crossing sources, reasoning, prioritizing, summarizing. It is also terrain where a badly designed agent is dangerous. This project, personal and with public code, serves both purposes: produce a cost diagnosis you can act on, and answer seriously the question of how you put an LLM agent in contact with infrastructure without inheriting its risks.

Constraint

The constraint is twofold, and each half shaped part of the design.

First, safety: a language model is sometimes wrong with great confidence. Giving write access on an AWS account to a non-deterministic system is not defensible. Safety could not rest on the quality of a prompt — it had to rest on what the agent is materially capable of doing.

Second, accuracy: a FinOps tool is only worth what its numbers are worth. An LLM produces plausible figures, not exact ones — and a saving announced wrongly costs more in credibility than it earns. The model therefore had to be prevented from ever computing anything.

Decisions

AGENTStrands Agents loop · Amazon Bedrockorchestrates, cross-references, prioritises — never calculatesSIX TOOLSDiscoveryget_rightsizing_recommendationsget_idle_resourcesPricingestimate_instance_costestimate_ebs_volume_costestimate_eip_costcompute_savings_summarydeterministic arithmetic, in code — never in the model4 IAM actions — all readsAWSCompute OptimizerEC2Price List
The agent's blast radius. All six tools exposed to the model are read-only, and the only monetary arithmetic happens in code: the model orchestrates and writes, it does not do the sums.

The first decision structures everything else: the agent is read-only by construction. Six tools are exposed to it — rightsizing recommendations via Compute Optimizer, detection of unattached EBS volumes and unassociated Elastic IPs, EC2 and EBS pricing via the Price List API, the cost of public IPv4 addresses, and a savings calculator — and none of them mutates anything. The IAM policy fits in four actions, all reads. The nuance matters: a denied permission can be bypassed by a configuration mistake; an absent capability cannot be invoked. The cost is accepted: the agent does not “fix” anything itself — remediation remains a human act, outside the system.

Second decision: no arithmetic is left to the model. The pricing tools return exact figures from the AWS API; a dedicated tool, in pure code, does the subtractions and the totals; the prompt explicitly forbids the model from calculating and requires it to label as “unpriced” anything it cannot put a figure on with the tools, rather than estimating from memory. The agent does not even trust Compute Optimizer’s precomputed savings: for every recommendation, it re-prices both the current instance type and the proposed one, and derives the exact difference from live pricing. Finally, the numbers in the report — savings table, chart, resource map — are re-derived in code, independently of the model’s prose. The model narrates; the code counts.

Third decision: the system can be developed without AWS and without an LLM. A mock mode serves data in the exact shape of real AWS responses, with mock/real parity enforced in the same place in every function. A --tools-only mode runs the whole pipeline — collection, pricing, report — without a single model call: that is what makes CI and demos possible. The logic lives in ordinary Python functions and the tool decorators are one-line wrappers, so the core of the system is tested like normal code, without mocking an LLM. The price: mocks to maintain as the APIs evolve. It is small next to the alternative — developing blind against real, billed resources.

Last decision, the least obvious one: testing against real AWS requires creating real waste, and that cost had to be bounded. A disposable CDK stack provisions exactly the minimal scenery the tools know how to detect — an idle instance, a volume never attached, an IP never associated — with a budget alert and a one-command teardown. As for the foundation: Strands Agents on Amazon Bedrock by default, which keeps billing data inside the account’s AWS boundary; the model provider is an environment variable, not an architectural decision — the direct Anthropic API substitutes for Bedrock without touching the tools’ code.

Outcome

The agent runs in three modes — mock, tools-only, and full agent against a real account — and produces a Markdown report: a savings table per action, a chart, and a resource map colored by state. The report’s totals are reproducible to the cent without a model, which also makes them a check on the agent’s prose.

The code is public — the repository stands as proof for every claim on this page. What the project demonstrates: an LLM agent can produce a cost diagnosis worthy of trust, provided the architecture takes away from the model what it does badly — arithmetic, mutation — and leaves it what it does well — orchestrating tools, crossing data, and prioritized synthesis.