Cloud governance, building materials
Cloud costs by owner, not by resource ID
A portal shows what cloud usage actually costs, broken down by the people and projects responsible. Shared resources are deliberately not charged to one project, even though that makes the savings look smaller.
- Year
- 2026
- Services
- Automation · Artificial intelligence
- Area
- Corporate IT
- Role
- In-house, employed
Delivered in an employed role for an internal department, not under an external consulting contract. The organisation is not named.
The situation
The project folder says nothing about it. No README, no requirements documentation, no commit message describing the original problem — the documentation that exists explains only the current state.
Inferable but not evidenced: the effort the code puts into attributing cost to owners — a two-level ownership model, flagging of unassigned resource groups, a rule engine for automatic attribution — suggests that this attribution was the problem. That is a supposition, and is named as one here.
The approach
Two separate applications over one shared database.
The collection layer is a Function App: 13 scheduled jobs and a queue trigger pull data on a staggered schedule — cost through the Cost Management API, resource inventory through Resource Graph, recommendations through Advisor, plus reservation coverage, orphaned resources and storage utilisation. Results land in around 25 tables.
The web layer is a Flask application with 80 routes. It reads exclusively from the database — across the entire application directory there is not a single call to an Azure management API. Pages therefore load from prepared data rather than live queries. When someone triggers a synchronisation manually, the web layer only writes a message to a queue; the Function App processes it.
Two analyses sit on top. Anomaly detection compares against a 14-day baseline, groups consecutive days into one event, suppresses repeat notifications after five days, and sorts by euro impact rather than statistical significance. The AI review produces a prioritised recommendation list per project; the response is validated against a schema through a forced tool call, not parsed freely.
Where it could have gone the other way
Shared resources are not charged to a single project — even though that makes the numbers look less useful.
An App Service Plan or a SQL server often serves several projects. The easy route would have been to attribute that resource’s full cost to the project. It would have produced large, tidy-looking savings opportunities — and it would have been wrong.
The code deliberately does the opposite: two separate cost views, per-resource costs explicitly
marked as upper bounds, and resources whose raw cost exceeds the project’s monthly total
automatically flagged as likely shared or misattributed. The system prompt instructs the model
to recommend “split the usage” in that case rather than “delete this and save X” — and to set
the estimate to null where no defensible figure is possible.
The same restraint sits in the reservation calculation: the list of reservable meters is a deliberately narrow allow-list, so savings estimates are not inflated by storage and network costs that cannot be reserved at all.
The decision costs impact in the presentation and buys trust in the number. For a tool whose only purpose is that somebody acts on it afterwards, that is the right trade.
The result
Around 19,000 lines across roughly 100 files, 80 routes, 25 tables, 14 background jobs, nine connected data sources. Built by one person over about a quarter, with a dense build phase followed by targeted performance work and its own index migration.
Deliberately bounded: the system changes nothing in Azure. There are no delete, stop or deallocate calls. “Implemented” is a status in the database — a person does the implementing. The AI recommends with confidence levels; at low confidence, user review is explicitly expected.
Stated openly: there are no automated tests. Savings figures are estimates based on a discount assumption held in code, not a quoted price. And attribution of shared resources remains imprecise — the system marks the problem, it does not solve it.
Stack
- Python / Flask
- Azure Cost Management API
- Azure Resource Graph
- Azure SQL
- Claude API
More projects
Sales & inside sales, construction chemicals
2026One orchestrator, three specialist agents for product questions
Instead of one agent with three knowledge sources, a parent agent routes to three specialists — one each for ERP article data, product content and SharePoint documents.
- Microsoft Copilot Studio
- Azure AI Search
- Azure Functions
- SharePoint
Supply chain, construction chemicals
2026Stock, replenishment and documents per article on one page
Around 334,000 article documents from the data warehouse and the product information system, rebuilt daily. Stock is derived from the movement log rather than the ready-made inventory view — which never reports a zero balance.
- Python
- Azure AI Search
- Azure Functions
- Databricks SQL
Sales / CRM, construction chemicals
2026Researching missing address data in CRM leads automatically
Without a postcode and town, an enquiry cannot be assigned to a sales territory. The system reads the address from the company website's legal notice — and deliberately writes nothing back to the CRM.
- Python
- Salesforce API
- Claude API
- httpx / BeautifulSoup
A similar process at your company?
30 minutes, free, no sales pitch. You describe what is costing you time — I tell you honestly whether automation is worth it.