
From "Do I need rainwater harvesting?" to a monsoon-checked system, serverless on AWS.
How we turned Delhi's rainwater rules, ten years of real rainfall and a photo of a dirty filter into one plan a homeowner can act on, built with AWS Lambda, Amazon Bedrock, Amazon Location Service and DynamoDB.
A 120 m² roof in Lodhi Road
Take one ordinary house in central Delhi: a 120 m² concrete roof on a 150 m² plot, four people, and a water bill of ₹900 a month.
In an average year about 72,000 litres of rain land on that roof and run off it, which is roughly seven water tankers. Most of it goes into the street drain. Because the plot is over 100 m², Delhi's rules say this house must have a rainwater harvesting system. If it doesn't, the Delhi Jal Board can add a penalty to the water bill. If it does, the owner can get financial help to build one and a rebate on the bill every year.
When we asked homeowners about it, almost none could answer the first questions:
- Is it mandatory for my house?
- What should I build, and how big?
- What will it cost me after the subsidy?
- How do I apply?
- How do I know it still works next July?
The last question matters most. Surveys of cities that made harvesting mandatory found that a large share of the systems people built stopped working. Around 55% were reported non-functional in Bengaluru and 70–80% defunct in Faridabad. A pit full of silt or a filter blocked by leaves looks the same from the street as one that works.
Boond (बूँद, "drop") is our answer. A homeowner or RWA secretary types an address, outlines the roof on a map, answers four questions, and in about 30 seconds gets:
- whether harvesting is mandatory for them;
- the structure to build and its exact size;
- the cost after assistance and the payback period;
- a pre-filled application PDF.
After the build, a phone photo of the filter or pit is checked by a vision model before every monsoon, with an email reminder when it's due.
The problem is follow-through, not information
The rules are public and the engineering is standard, yet harvesting fails at three points: deciding what to build, filling in the application, and keeping the system working once nobody checks it.
So Boond doesn't stop at one answer. It follows each plan through its whole life:
Plain text
planned → applied → installed → verified ⇄ needs_attention
Architecture: one journey, ten Lambda functions
Boond is fully serverless and defined in one AWS SAM template. The React + Vite frontend uses Leaflet and Geoman to draw the roof and
@turf/area to measure it. It's hosted on AWS Amplify and calls an API Gateway HTTP API, backed by ten Python 3.12 Lambda functions on arm64:Step | Lambda | AWS services and data |
|---|---|---|
Find the house | Geocode | Amazon Location Service (Esri), Nominatim fallback |
Get the plan | Plans | Open-Meteo rainfall archive, DynamoDB |
Read the rules | Rules | delhi_rules.json, structures.json |
Ask "what if…?" | Agent | Amazon Bedrock (Nova Lite) via Strands Agents SDK |
Apply | Application | reportlab PDF → S3, presigned link |
Officer review | Review | OpenStreetMap Overpass, DynamoDB cache |
Photo check | Maintenance | S3 presigned upload → Bedrock Converse vision |
Remind | Reminders | EventBridge Scheduler → SNS email |
Ward view | Wards, Dashboard | Overture footprints, DynamoDB GSI |

Splitting the work into one function per job gives each its own IAM role: only Agent and Maintenance can call Bedrock. It also lets each function have its own timeout. The Agent gets 1 GB and 29 s, and Reminders gets 120 s. All state lives in one DynamoDB table: a plan, its photo checks and its chat share one partition key, and a ward/status GSI powers the dashboard.
The calculations
Every number below comes from two JSON config files, not from code.
1. Rain on this roof
Plain text
key = RAIN#<lat, lon rounded to 2 dp> (≈ 1 km cell)cache hit → use itelse → Open-Meteo: daily rainfall for the last 10 full yearsannual_mm = average of the 10 yearly totals; cache the annual figure AND the daily seriesfailure → 750 mm Delhi default, labelled "default"
2. Runoff, tankers, compliance
One millimetre of rain on one square metre of roof is one litre.
Plain text
litres_per_year = roof_m2 × annual_mm × coefficient (RCC 0.80 · tin 0.85 · tiles 0.75)tankers = litres_per_year ÷ 10,000mandatory = plot_m2 ≥ 100 (the plot, not the roof)
3. What to build, and how big
A structure overflows during a heavy burst, so it's sized for one design storm rather than the whole year: 60 mm/h for 15 minutes.
Plain text
storm_litres = roof_m2 × 15 mm × coefficientOpen ground AND recharge safe here?├─ yes → roof ≤ 300 m² → RECHARGE PIT 3 m deep; side = √(storm_m3 ÷ 3), rounded UP to 0.1 m, kept within 1–2 m; ₹3,500/m³│ roof > 300 m² → RECHARGE TRENCH 1 m × 1.5 m; length = storm_m3 ÷ 1.5, rounded UP to 0.5 m (min 2 m); ₹3,000/m³└─ no → STORAGE TANK smallest of 1k/2k/3k/5k/10k L ≥ max(storm_litres, people × 20 L × 3 days)+ first-flush filter, ₹8,000, on every system
"Recharge safe" comes from three questions:
- Is there a septic tank, soak pit or sewer line nearby?
- Does the street waterlog?
- Is the only open ground next to the foundation?
Any yes switches the plan to a tank, because pushing water into the ground there risks contaminating groundwater or damaging the building. Not sure keeps the pit but adds a warning. We cite no setback distances because we couldn't verify an official figure.
Roof | Storm | Structure | Size | Install cost |
|---|---|---|---|---|
120 m² | 1,440 L | Pit | 1.0 × 1.0 × 3.0 m (0.69 m → min 1.0) | ₹18,500 |
300 m² | 3,600 L | Pit | 1.1 × 1.1 × 3.0 m (1.095 → 1.1) | ₹20,705 |
400 m² | 4,800 L | Trench | 3.5 × 1.0 × 1.5 m (3.2 → 3.5) | ₹23,750 |
1,500 m² | 18,000 L | Trench | 12.0 × 1.0 × 1.5 m | ₹62,000 |
4. The money
Plain text
assistance = min(₹50,000, 50% × install cost)you pay = install cost − assistancerebate = bill × 12 × 10% per yearpenalty avoided = bill × 12 × 50% per year, only if mandatorytanker savings = tankers bought × ₹4,500 per yeartank water = litres used ÷ 1000 × ₹50/kL (tanks only)payback = you pay ÷ yearly benefit ("no payback" if 0)
The worked example
Step | Calculation | Result |
|---|---|---|
Rainfall | Open-Meteo 10-year average | 752.1 mm |
Water a year | 120 × 752.1 × 0.8 | 72,202 L (7.2 tankers) |
Mandatory? | 150 ≥ 100 | Yes |
Design storm | 120 × 15 × 0.8 | 1,440 L |
Pit | √(1.44 ÷ 3) = 0.69 → min 1.0 | 1.0 × 1.0 × 3.0 m, 3,000 L |
Install | 3 m³ × ₹3,500 + ₹8,000 | ₹18,500 |
Assistance | min(50,000, 9,250) | ₹9,250 |
You pay | | ₹9,250 |
Benefit | ₹1,080 rebate + ₹5,400 penalty avoided | ₹6,480/yr |
Payback | 9,250 ÷ 6,480 | 1.4 years |
If the same house has no open ground, it gets a 2,000 L tank: ₹24,000 to install, ₹12,000 to pay, and a 1.9-year payback.
5. The number that looked right but wasn't
Our first version said "72,202 litres saved a year". That's how much rain falls, not how much a system keeps. Delhi's rain arrives in a few heavy monsoon days, a tank holds only so much, and a pit soaks only so much in a day. So Boond now replays ten years of real daily rainfall through the recommended structure:
Plain text
each day: inflow = mm × roof × coefficientpit/trench: kept = min(inflow, capacity × 3) # drains and refills ~3× a day (labelled assumption)tank: fill up to capacity, overflow the rest; household draws people × 20 L a day
The replay showed two things:
- A pit almost never overflows. At Lodhi Road it takes 9,000 L a day, which is only exceeded on a day above 93.75 mm. On 31 July 2024, 116 mm fell. The roof produced 11,136 L, the pit kept 9,000 L, and 2,136 L overflowed. That was one day in years.
- A tank keeps far less than the headline. Four people drawing 80 L a day can use at most 29,200 L a year, under 40% of what falls on the roof, and less in practice. One 50 mm day sends 4,800 L at a 2,000 L tank, and 2,800 L overflows at once.
So Boond recommends recharge first wherever it's safe, and values tank water only at what the household actually uses.
Rules belong in config, not in code
Delhi's rules have changed several times since 2001. If the ₹50,000 cap were hard-coded in Python, every rule change would mean a redeploy. Instead the calculator is made of pure functions, and every threshold, fraction, price, coefficient and assumption lives in
delhi_rules.json or structures.json .Each policy value records its source, URL and the date we checked it (7 October 2026). The file also states that the DJB's own PDFs weren't reachable at the time. Moving Boond to another city means writing a new rules file, not a new app.
An agent that can only touch one plan
Homeowners ask questions like "what if I only have a small backyard?" or "सब्सिडी कितनी मिलेगी?" ("how much subsidy will I get?"). The assistant runs Amazon Nova Lite on Bedrock through the Strands Agents SDK.
It never sees a plan ID or a database client. Its six tools are closures created for one plan:
-
get_plan,explain_rulesandmaintenance_tipsonly read data.
-
recalculatepreviews a change without saving it.
-
save_plan_changesandgenerate_applicationrun only after the user says yes.
The system prompt sets five rules:
- State only numbers that come from a tool.
- Act first: call
recalculateinstead of asking clarifying questions.
- Ask before saving anything.
- Reply in the user's language.
- Always say to confirm subsidy, rebate and penalty with the Delhi Jal Board.
What fought back: Nova Lite sometimes sent
"openSpace": "true" as a string. Strict validation rejected it, and the agent got stuck apologising in a loop. Typed tool parameters plus a small coercion step fixed it. If Bedrock is unavailable, the Lambda returns a friendly 503 and doesn't save the question.
The photo check: a vision model with a strict contract
Before each monsoon, a daily EventBridge Scheduler rule wakes the Reminders Lambda. It emails, through SNS, every installed system that's due for a check.
The homeowner's photo is downscaled in the browser to a 1,600 px JPEG at quality 0.85. It's uploaded straight to S3 through a 15-minute presigned URL, then sent to Bedrock Converse at temperature 0 with a prompt that asks for one JSON object only:
json
JSON
{"component": "filter", "verdict": "needs_cleaning","reason": "Dry leaves are covering the filter mesh.", "confidence": 0.85}
The parser assumes the model can be wrong. It extracts the first
{…} , checks the verdict against four allowed values and clamps the confidence. If the reply is unusable, it retries once, then returns unclear .Plain text
unclear OR confidence < 0.6 → "please retake" (nothing changes)healthy AND taken at the house → verifiedneeds_cleaning / broken → needs_attention + a specific fix tip
"Taken at the house" means within 150 m of it, plus up to 100 m of GPS uncertainty, using browser location or EXIF GPS. The photo must also be less than 15 minutes old. That stops anyone verifying a system with a photo from the internet.
In testing, a clogged gutter came back
needs_cleaning (0.9) and a restaurant photo unclear . A verified system earns a "Boond Verified" certificate with a QR code that links to its live status.For installed systems, Boond also replays real daily rain since installation. It counts nothing on the days between a failed check and the next healthy one. A missed cleaning shows up as litres lost this monsoon.
From one roof to a whole ward: the ward officer’s view
Boond’s second user is the ward officer, the Jal Board or municipal official responsible for rainwater harvesting in one ward. Today that job is mostly paper: forms, site visits, and no way to say how many required buildings actually harvest. Boond gives them two screens.
1. The application queue. Every filed application lands in that ward’s queue, newest first. The officer sees the roof outline, plot, residents, recommended structure, any site-safety flags, the cost after assistance and the PDF.
What a form never shows is where the water will go. So Boond pulls real ponds and lakes within 2 km and drains within 600 m from OpenStreetMap Overpass (cached per ~100 m cell for a week) and suggests a destination: recharge on site if safe, else the nearest pond, else the storm drain, else storage and reuse.
The officer picks the destination on the map and records approved, site visit needed or rejected. The last two require a note. The decision appears on the homeowner’s plan straight away and is kept in its review history.
2. The ward dashboard and “simulate monsoon.” This answers *how much of this ward’s rain are we actually catching?*Boond loads Overture Maps building footprints for five Delhi wards, colours each roof by the litres it could harvest, marks it required if the footprint is at least 100 m², and overlays every Boond plan by status.
The officer then picks any past date, and Boond replays that day’s real rain over every roof:
- Installed or verified systems keep up to capacity × 3; the rest overflows.
- Systems flagged “needs attention” lose all their runoff, because a broken system catches nothing.
- Unbuilt or unplanned buildings send all their runoff to the drains.
On 31 July 2024 that meant 116 mm at Lodhi Road and about 280 mm over parts of east Delhi. The screen shows litres kept today beside litres kept if every required building harvested. The gap is the officer’s enforcement case for one real storm, and it shows where to act first: broken systems, and large required roofs with no plan.
Every Delhi roof already collects rainwater, and most of it goes into the drain. Boond tells each house what to build, gets the application filed, and checks every monsoon that the system still works.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article