Problem
Sawari is a rider-to-rider auto-rickshaw sharing app. One rider books an auto through any aggregator or off the street. Other riders whose pickup and drop lie along that route join the same auto, and the fare is split by the kilometres each rider actually shared. The driver never touches the app.
The v2 plan frames the job as three questions a commuter should be able to answer in one glance: is there an auto along my route in the next hour, can I trust the person whose auto it is and what should I do next, and will the fare be split fairly if someone does not turn up. Matching, trust and fare fairness are the product; everything else supports them.
I did not run user research for this build. No interviews or surveys are recorded in the repo; the framing comes from the design spec and the v2 plan.
Users
The intended users are commuters in Mumbai and Bangalore, in two roles. The owner books the auto, posts the ride and approves every joiner. The co-rider finds a ride along their route, requests a seat and settles their share with the owner. Drivers are deliberately not users.
There are no real users. The latest handover says Sawari has never run anywhere but localhost, and there is no environment an alpha tester could open. Everything below describes built behaviour, not observed use.
Decision
That removed a two-sided marketplace and live GPS in one move. The owner already books the auto, so the app only has to coordinate riders. Owner approval puts a person, not an algorithm, on the trust decision, and a seat is row-locked so it is never given to two riders. Hackmate, an earlier matching product, made a similar call: legible matching inputs over an opaque score.
The cost is speed and reach. A rider cannot hop on a moving auto, and matching is limited to rides someone has already posted. Seek commutes narrow that gap: a standing wish for a seat is matched the moment a ride is posted, with a push to each matched rider.
Trade-offs
The repo records these choices across matching, trust, fare fairness, verification, cancellation and disputes.
Fare fairness. The split has invariants checked by property tests: shares sum to the total, no share is negative, a rider on a superset of legs never pays less than one on a subset, and equal mode gives equal per-seat amounts. Money is integer paise, so there are no floats in fare maths. The v2 plan also fixed a fairness bug where the split billed riders who never showed: the owner now marks each joiner rode or no-show, and only riders who rode are counted.
Cancellation. Cancel reasons are a fixed list (auto not available, plans changed, running late, other, lapsed). Cancels and leaves inside 30 minutes of the window are flagged late and feed the trust chip.
Disputes. A rider marked no-show is told they can dispute through Report, and the report reasons include a fare dispute. How a dispute is resolved is not decided yet.
Two late rulings. I raised the ride cap from 25 km to 50 km of routed distance, because 25 km refused an everyday commute like Colaba to Powai while 50 km still refuses intercity runs. I chose an iOS install hint over an email notification leg, accepting that an iOS rider who dismisses the hint gets in-app notifications only.
What shipped
In the order a rider meets it:
Profile gate. A display name and phone are required before the first offer, join request or commute, not at registration.
Offer and find. The owner picks places, previews the route on a map, sets a time window and seats. A co-rider's search returns open rides covering both stops in route order, with walk minutes, ride kilometres and an estimated share.
Join. The co-rider requests, the owner approves or declines, and a waiting panel shows the request state. Every rider name carries a trust chip.
The ride. A ride room shows the lifecycle, one "what to do now" sentence per role and state, and live updates. Riders can say they are at the pickup or running late. A safety sheet links to the emergency contact and 112, and a revocable share link shows the trip to someone outside the app.
Fares and settlement. Per-city rate cards give an estimate, or the owner enters the aggregator amount. The split excludes no-shows, and settlement is a UPI link plus "I've paid" and "Mark paid".
Commutes and notifications. Repeat rides spawn nightly; seek commutes match within 20 minutes either side, with fan-out capped at 50 and no push between 22:00 and 06:30.
Under the hoodArchitecture and implementation
Structure
Ash domains for Accounts, Geo, Rides, Fares and Notifications, with boundaries enforced at compile time by the Boundary library. Every ride or membership change writes a RideEvent in the same transaction and broadcasts after commit. Oban workers lock rides, lapse them, spawn commutes, match seekers and send reminders.
Fare computation
legs = consecutive stop pairs, sorted by distance along the route
present = riders whose pickup is at or before the leg start
and whose drop is at or after the leg end
leg cost = (total + extras) * leg length / route length
share = leg cost * rider seats / seats present on that leg
remainder after rounding to whole paise goes to the owner
Geo and push providers sit behind behaviours with fakes, so tests never hit the network.
Validation
Validation is tests and local runs only. The last recorded gate, on 9 Sep 2026, reads 897 passed (33 doctests, 4 properties, 860 tests) across 93 test files, with credo --strict clean, no compiler warnings and the Ash codegen check passing.
One process lesson came from that session. Parallel lanes were told to verify each queued finding from the code before implementing it, and four of the seven queued items had premises that did not survive that check.
The limits are plain. The manual test script has never been hand-run; the click-through that passed was automated. No tester, rider or owner has used the app.
Limits and next
Status: locally built, not deployed. Render plus Neon is the planned free hosting and render.yaml exists, but nothing is deployed. The alpha gate is mostly deployment work:
- Deploy on Render and Neon, with production push keys and host set. Nothing exists yet.
- Verify a Brevo mail sender. Without it, sign-up succeeds but confirmation, magic-link and reset mails silently never arrive.
- Add Google OAuth credentials.
- Check the seeded 2026-09-01 tariffs against current Mumbai and Bangalore transport authority notices, because the app quotes real money.
- Confirm the trusted-proxy setting on first real traffic, so rate limits are not shared by every visitor.
- Decide on error tracking; there is none today.
- Hand-run the manual test script after rewriting its obsolete ride-cap step.
Free Render services sleep after 15 minutes idle, and scheduled jobs only fire while awake, so the runbook calls for an external uptime pinger. Dispute resolution is not decided yet, and there is no licence file.
Credits
Solo side project. All 54 commits are mine. I built it with AI coding agents, one planning and verifying and one coding, with parallel lanes on disjoint files and a gate per wave, as recorded in the repo's handover docs. Maps and routing use open data services: Photon by komoot, OpenRouteService, OSRM and OpenFreeMap. The repo is not linked here.

