The Problem I Was Solving
Eight browser tabs. Every morning. Screener.in for Indian fundamentals. Yahoo Finance for US stocks. Moneycontrol for news. AMFI for mutual fund factsheets that look like they were laid out in 2007 because they were. NSE for IPOs. Chittorgarh for IPOs that NSE forgets about. Zerodha Kite to actually buy things. And Groww because Kite makes me sad. Twenty minutes of actual research. Thirty minutes of context-switching between pages with different formatting and different update frequencies. Most days I closed my laptop without buying anything, because by the time I had compared everything I needed to compare, I was tired. I decided this was a problem worth solving for myself. I am a designer, and I had been wanting to build something with my own hands for a while, partly because I keep talking to engineers about products and noticing how often the conversation skips over the boring decisions that actually shape what a thing feels like. The only way to learn that for real was to make something where every decision was mine.What It Does
Investu started as a single-user Telegram bot. Mine. It now serves a small, owner-curated allowlist of trusted friends too. It runs every morning at 8 AM IST. It screens 100+ Indian large-caps, the S&P 500 starter set, mutual funds, SIP-eligible picks, and live IPOs. It ranks whatever passes a quality screen, surfaces a near-pass watchlist of stocks that almost qualified, and pulls sourced news on the top picks. Every URL it cites is a real URL. Sixteen commands. An inline keyboard menu. Cards, not tables. And a morning quote from Buffett, Munger, or Naval to open the brief.Designing the Experience
The whole point was to turn a chore into something I look forward to opening. That is an experience problem before it is an engineering one, so the design decisions came first. Telegram, not a web app. The brief had to arrive where I already am, with no browser tab to open and no login to clear at 8 AM. Telegram also gives bots real formatting freedom that WhatsApp does not: inline keyboards, rich cards, scheduled messages, and no per-message cost. The whole interface is sixteen commands behind an inline keyboard menu, so the bot is browsable, not memorised.
Cards, not tables. The first thing I tried was a monospace table. It was a disaster. Phone screens line-wrap monospace tables in the worst possible places, usually the price column, right when the number runs into the next column and you cannot tell whether ROE is 16.8% or 168%. Most developer-brain outputs default to tables because tables are how data looks in a database. The bot does not run on a database. It runs on a phone screen at 8 AM, and the person reading it has bedhead. So I rewrote the formatter as cards: one company per card, labels and values stacked, message-limit splits that fall between cards and never cut one in half. It sounds like a tiny call, but it changes how the output is composed at every layer, and the product feels different because of it.
Honest labels. Every number the bot prints carries its timeframe and its source. PE current. ROE TTM. Revenue 3Y CAGR. Source: Screener.in. As of timestamp. When something is missing, the missingness has a label too: "Market cap: n/a" is information, not an error. The bot has never lied to me about what it does not know, and that is the whole basis of trusting it.
Decision support, not just a verdict. The most useful idea in the product is the near-pass watchlist. The strict screen tells you what to buy this quarter; the near-pass list tells you what to check next quarter, showing exactly why a name missed, for example "Reliance: 3Y profit CAGR 8.4% against a 12% floor." A screen that only says yes or no throws away the most interesting half of the answer.
A ritual, not a tool. The morning brief opens with a quote, a 43-strong rotating deck of Buffett, Munger, Naval, Damani, and Morgan Housel that never repeats until it has been through all of them. That single line is the difference between a tool I use and a tool I look forward to opening.
Trust by Design: The AI Research Pipeline
The five screens tell me what to buy. They do not tell me why this week is the right week, and that is what news research is for. But news enrichment is only worth having if the "honest labels" promise survives contact with an LLM, so the pipeline is built around one rule: every URL the bot cites must be real.
LLMs hallucinate URLs. The first time I asked GPT-4 for three recent articles about Reliance with sources, all three returned 404, not out of malice but because a URL is exactly the kind of detail a model will invent to satisfy a citation pattern. It knows what URLs look like; it does not know which ones exist.
The pipeline that solved this has three steps. Tavily searches fire two focused queries per ticker (catalysts in the last 21 days, analyst targets) and return real snippets with their source URLs. Groq extracts, taking those snippets into Llama 3.3 70B with a fixed JSON schema that has no "growth potential" or "expected returns" field, so the model physically cannot emit speculation. Code validates, and this is the part that matters: I keep the set of URLs Tavily actually returned, and any URL in the model's output that is not in that set gets dropped.
The model can hallucinate. The pipeline does not. In six weeks of running, not one fake URL has leaked into the bot's output. The model is the cheapest part of this system; the expensive part is the engineering around it.
Building It, Phase by Phase
Phase 1 was a 250-line Python CLI: no Telegram, no LLM, no scheduler, just a quality screen that printed Indian large-caps to the terminal. The screen loads a universe, checks fundamentals against a YAML rule set (market cap, revenue and profit CAGRs, ROE, debt-to-equity, PE), ranks the survivors, and records every check it ran so the near-pass watchlist can explain a miss.
Once that pattern was solid, the other four screens were a copy-the-shape exercise: US stocks on Financial Modeling Prep, mutual funds on MFAPI.in, SIPs as the fund screen with a minimum-amount filter, and the IPO calendar from NSE's official endpoint. Five screens, same three-step contract, same caching layer, same formatting pipeline.
Phase 4 added the 8 AM digest as an in-process scheduled job (no Celery, no cron container): the bot wakes itself, fans out all five screens, and posts each as a card stack. One subtle problem followed. Indian fundamentals only refresh quarterly, so the same names surfaced every morning, technically correct and dead stale. The fix was a date-seeded daily rotation (deterministic and unit-testable) over a larger universe, plus an honest recalibration of the thresholds when a live run revealed the strict screen passed only 7 of 96 names. The brief now spotlights roughly eight different, still-qualified names a day.
Shipping It, and Running at Zero Cost
Most side projects die between "it works on my laptop" and "it runs every morning whether I touch it or not." The first version ran on a Render free service woken by a GitHub Actions cron, and it failed twice over: cold starts outran the trigger, and GitHub's best-effort schedules fired hours late, so my "8 AM" brief routinely arrived at noon. So I stopped fighting it. The bot now runs always-on in polling mode on an Oracle Cloud Always Free VM, where the in-process scheduler fires at 08:00 IST exactly. With a public IP it also got locked down: key-only SSH, no inbound ports, owner-only .env, quiet logs so the token stops leaking. A read-only deploy key plus a systemd timer make the VM self-update on every push, so the whole deploy workflow is a single git push.
Investu costs Rs. 0 a month, steady state, because it caches aggressively: six-hour caching means a ticker is never re-searched within a business day, which keeps Tavily, Groq, and FMP comfortably inside their free tiers. The shared cache is also what makes "a few friends" free, since every allowlisted user reads the same cached picks and the only quota-burning command is owner-only. "Free tier only" was a constraint I set upfront, not an outcome I stumbled into, and it was clarifying: the Rs. 500-a-month version would be more capable and worse-designed in every way that matters.
Platform Evolution
Lessons
- Design the output before the screens I nearly shipped a table-based formatter before realising it was unreadable at 8 AM on a phone. Output first. Everything else follows.
- Honest labels are the product Saying "no data found" instead of inventing a default builds more trust than any feature could. The bot has never lied to me about what it does not know.
- A ritual beats a tool The opening quote, the card rhythm, the fixed 8 AM arrival: the small experience choices are why I actually open it, and a research tool nobody opens is worthless however good its data.
- The model is the cheapest part The real work was the schema lock, URL validation, sanity ranges, and mode-specific prompts. The model just executes inside those constraints.
- Constraints are clarifying "Free tier only" forced every architectural decision worth making. The constraint shaped the product more than any feature idea did.
- Phase the build A working script on day one meant every later phase had something real to build on. The "start with AI" version of this project would still be in design.
FAQ
Telegram is where I already am. A bot message arrives in the same place as everything else, with no browser or login required. Telegram also gives bots far more customization freedom than WhatsApp: inline keyboards, rich card formatting, scheduled messages, and no per-message cost.
Tables are how data looks in a database, not how it reads on a phone at 8 AM. Monospace tables line-wrap on the price column and turn 16.8% into something that could be 168%. Cards put one company per block with labels and values stacked, and the message-limit splitter breaks between cards so a company is never cut in half mid-data.
For a few trusted friends, yes. Investu now runs an owner-curated allowlist with opt-in daily digests. It stays affordable because everyone reads the same shared-cache picks, so the fixed screens cost the same for one user or fifty, and the only quota-burning command is owner-only. Going fully public is intentionally not on the roadmap: public-scale scraping would breach Screener.in's terms, the free FMP and Tavily tiers would not survive the load, and distributing a financial screen at scale edges into regulated advice territory.
Each screen has a caching layer. If a ticker was fetched in the last six hours, the bot returns the cached result instead of calling the API again. Rate limits almost never trigger in practice because the cache absorbs most of the repeat calls across a normal day.
Those apps are great products. They are also built for a general audience, which means the screens, defaults, and alerts reflect average preferences. Investu's quality criteria are specifically mine. The PE ceiling, the revenue CAGR floor, the near-pass watchlist, the Telegram format at 8 AM: none of that exists in a general-purpose app because none of it is generally useful.