Astrosaathi
Vedic astrology AI grounded in a computed birth chart
Astrosaathi answers from your actual birth chart, not your sun sign. Enter date, time and place once and it computes a classical janam kundli (sidereal positions with Lahiri ayanamsa, whole-sign houses, nakshatras and the Vimshottari dasha you are currently running), then grounds every answer in it. Six astrologer personas each read a different part of that same chart, in Hinglish, Hindi, Tamil, Telugu or Kannada.
The Problem
Astrology apps almost always fake the hard part: they ask for a sun sign and generate horoscope-shaped text. Doing it properly means computing a real chart, and then keeping a language model tethered to that computation instead of letting it invent plausible-sounding planetary positions, in five languages, for an audience that will immediately notice when a reading contradicts their kundli.
The Solution
A Go service owns the astrology: a `jyotish` package computes grahas, bhavas, nakshatras and the dasha timeline behind an Engine interface, and that computed chart is what gets injected into every prompt. Personas are database-seeded rather than hardcoded, each scoped to the houses and planets its speciality actually reads: marriage questions against the 7th house, Venus and Mangal dosha; career against the 10th and the running dasha. Answers stream to the app over SSE in whichever of the five languages the user picked, with the entire UI rendered in that language rather than translated on top of English.
Architecture
- Go 1.26 + Gin, layered handlers → services → repositories, with a hard 300-line-per-file review limit
- PostgreSQL via pgx with golang-migrate; Redis for per-user and per-IP rate limiting
- `jyotish` package: chart types behind an Engine interface (sidereal/Lahiri positions, whole-sign houses, nakshatras, Vimshottari dasha)
- OpenRouter streaming chat completions behind a provider-agnostic LLM client, grounded in the computed chart
- Firebase Admin as token authority with MSG91 phone-OTP sign-in behind a `Sender` interface
- Razorpay subscriptions with signature-verified webhooks; Google Geocoding proxied server-side so the key never ships in the app
- Flutter 3.44 with GetX and Material 3: seven-step onboarding wizard, SSE chat, five-language UI
- Next.js marketing site and admin console; deployed on Railway with migrations and persona seeds run at startup
Challenges & How I Solved Them
Keeping the model tethered to the chart
A language model will happily invent planetary positions that sound authoritative. Computation stays in Go and the resulting chart is injected as ground truth, so the model's job is interpretation rather than astronomy, and a reading can be traced back to the houses and dasha it came from.
Five languages, not a translation layer
The reading is generated in the chosen language and every screen renders in it, rather than English being machine-translated after the fact, which matters most for astrological vocabulary that has real, non-interchangeable terms in each language.
Six readers, one chart
Personas are seeded rows scoped to the parts of the chart their speciality reads, so adding or retuning an astrologer is a data change rather than a code change, and two personas asked the same question give genuinely different, chart-justified answers.
My Contributions
- Entire system: Go backend, chart engine, Flutter app, marketing site and admin console
- Vedic chart computation: sidereal positions, whole-sign houses, nakshatras and Vimshottari dasha
- Chart-grounded persona prompting with SSE-streamed responses
- Five-language product surface, generation and UI alike
- Phone-OTP auth, Razorpay subscriptions and proxied geocoding
Impact
- Live on Google Play as Astrosaathi
- Real kundli computation rather than sun-sign templating, with daily rashifal drawn from the user's own chart and transits
- Shipped in five languages across generation and UI
Lessons Learned
Grounding beats prompting. Once the chart was computed deterministically and handed to the model as fact, answer quality stopped being a prompt-tuning problem and became a retrieval-and-scoping one.