AWS Builder Center
VayuGuard: Building an Honest AI Safety System on AWS

VayuGuard: Building an Honest AI Safety System on AWS

How I built a school air-quality safety system on AWS that turns raw AQI numbers into real scheduling decisions — and why I designed it to honestly surface every AI/data fallback instead of hiding them, for Environmental Hacks 2026.

VayuGuard: I Built an AI Safety System That Admits When Its AI Isn't Working

By Kanakaboina Ankith Raj — Environmental Hacks 2026 (WeMakeDevs x AWS), Air Track

The one-line pitch

Most air quality apps show you a number. VayuGuard shows a school principal exactly what to do about it — and tells the truth about whether that decision came from real AI or a safety-net fallback.
Upfront, honestly: Amazon Bedrock access on this AWS account is currently blocked by a new-account model restriction, confirmed three independent ways (detailed below) — not a code issue. The system runs correctly on its documented, clearly-labeled fallback instead. I'm telling you this in the second paragraph, not burying it, because that's the whole point of this project.

The problem

Every winter, North Indian schools face the same situation: the air quality index crosses into hazardous territory, and nobody tells the school what to actually do about it. Apps like SAFAR or AQI.in show a number — "AQI: 380" — and stop there. By the time a principal decides that's bad enough to cancel outdoor recess, the kids are usually already outside.
I built VayuGuard to close that gap: not another AQI display, but a system that converts a live reading into an actual decision — which periods move indoors, which stay as-is, and who gets notified.

What it does

VayuGuard ingests live AQI data for a school's location, evaluates it against the school's own daily schedule, and re-sequences outdoor-heavy periods (assembly, recess, PE) into indoor venues whenever the hazard threshold for that specific activity's exertion level is crossed. It then sends a real alert through Amazon SNS to staff and parents, and shows everything on a live dashboard.
Dashboard showing the AQI gauge + the LIVE badge


AWS architecture

Architecture Diagram

The system runs on two independent AWS paths:
  • A scheduled ingestion loop: Amazon EventBridge triggers an AWS Lambda function every 15 minutes, which pulls live AQI readings and writes them into Amazon DynamoDB — running in the cloud whether or not anyone has the dashboard open.
  • A public API: Amazon API Gateway fronts a second Lambda function (the full FastAPI backend, adapted with Mangum) that serves the React dashboard, hosted on AWS Amplify. This Lambda reads/writes DynamoDB, calls Amazon Bedrock (Nova Lite, via the model-agnostic Converse API) for schedule optimization, and dispatches alerts through Amazon SNS.
Everything is defined as code in a single AWS SAM template and deployed as one CloudFormation stack — one command builds it, one command deploys it.

The design decision I'm most proud of: honest fallbacks

Here's something most AI-pitched hackathon projects don't talk about: what happens when the AI call fails? Usually, the fallback quietly pretends nothing happened, and the demo just... works, without anyone knowing it wasn't really the AI.
I designed against that deliberately. In this AWS account, Bedrock model access turned out to be blocked by a new-account restriction — not a code or permissions issue. I verified this three separate ways: bare model ID, the inference-profile ID, and a completely separate IAM user with full  AmazonBedrockFullAccess  — all three returned the identical error:
Plain text
ValidationException: Operation not allowed
Rather than hide that, VayuGuard surfaces it everywhere:
  • The API response includes  live_ai: true/false  and the actual engine name — never mislabeled.
  • The dashboard shows a LIVE / CACHED / SIMULATED badge on every reading, so a stale fallback value is never presented as a fresh one.
  • The deterministic fallback that runs instead of Bedrock isn't a hardcoded special case. It's driven by each schedule period's own attributes:
Python
HAZARD_THRESHOLD_BY_INTENSITY = {
"Extreme": 300,
"High": 250,
"Moderate": 250,
"Low": 250,
"Sedentary": 350,
}
threshold = self.HAZARD_THRESHOLD_BY_INTENSITY.get(period.get("intensity", "Moderate"), 250)
if current_aqi >= threshold:
# relocate this period indoors
That's attribute-driven, not hardcoded to specific period IDs — it generalizes to any school's timetable, not just my sample one.
An air-safety tool that lies about its own confidence is worse than one that's simply honest about what's live and what isn't.

AWS lessons learned (the real debugging stories)

A few things that actually tripped me up, in case they save someone else time:
  1. DynamoDB wants  Decimal , not  float .  boto3 's resource API silently errors on raw Python floats ( "Float types are not supported. Use Decimal types instead" ). I hit this twice — once locally, once again in a Lambda I'd forgotten to patch the same way. Fix:  Decimal(str(value))  everywhere a float touches  put_item .
  1. IAM users have a 10-managed-policy limit per account by default. I hit  "The selected policies exceed this account's quota"  mid-build. The fix wasn't a quota increase — it was realizing one of my attached policies ( AdministratorAccess-Amplify ) didn't actually grant what I needed (that's scoped for Amplify's CLI backend/AppSync features, not plain Hosting), so I swapped it out for a precise custom policy instead of stacking up more.
  1. Some Bedrock models need an inference-profile ID, not the bare model ID.  amazon.nova-lite-v1:0  alone didn't work for on-demand invocation in some cases —  list_inference_profiles()  revealed the real ID was  us.amazon.nova-lite-v1:0 . (In my case, even that didn't unblock things — turned out to be a separate new-account restriction entirely — but it's a real gotcha worth checking first.)
  1. CORS wildcard + credentials is a trap.  allow_origins=["*"]  with  allow_credentials=True  doesn't work per the CORS spec — and I didn't even need credentials for this stateless API. Scoped the origins list down and turned credentials off entirely.

What's genuinely working right now

  • Real DynamoDB writes from real live AQI data
  • Real SNS alerts firing on genuine detected hazards (with a cooldown so it doesn't spam)
  • Full stack deployed on AWS — not just running on my laptop
  • 17 passing tests covering the response parsing, the fallback engine's hazard logic, and the alert cooldown

What I'd build next

The concrete next step isn't a wishlist — it's that the schema already supports it. DynamoDB's partition key is  STATION#<id> , not a school ID, so onboarding another school is adding a row to a schools table and pointing it at its nearest station — no redesign. Real Bedrock-driven optimization activates automatically the moment account access clears, with zero code changes. After that: a weekly "exposure budget" view per school using the AQI history already accumulating in DynamoDB.


Built solo for Environmental Hacks 2026.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article