FinOps Sentinel
GitHubAn autonomous AWS cost agent that scans for wasted spend, prices it, explains it, and deletes it, but only after a human approves in Slack.
By the numbers
- 9
- detection rules
- 8
- scanners per region
- 96%
- test coverage
- 294
- tests
- 6.4k
- lines of source
- 0
- deletions without approval
Currently building
In progress · August 2026
Currently packaging the agent for real deployment: Terraform modules for the IAM roles, scan schedule, and Slack webhook secrets, and a Kubernetes deployment splitting the scanner into a CronJob and the approval API into a long-running Deployment. The goal is an account owner running one apply instead of following a setup document.
Architecture
Detection is automatic. Deletion requires a named human.
Overview
FinOps Sentinel is an event-driven AWS cost optimization agent. It scans accounts across regions for wasted spend, prices each finding in real monthly dollars, explains it in plain language, and remediates it, with a human approval step standing between detection and deletion.
Nine detection rules cover the waste that accumulates quietly: unattached EBS volumes, orphaned Elastic IPs, long-stopped EC2 instances, expired snapshots, abandoned multipart uploads, plus advisory-only rules for idle instances, idle and stopped RDS databases, and S3 buckets with no lifecycle policy. Rules that can act do; rules that rely on inference stay advisory and never render an approve button.
Every finding is posted to Slack as an interactive Block Kit message with the evidence, the estimated monthly saving, and the exact action proposed. Approve triggers the remediation playbook, which snapshots an EBS volume before deleting it and records the snapshot ID as the recovery path. Requests are verified against Slack's signing secret with a 5-minute replay window, and the domain re-checks every guardrail at click time rather than trusting the state the button was rendered with.
Safety is layered rather than assumed: a `finops:protected=true` tag excludes a resource from notification and remediation entirely, dry-run mode is the default, a state machine makes each finding decidable exactly once regardless of click timing, and undecided findings expire themselves after 72 hours. A local Ollama model writes the human-readable summary but never gates a decision, so an unreachable or misbehaving LLM degrades to a deterministic template instead of blocking the pipeline.
The codebase is built on hexagonal architecture: the domain layer holds the rules, guardrails, and state machine as pure Python with no boto3, no SQLAlchemy, and no Slack SDK, while AWS, SQLite, Slack, and Ollama sit behind ports as interchangeable adapters. The whole approve-and-remediate flow runs end to end in tests against in-memory fakes, which is what keeps 96% coverage meaningful rather than decorative.
Why It Matters
Cloud waste is not an event, it is accumulation. A terminated instance leaves its boot volume behind, still billing. An Elastic IP outlives the migration it was reserved for. A staging database gets stopped rather than deleted, and keeps billing for allocated storage. Each item is individually too small to chase, and together they are the line on the bill nobody can account for.
Detection is the easy half. An unattached volume is one API call from obvious. The hard part is acting on it, because deleting infrastructure in a live account means the cost of one wrong deletion dwarfs months of savings. So tooling splits into dashboards that report waste and leave the work to a human, and automation that acts confidently enough to cause an incident.
FinOps Sentinel takes the third path: automate the tedious 95%, and put a named human on the irreversible 5%. Every deletion is approved by a person, attributed to their Slack handle, preceded by a snapshot, and recorded with the evidence that justified it. That audit trail is a compliance artifact as much as an engineering one.
Stack
Python 3.11+ · boto3 · SQLAlchemy · Alembic · FastAPI · Typer · Slack Block Kit · Ollama · pytest (96% coverage) · mypy strict · Ruff