<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ranbir Singh</title>
    <description>The latest articles on DEV Community by Ranbir Singh (@ranbir0x1).</description>
    <link>https://dev.to/ranbir0x1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4155089%2F1bdc7b90-a499-4e98-8918-35ff859c4e87.jpg</url>
      <title>DEV Community: Ranbir Singh</title>
      <link>https://dev.to/ranbir0x1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ranbir0x1"/>
    <language>en</language>
    <item>
      <title>Every refused COD parcel costs an Indian seller ₹150. RTO Shield stops them before they ship.</title>
      <dc:creator>Ranbir Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 18:03:02 +0000</pubDate>
      <link>https://dev.to/ranbir0x1/every-refused-cod-parcel-costs-an-indian-seller-150-rto-shield-stops-them-before-they-ship-2gk0</link>
      <guid>https://dev.to/ranbir0x1/every-refused-cod-parcel-costs-an-indian-seller-150-rto-shield-stops-them-before-they-ship-2gk0</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In India, a lot of online orders are cash on delivery. The buyer taps "COD", forgets about it, and when the courier shows up three days later they refuse the parcel, aren't home, or gave an address the courier can't find. The parcel goes back to the seller. That's an &lt;strong&gt;RTO&lt;/strong&gt;, a return to origin.&lt;/p&gt;

&lt;p&gt;The seller doesn't get the product's price back as profit. They lose the shipping out &lt;em&gt;and&lt;/em&gt; the shipping back. RTO Shield uses &lt;strong&gt;₹150&lt;/strong&gt; as the default cost of one RTO, and the shop can change it. For a small D2C brand making a few hundred COD orders a month, that adds up to a real slice of the margin, lost on orders that never had to ship.&lt;/p&gt;

&lt;p&gt;Most of these returns can be predicted, and many can be fixed: confirm the order before it ships, correct a bad address, or nudge the buyer to pay up front. Sellers already know that. They just don't have the hours to message every risky buyer by hand.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;RTO Shield&lt;/strong&gt;, an autopilot that does that work for Shopify sellers.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/DHdSgPbOdMs" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;RTO Shield connects to a Shopify store and works through every new COD order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scores it.&lt;/strong&gt; Every pending order gets a 0–100 risk score, a Low / Medium / High band and a one-line reason.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Messages the buyer on WhatsApp.&lt;/strong&gt; The message goes from RTO Shield's platform number with the &lt;strong&gt;shop's name&lt;/strong&gt; on it, asking the buyer to confirm, or offering a prepaid link. The seller never pastes a token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixes the address.&lt;/strong&gt; If the buyer replies with a corrected address, the API parses it and checks the pincode against &lt;strong&gt;India Post&lt;/strong&gt;. If the city and state agree, the fix is &lt;strong&gt;written back to Shopify&lt;/strong&gt; and confirmation carries on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calls when nobody answers.&lt;/strong&gt; A silent buyer moves on to a voice-agent call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hands the leftovers to a human.&lt;/strong&gt; Whatever still needs the seller lands on &lt;strong&gt;Exceptions&lt;/strong&gt;, with Confirm, Cancel and &lt;strong&gt;one&lt;/strong&gt; extra call. Nothing else needs their attention.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The seller mostly looks at two screens. &lt;strong&gt;Results&lt;/strong&gt; shows the money saved. &lt;strong&gt;Exceptions&lt;/strong&gt; shows the short list that needs a decision.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frp928678iu8gllc15mo3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frp928678iu8gllc15mo3.png" alt="Results screen of the demo shop: ₹150 RTO cost, ₹13,246 prevented, 37% RTO rate, 1 exception" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The demo shop's Results screen (demo data): ₹13,246 prevented, 3 COD orders converted to prepaid, 2 addresses fixed, 17 orders confirmed before they shipped.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who pays, and why.&lt;/strong&gt; The buyer is a small Indian D2C seller on Shopify who ships COD. The suggested price is &lt;strong&gt;₹499 a month&lt;/strong&gt;. At ₹150 an RTO, preventing four returns a month pays for it. Everything after that is margin they'd otherwise have handed to the courier. (This build doesn't take a card yet.)&lt;/p&gt;

&lt;p&gt;There's also a robot voice tour that walks a new seller through the app in &lt;strong&gt;Hindi, English or Hinglish&lt;/strong&gt;, because many of the people running these stores aren't developers and don't want to read docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://www.rtoshield.tech" rel="noopener noreferrer"&gt;www.rtoshield.tech&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Judges:&lt;/strong&gt; press &lt;strong&gt;Try the demo&lt;/strong&gt; on the landing page. There's no sign-up; it drops you into a demo shop with real screens and demo orders. The robot tour starts by asking for a language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talk to the agent:&lt;/strong&gt; open &lt;strong&gt;Exceptions&lt;/strong&gt; and pick the order. In the demo you can start an &lt;strong&gt;in-browser call&lt;/strong&gt; with the voice agent, so you can hear what a buyer would hear. You get two demo calls every 30 minutes, and &lt;strong&gt;Reset call&lt;/strong&gt; starts a fresh one.&lt;/li&gt;
&lt;li&gt;The API and ML service run on Render's free plan and sleep when idle, so the first load can take about a minute. The site waits until both services report healthy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs2cs8z9dwwwlwytpgfzb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs2cs8z9dwwwlwytpgfzb.png" alt="Exceptions detail: order #1047 held for the seller, Autopilot called once, one extra call already used, Simulated call result" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Exceptions keeps a human in the loop: the order's history, Confirm / Cancel, and at most one extra call. In test mode the call is clearly labeled "Simulated call".&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Ranbir5ingh" rel="noopener noreferrer"&gt;
        Ranbir5ingh
      &lt;/a&gt; / &lt;a href="https://github.com/Ranbir5ingh/rto-shield" rel="noopener noreferrer"&gt;
        rto-shield
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Predict and prevent COD return-to-origin (RTO) losses for small Indian sellers with open-source AI (TabPFN + Gemma).
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;RTO Shield&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Autopilot for cash-on-delivery returns. It scores an order, messages the buyer, fixes the address, and calls when nobody answers. The seller sees what stopped.&lt;/p&gt;
&lt;p&gt;Live demo: &lt;a href="https://www.rtoshield.tech" rel="nofollow noopener noreferrer"&gt;www.rtoshield.tech&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Suggested price: ₹499 a month. This build does not take a card.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The problem&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;A refused cash-on-delivery parcel in India still costs the return trip. RTO Shield uses &lt;strong&gt;₹150&lt;/strong&gt; as the default cost of the shipping on one return-to-origin. The shop can change that number. Results counts rupees prevented as converted and cancelled risky orders, plus shipping. It is a planning figure, not a payout.&lt;/p&gt;
&lt;p&gt;The buyer is asked before the parcel ships. A bad address is checked. A silent buyer gets a call. The orders that still need a person land on Exceptions.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Score.&lt;/strong&gt; Each pending order gets 0–100, a Low, Medium, or High band, and a short reason. A pincode is courier context, not a ban.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autopilot WhatsApp.&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Ranbir5ingh/rto-shield" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;A monorepo with three services and an MIT license. CI runs lint, typecheck, unit tests, a production build and Playwright end-to-end tests (seller tour, judge demo tour, Exceptions) on every push, plus ruff and pytest for the ML service.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shopify order ─▶ NestJS API (Render) ──▶ ML service (FastAPI, Render)
                    │                       ├─ TabPFN: risk score from this shop's own history
                    │                       ├─ scikit-learn: instant score on every new order
                    │                       └─ Gemma 4: address-quality notes + message drafts
                    ├─▶ WhatsApp Cloud API ─▶ buyer replies ─▶ address parse ─▶ India Post ─▶ Shopify write-back
                    ├─▶ ElevenLabs voice agent (calls, Hindi/English/Hinglish tour)
                    └─▶ MongoDB Atlas (orders, users, audit; phones and addresses encrypted)
Next.js 15 web app (Vercel) ─ www.rtoshield.tech
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The model learns the shop, not the pincode
&lt;/h3&gt;

&lt;p&gt;The easy shortcut in RTO scoring is to blacklist pincodes. It's unfair to buyers, and it's wrong for a seller whose customers in that area pay fine. So in RTO Shield &lt;strong&gt;a pincode is not a model feature&lt;/strong&gt;. The score uses 15 signals: order value, COD or prepaid, the hour (as a circle, so 11 PM sits next to midnight), the buyer's prior orders and prior returns, whether they're new, high-value COD, late-night orders, address-quality flags (incomplete, junk, landmark-only, city/state mismatch), and this shop's own return rate in that area, shrunk toward typical so one bad week can't swing it. The score never sees the buyer's phone or name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TabPFN&lt;/strong&gt; does the full scoring. It's Prior Labs' open-source tabular foundation model: it learns &lt;em&gt;in context&lt;/em&gt; from the shop's own labelled history (delivered vs returned) and scores the pending orders in one pass. There's no training pipeline to run per seller, which matters when every shop has a different few hundred orders. On the live service it runs through Prior Labs' hosted &lt;code&gt;tabpfn-client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A new order needs a score straight away, before WhatsApp fires, so new orders, webhooks and the demo get an instant &lt;strong&gt;scikit-learn gradient-boosting&lt;/strong&gt; score. TabPFN then rescores in full. If TabPFN is unreachable, the chain falls back to local TabPFN, then scikit-learn, then a rules prior, and scoring never just stops.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gemma reads the address, code decides
&lt;/h3&gt;

&lt;p&gt;Indian addresses are messy: "near Hanuman mandir, behind petrol pump", a missing house number, or a city that doesn't match the pin. &lt;strong&gt;Gemma 4&lt;/strong&gt; (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;) reads each address and returns structured quality notes, which become features and a plain-English reason for the seller. It also drafts the confirmation messages.&lt;/p&gt;

&lt;p&gt;Gemma never gets the last word on facts. Whether an address is &lt;em&gt;valid&lt;/em&gt; is decided by India Post's pincode data, not by a model: when a buyer sends a correction, it's only written to Shopify if India Post's city and state agree. If a check fails, that's recorded on the order and the fix is skipped.&lt;/p&gt;

&lt;h3&gt;
  
  
  WhatsApp without the setup
&lt;/h3&gt;

&lt;p&gt;Asking a small seller to create a Meta Business account, register a number and paste tokens loses them on day one. So RTO Shield sends from &lt;strong&gt;its own platform number&lt;/strong&gt;, with the shop's name on every template. A shop that wants buyers to see its own number can switch that on in Settings. Its token is stored encrypted and only that shop's messages move.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calls, but autonomous
&lt;/h3&gt;

&lt;p&gt;Calls run on an &lt;strong&gt;ElevenLabs&lt;/strong&gt; conversational agent. The seller doesn't start calls; Autopilot does. From Exceptions the seller gets exactly &lt;strong&gt;one&lt;/strong&gt; extra call per order, the result shows inline, and if the buyer answers, the order goes back into the pipeline. I capped it on purpose, because a tool that lets a seller ring a buyer five times turns into a harassment tool. ElevenLabs also voices the Hindi, English and Hinglish tour.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flkv6m50vc7nq2u79t1sf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flkv6m50vc7nq2u79t1sf.png" alt="Voice tour language picker over the Results screen: English, Hindi, Hinglish" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What's real today, and what's a switch
&lt;/h3&gt;

&lt;p&gt;I'd rather say this up front:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WhatsApp runs on Meta's test number.&lt;/strong&gt; It works end to end. I've confirmed an order from my own phone. But a test number can only message numbers verified on the Meta app, and the store-name templates are waiting for Meta's approval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outbound phone calls are simulated.&lt;/strong&gt; With &lt;code&gt;CALLS_MODE=browser&lt;/code&gt;, Autopilot and "Try one more call" record a clearly labeled &lt;strong&gt;Simulated call&lt;/strong&gt; and dial nobody. The in-browser demo call is a real conversation with the agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Going live is config, not code.&lt;/strong&gt; Add a paid WhatsApp number, import a Twilio number into ElevenLabs, and set &lt;code&gt;CALLS_MODE=live&lt;/code&gt;. The steps are in &lt;a href="https://github.com/Ranbir5ingh/rto-shield/blob/main/docs/PRODUCTION.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/PRODUCTION.md&lt;/code&gt;&lt;/a&gt;. Sellers don't set anything up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demo numbers are demo data.&lt;/strong&gt; ₹13,246 is the demo shop's figure. The model eval in the repo runs on a synthetic set, and I label it that way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Built fast, with agents
&lt;/h3&gt;

&lt;p&gt;I built this during the challenge week (first commit October 15) with AI coding agents doing much of the typing, while I made the product calls: no pincode bans, one extra call, platform-owned AI keys, Exceptions-first design. The whole stack runs on free tiers: Vercel, Render, MongoDB Atlas and free API tiers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The unit economics only work if the AI is cheap.&lt;/strong&gt; A seller pays ₹499 a month, and a single RTO costs ₹150. If every order's score and every address check went through a per-token closed API, the AI bill would eat the margin I'm trying to save. TabPFN and Gemma are open, so I can run them wherever is cheapest. Today that's free hosted tiers. At scale it can be my own box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open models let me fit the problem instead of the API.&lt;/strong&gt; Every Shopify store is a different, small dataset. TabPFN is built for exactly that: a few hundred rows, scored in context. It's open, so I can read how it works, run it locally (the code already supports the local &lt;code&gt;tabpfn&lt;/code&gt; package) and fall back to scikit-learn without changing anything else. A closed "risk score API" would give me a number and ask me to trust it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Seller and buyer data stays under our control.&lt;/strong&gt; Buyer phones and addresses are some of the most sensitive data a small business holds. Gemma's weights are open, so the same address check can run on our own hardware through Ollama. Setting &lt;code&gt;OLLAMA_BASE_URL&lt;/code&gt; switches it, and &lt;code&gt;docker compose --profile ollama&lt;/code&gt; brings up a local Gemma. Today, honestly, production calls Gemma through Google AI Studio, because a free Render instance can't hold the model. The point is that I'm not locked in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No lock-in on price or on a vendor.&lt;/strong&gt; Every AI piece sits behind an env var with a fallback: TabPFN → scikit-learn → rules, Gemma → templates. If a provider changes its price or goes down, RTO Shield degrades instead of breaking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where I still use closed models:&lt;/strong&gt; Gemini 2.0 Flash parses buyers' free-text address replies and powers the call agent's conversation, because it was the fastest reliable option for messy Hinglish on a free tier this week. It also sits behind templates as a fallback, and moving those jobs onto Gemma is the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The stack is open too:&lt;/strong&gt; Next.js, NestJS, FastAPI, scikit-learn and India Post's public pincode API. RTO Shield is mostly glue on top of other people's open work, and the repo is MIT so the next person can build on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;I haven't charged anyone yet, and I won't pretend I have.&lt;/p&gt;

&lt;p&gt;I messaged e-commerce business owners in my own circle, people who ship COD orders and deal with RTOs every week, and showed them what RTO Shield does. They told me they want to use it once it's live. What's holding it back isn't the product. It's the paid pieces: a verified WhatsApp Business number, a calling number and paid hosting. Right now everything runs on free and developer tiers because I don't have funding for those yet.&lt;/p&gt;

&lt;p&gt;As soon as that's sorted, the switch is a config change, and I have sellers waiting to plug in their stores.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of TabPFN:&lt;/strong&gt; TabPFN does the full risk scoring. It learns in context from each shop's own delivered-vs-returned history across 15 features (no pincode) and scores the pending orders through Prior Labs' &lt;code&gt;tabpfn-client&lt;/code&gt;. It's the core of a wider prediction agent: the score decides who gets a WhatsApp, a prepaid offer, a call, or a spot on Exceptions. The live service reports &lt;code&gt;active_predictor: tabpfn-client&lt;/code&gt;, and the fallback chain is local TabPFN → scikit-learn → rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 4 (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;, served through Google AI Studio) reads every address for quality problems: incomplete, landmark-only, junk, or a city/state mismatch. Those notes become model features and the seller-facing reason, and Gemma also drafts the confirmation messages. A local Gemma path through Ollama is built in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render:&lt;/strong&gt; The NestJS API and the FastAPI ML service (TabPFN + Gemma) both run on Render from a &lt;code&gt;render.yaml&lt;/code&gt; Blueprint, with secrets kept out of the repo (&lt;code&gt;sync: false&lt;/code&gt;), health checks, and the custom domains api.rtoshield.tech and ml.rtoshield.tech.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of ElevenLabs:&lt;/strong&gt; A conversational ElevenLabs agent is the calling layer for buyers who don't reply. Judges can talk to it in the browser in the demo. ElevenLabs v3 also narrates the robot tour in Hindi, English and Hinglish. Outbound phone calls are simulated in test mode, and live dialing is one config switch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of MongoDB Atlas:&lt;/strong&gt; Atlas is the data layer for orders, scores, WhatsApp threads, call outcomes, users and the audit log behind Results, Exceptions and Activity. Buyer phones and street addresses are encrypted at rest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of a .tech Domain:&lt;/strong&gt; The whole product lives on &lt;strong&gt;rtoshield.tech&lt;/strong&gt;: the app at &lt;a href="https://www.rtoshield.tech" rel="noopener noreferrer"&gt;www.rtoshield.tech&lt;/a&gt;, the API at api.rtoshield.tech and the ML service at ml.rtoshield.tech.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built solo by Ranbir Singh.&lt;/p&gt;

&lt;p&gt;If you sell on Shopify in India, how many of your COD orders come back? I'd love to hear what you'd want RTO Shield to handle next.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Dead Drop: a hide-and-seek network for the real world</title>
      <dc:creator>Ranbir Singh</dc:creator>
      <pubDate>Sun, 11 Oct 2026 18:27:06 +0000</pubDate>
      <link>https://dev.to/ranbir0x1/dead-drop-a-hide-and-seek-network-for-the-real-world-2a3e</link>
      <guid>https://dev.to/ranbir0x1/dead-drop-a-hide-and-seek-network-for-the-real-world-2a3e</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Dead Drop&lt;/strong&gt; — a hide-and-seek network for the real world.&lt;/p&gt;

&lt;p&gt;Here's the problem with most "touch grass" apps: they hand you AI-generated errands. Walk to the park. Photograph a tree. Check in. You're still playing single-player against an app, and the grass is just a backdrop.&lt;/p&gt;

&lt;p&gt;Dead Drop flips it. &lt;strong&gt;Humans hide real objects for other humans.&lt;/strong&gt; You stash a painted stone in a park, describe the vicinity (never the exact spot), and the AI writes a cryptic riddle for it. Hunters browse riddles, walk outside, find the thing, and photograph it. Then the AI does the one job it's actually good at here: &lt;strong&gt;referee&lt;/strong&gt;. It compares the find photo against the hider's description and issues a verdict — match or no match. No couch-faking. Both sides score.&lt;/p&gt;

&lt;p&gt;Every screen is designed to end with you going outside. No feeds. No infinite scroll. No notification spam. The reward is genuinely variable — you never know what's hidden until you find it, and as a hider you never know when someone finds yours. Finders become hiders; that's the loop.&lt;/p&gt;

&lt;p&gt;It's for anyone who's ever wanted their neighborhood to feel a little more like an adventure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Live app: &lt;a href="https://dead-drop-eight.vercel.app/" rel="noopener noreferrer"&gt;https://dead-drop-eight.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/N3MjgbSKbUQ" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Narration generated with ElevenLabs. The video shows the full loop: login → hiding a drop with live AI riddle generation → the drop going live → hunting → photo verification → leaderboard.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Ranbir5ingh" rel="noopener noreferrer"&gt;
        Ranbir5ingh
      &lt;/a&gt; / &lt;a href="https://github.com/Ranbir5ingh/dead-drop" rel="noopener noreferrer"&gt;
        dead-drop
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Hide a small treasure outdoors. Hunt someone else's by riddle. An AI referee checks the photo.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Dead Drop&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Humans hide real things for each other. AI only referees.&lt;/p&gt;
&lt;p&gt;A hider stashes a small object outdoors, describes the vicinity, and the referee writes a riddle. A hunter reads the riddle, goes outside, and photographs the object. Vision verification decides the match. Both sides score. The exact spot is never published. The app never arranges a meeting.&lt;/p&gt;
&lt;p&gt;This is a mobile-first PWA for the Hacktoberfest Week 1 "Touch Grass" DEV challenge.&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;Phone (mobile browser, nothing installed)
   │  HTTPS JSON
   ▼
Vercel  — Next.js UI, GSAP, camera
   │  NEXT_PUBLIC_API_URL
   ▼
Render  — NestJS API, the AI runtime
   ├── Supabase Postgres (Drizzle) — drops, finds, scores
   ├── Supabase Storage — drop-photos bucket
   └── Google AI Studio — Gemma, riddles + photo checks
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The phone does not run a model. It calls the API. The API calls Gemma. Keys never reach the browser.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Honesty about photos&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The hosted demo sends find-photos…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Ranbir5ingh/dead-drop" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The AI: Gemma as the referee, not the quest-giver.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Riddle generation.&lt;/strong&gt; Gemma takes the hider's vicinity description and writes a cryptic, solvable riddle — behind strict guardrails: never an address, coordinates, or exact spot name. A deterministic safety scan runs in code, and the AI never overrides it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find verification.&lt;/strong&gt; Gemma (vision) compares the hunter's photo against the hidden object's description and returns a strict match/no-match verdict with a confidence score. Uncertain → no match, always. This honesty is the product's trust core: scores only mean something because the referee can't be gamed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemma runs two ways behind one provider interface: served through &lt;strong&gt;Google AI Studio&lt;/strong&gt; (&lt;code&gt;gemma-3-12b-instruct&lt;/code&gt;) in production, and via &lt;strong&gt;Ollama&lt;/strong&gt; locally during development. Same adapter, env-switched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The stack:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend: Next.js 16 + Tailwind + GSAP, mobile-first PWA (Vercel)&lt;/li&gt;
&lt;li&gt;Backend: NestJS API — the project's AI runtime (Render)&lt;/li&gt;
&lt;li&gt;Data: Supabase Postgres via Drizzle ORM; photos in Supabase Storage, uploaded server-side only&lt;/li&gt;
&lt;li&gt;Auth: email + Google/GitHub OAuth, httpOnly sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One honest note: the deployed demo sends find photos to Google's API so Gemma can referee them. The local Ollama path — where photos never leave the machine — is documented in the README as the privacy-preserving alternative. Open weights mean you get to choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Because the referee has to be inspectable.&lt;/p&gt;

&lt;p&gt;Dead Drop's entire value proposition is trust: a scoreboard that means something, riddles that are fair, verdicts that can't be gamed. If the referee were a closed black box, you'd have to take my word for it. With open weights, anyone can read the prompts, swap the model, run the whole AI layer locally, and verify the game is fair. That auditability isn't a nice-to-have — it &lt;em&gt;is&lt;/em&gt; the product.&lt;/p&gt;

&lt;p&gt;It also made the architecture possible on a hackathon budget: no per-seat AI pricing, no vendor lock-in, and a local inference path that runs with zero cloud spend. I built the thing I wanted to exist — and anyone can fork it and run their own city's dead-drop network tomorrow.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;Built with Cursor as the agentic IDE (Grok 4.7, high-effort planning mode) against a written master prompt: strict AI contracts, deterministic safety rules, and a provider-neutral AI adapter came straight out of that spec. No DevRelay session for this one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — Gemma writes every riddle and judges every find photo; the served-in-prod / local-via-Ollama setup shows genuine, load-bearing use of the open-weight model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render&lt;/strong&gt; — the NestJS backend, the project's AI runtime, is deployed as a Render Web Service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of ElevenLabs&lt;/strong&gt; — the demo video's narration was generated with ElevenLabs.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>My Girlfriend Manages Her Family's Health From a Plastic File. I Built Her SehatFile.</title>
      <dc:creator>Ranbir Singh</dc:creator>
      <pubDate>Sun, 04 Oct 2026 12:11:32 +0000</pubDate>
      <link>https://dev.to/ranbir0x1/my-girlfriend-manages-her-familys-health-from-a-plastic-file-i-built-her-sehatfile-39c5</link>
      <guid>https://dev.to/ranbir0x1/my-girlfriend-manages-her-familys-health-from-a-plastic-file-i-built-her-sehatfile-39c5</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SehatFile&lt;/strong&gt; — for my girlfriend, who handles all the health stuff in her family.&lt;/p&gt;

&lt;p&gt;Every Indian home has a plastic file. Hers holds years of her family's medical reports — different labs, prescriptions in fading handwriting, none of it sorted, all of it important. Before every doctor visit, she's the one spreading it across the bed and digging through it. And then, in the 90-second consultation, the doctor asks the question nobody can answer precisely: &lt;em&gt;"What medicines are they on, and since when?"&lt;/em&gt; Recently, the doctor re-ordered the same tests because she couldn't prove they'd already been done. The information existed. It just wasn't organized by person — so it might as well not have existed.&lt;/p&gt;

&lt;p&gt;I built it for her.&lt;/p&gt;

&lt;p&gt;She photographs each report once — lab slip or prescription, printed or handwritten, English or Hindi. SehatFile reads it, files it under the right person and date, pulls the medicines into a living medication list, and tracks the key values over time. Before the next appointment, one click generates a one-page doctor's brief: the conditions, the current medications, how the numbers have moved, and the exact questions to ask. She prints it and hands it to the doctor. Ninety seconds, finally used well.&lt;/p&gt;

&lt;p&gt;I handed it over to her, and in her words, it's "really a lifesaver."&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/ggLICYHy_ys" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The demo shows the real thing: a stack of genuine reports from her family's plastic file, photographed and filed; the timeline building up; the medicine list populating itself; and the doctor's brief generating — the same brief she'll carry to the next appointment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Ranbir5ingh/sehatfile" rel="noopener noreferrer"&gt;https://github.com/Ranbir5ingh/sehatfile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Public repo, MIT licensed. README covers the one-command setup. The app runs fully offline once the model is pulled — there is deliberately no cloud component, and that's the point (see below).&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; Next.js 16 (App Router) + TypeScript + Tailwind CSS — one codebase, no separate backend. All server logic lives in Route Handlers under &lt;code&gt;app/api/&lt;/code&gt;. The database is SQLite via &lt;code&gt;node:sqlite&lt;/code&gt; — built into Node.js, zero dependencies, a single file on the machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The AI core is Gemma, and the architecture is built around a hard rule:&lt;/strong&gt; no API route is allowed to touch the model directly. Everything goes through a &lt;code&gt;HealthAI&lt;/code&gt; interface in &lt;code&gt;lib/ai.ts&lt;/code&gt; with exactly two methods — &lt;code&gt;extractReport(image)&lt;/code&gt; and &lt;code&gt;generateBrief(record)&lt;/code&gt;. Two implementations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MockHealthAI&lt;/code&gt; (default) — realistic sample data in the exact same shapes, so the entire app works end-to-end with no model installed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GemmaHealthAI&lt;/code&gt; — calls Gemma via Ollama's &lt;code&gt;/api/generate&lt;/code&gt; with JSON mode. Switching providers is one env var: &lt;code&gt;AI_PROVIDER=gemma&lt;/code&gt;. Zero code changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The extraction prompt is the most carefully written part of the project. Medical data punishes hallucination, so its prime directive is: &lt;em&gt;read only what is actually visible; if handwriting is illegible, say so; never invent a value, a date, or a medicine name.&lt;/em&gt; Photos are downscaled client-side before they ever reach the model.&lt;/p&gt;

&lt;p&gt;The brief prompt turns the structured record into the one-pager: patient snapshot, current medications, key values over time with trends in plain words, recent changes, and 3–5 specific, data-grounded questions for the doctor — explicitly instructed never to diagnose or suggest doses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;This is the section the whole project stands on, so I'll be direct:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. This tool cannot exist on a closed API.&lt;/strong&gt; Nobody uploads their family's heart reports to someone else's server. Health data is the most sensitive data a family owns. A closed model would require piping all of it through a vendor's cloud — which means the families who need this most would never trust it. Open weights running locally aren't my preference here. They're the precondition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Free forever isn't a pricing tier, it's the design.&lt;/strong&gt; A family files reports for years; a parent's chronic illness is a decades-long paper trail. Per-report API billing would put a meter on the exact people who can least afford one. Gemma on the home computer costs nothing per report, forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. It works where the internet doesn't.&lt;/strong&gt; Small towns, hospital basements, homes with patchy connectivity — the app doesn't care, because nothing leaves the machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Multilingual without a pipeline.&lt;/strong&gt; Indian medical documents mix printed English, handwritten English, and Hindi. An open multilingual model reads all three in one pass — no translation service, no OCR vendor, no extra bill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. It's inspectable.&lt;/strong&gt; The prompts, the schema, the brief format — all in the repo. Any family, any clinic, any student can fork it and adapt the brief to their doctor. That's what open innovation actually means: the tool belongs to the people it serves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — Gemma (vision + text, via Ollama) is the entire AI core: it reads the photographed reports and writes the doctor's brief, on-device.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
  </channel>
</rss>
