DabbaETA: a 'will this tiffin be late?' predictor that never sends a customer's address to the cloud A developer built DabbaETA, a local-first dispatch assistant for small Indian delivery businesses such as tiffin services, bakeries and couriers, that predicts late deliveries without sending customer addresses to the cloud. The system stores orders in local SQLite and compares TabPFN against XGBoost on 5,000 synthetic orders, where XGBoost won with an MAE of 3.31 minutes versus TabPFN's 3.60, while a Gemma agent handles Hinglish queries through JSON tool routing and Temporal orchestrates the morning dispatch run with retries. The developer notes the synthetic benchmark only confirms the pipeline works and is not a claim about any real kitchen. This is a submission for the HF26 Challenge: Side Hustle https://dev.to/challenges If you run a small tiffin service in India, you know this day. It started raining at 12. One rider is new. Eight orders went out together. By 1 PM, customers are calling: "Bhaiya, khana kab aayega?" The owner has months of delivery history in a notebook or a spreadsheet. Nobody has ever used it to see this coming. Swiggy has an ML team for that. A 40-order kitchen doesn't, and that owner isn't going to upload customer names, phone numbers and home addresses to a random SaaS to fix it. So I built the version that runs on the laptop they already have. DabbaETA is a local-first dispatch assistant for small delivery businesses: tiffin services, bakeries, local couriers. Code: https://github.com/Harsh63870/DabbaWala https://github.com/Harsh63870/DabbaWala For this product, open is what makes the business possible at all. BasePredictor interface that already supports both the tabpfn-client API and the local tabpfn package, so going fully offline is a config change, not a rewrite. OLLAMA MODEL is an env var. When a better small Hindi-capable model ships, the owner upgrades without touching code. I didn't have a real tiffin dataset, so I generated 5,000 synthetic orders matching the schema of the Kaggle Food Delivery Times dataset: distance, traffic, weather, vehicle type, prep time, courier experience, evening rush and monsoon effects. Treat these numbers as a check that the pipeline works, not a claim about any real kitchen. Full data 4,000 train / 1,000 test : | Model | MAE min | RMSE | R² | Fit time | |---|---|---|---|---| | TabPFN | 3.60 | 6.05 | 0.937 | 0.39s | | XGBoost | 3.31 | 5.22 | 0.953 | 0.11s | | Linear regression | 6.27 | 10.15 | 0.822 | 0.003s | With thousands of rows, XGBoost wins. I'm reporting that as is. Both tree-based approaches are far ahead of linear regression, which is expected, since delivery time depends on interactions like distance × traffic × weather. A small owner doesn't have thousands of rows, though. They have a few weeks of history. That's why the benchmark script also runs a small-data experiment on 50, 100 and 200 training rows, and why the predictor is swappable: if XGBoost is better for your data size, switch to it in one line. The full results and chart are in the repo under docs/benchmark.json and docs/benchmark.png . php flowchart TD A Owner uploads CSV -- B SQLite, local B -- C TabPFN: ETA + late risk subgraph T Temporal DispatchWorkflow, exponential-backoff retries D load orders -- E predict all E -- F flag risky F -- G explain: Gemma G -- H draft messages: Gemma end C -- D H -- I WhatsApp drafts in Hinglish / Hindi / English J Chat: Aaj kaunsi orders late hongi? -- K{Gemma agent, JSON tool routing} K -- L predict eta K -- M list risky orders K -- N draft message L -- C M -- C O FastAPI + dashboard -.- T O -.- K S Sentry spans: tabpfn.predict, llm.gemma -.- C S -.- G S -.- H A Gemma agent that doesn't depend on native tool-calling. Small local models are unreliable at it, so Gemma is prompted to emit {"tool": ..., "args": ...} and I parse it with regex extraction plus a retry loop. Three tools: predict eta , list risky orders , draft message . Heuristic routing catches Hinglish queries like "Aaj kaunsi orders late hongi?" even when the model's JSON is malformed. Temporal for the morning run. A dispatch run chains a prediction step with several LLM calls, and any of them can fail halfway. Each step is an activity with exponential-backoff retries, so one flaky call doesn't mean redoing the whole run. If Temporal isn't reachable, the app falls back to an in-process run so the demo still works on any laptop. Sentry for visibility. Custom spans around every Gemma and TabPFN call record latency ms , tokens in and tokens out , which makes it clear where time goes when a dispatch run feels slow. Tests. 8 pytest tests cover order-schema validation, the predictor interface, agent JSON extraction, Hindi-query routing, message drafting, the workflow happy path and the API endpoints. My hypothesis, not yet validated: a tiffin or bakery owner will pay a small monthly fee, or a one-time setup fee, for "tell me which orders will be late before the customers call, and write the messages for me." The pitch is saved phone calls and fewer angry customers, not "AI". Because inference is local, my cost per customer is close to zero, so even a very small price leaves margin. A closed-API version would have to charge more just to cover token costs. I haven't landed a real paying user yet, and I'd rather say that than invent one. Everything above runs on synthetic data, so the first thing I'll do next is run it on a real owner's CSV and see where it breaks. DispatchWorkflow with exponential-backoff retries. llm.gemma and tabpfn.predict spans record latency and token counts. Run it on a real owner's data, add rider-level features, build a one-tap WhatsApp send flow, and retrain automatically as new deliveries get logged.