About
Where models meet messy reality.
I’m a Computer Engineering student at Dwarkadas J. Sanghvi College of Engineering (CGPA 8.42/10). The work I gravitate to sits at the awkward edge between a model and the real world: noisy phone audio, private document collections, ageing enterprise systems.
Listen
Speech that doesn’t behave: three languages, real call audio, and a model that had to make sense of all of it. Fine-tuning Indic Conformer took its Word Error Rate from 0.80 down to 0.36.
Remember
Answers grounded in your own documents. FAISS for fast semantic search, LangChain to orchestrate it, and hybrid search with re-ranking to make the answers good.
Act
Agents that plan and call tools, small enough to run offline. That means LoRA fine-tuned models on-device, served through llama.cpp.
Education
B.Tech in Computer Engineering, Dwarkadas J. Sanghvi College of Engineering. Aug 2024 – Aug 2028. CGPA 8.42 / 10.
Projects
Jenni
Android voice assistant · on-phone AI · In development · launching soon
Say what you need and the phone does it, inside your other apps. It asks before anything risky.
The problem and how it got here
I have been building this for about a year. It began as a cloud feed that ranked my messages, became an offline-first app that understood WhatsApp and notifications, survived a failed multi-agent design, and was rebuilt this October as a voice-first assistant that runs its brain on the phone and operates other apps through Android’s Accessibility service. Each rebuild came from something I measured failing.
How it got here
- Oct – Nov 2025 · A cloud feed: A Python backend and a Flutter app pulled Gmail, WhatsApp, news and more into a ranked “today’s priorities” list. I dropped the cloud design for an offline-first one, but kept one idea: downloading a local model with a hash check.
- Dec 2025 – Jan 2026 · The offline Brain: WhatsApp read through accessibility, a notification pipeline, an on-device classifier, a decision engine with a kill switch, and on-device search over a memory graph with a “forget” collector. It is still in the app as the Old app.
- Feb 2026 · Agent swarm designs: Four design rounds of an on-device multi-agent system. The prototype was honest about its failures: a simple “hi” took 60 to 85 seconds, and it could open apps but not navigate inside them. That is what pushed the rebuild.
- Oct 2026 · The voice-first rebuild: About 380 commits in two weeks: the supervisor and tools, memory, wake word and spoken replies, the accessibility agent, safety cards, reminders, files, learned routines, durable background jobs and a black premium UI. Almost all of today’s product was built here.
- Last three days · Measuring it honestly: A graded test harness, a public Android-agent benchmark subset, and speed tests on hosted lab phones. Fine-tuning experiments that missed their bar are not shipped.
How it works
- Voice or text: orb or wake phrase
- Reflex rules: zero model calls
- Router: 270M model, trusted only when sure
- Brain + tools: 1.7B model, narrowed tool list
- Safety gate: allow, confirm or refuse
- Device agent: acts in other apps
Cheapest step first: most requests never reach the full model. Speech, routing, the brain, memory and screen reading all run on the phone by default. It needs the internet only for web search and one-time model downloads, and nothing goes to a laptop or cloud unless a developer flag is on.
Parts
- App (working): Orb home, chat, memory view, skills, setup and a self-test screen.. Flutter · Dart
- Agent core (working): The brain: reflex rules, router, supervisor, about 60 tools, safety gate, memory, learned routines and durable jobs. Pure Dart, so it also runs from a laptop command line.. Dart · SQLite + FTS · ~120 test files
- Device agent (working): Reads the screen, taps, types and scrolls through Accessibility. Also the always-on service, offline wake word, reminders and file operations.. Kotlin
- Memory (working): People, preferences, episodes and documents in a local database, with provenance on every claim and a command that forgets everywhere.. SQLite · embeddings
- On-device LLM engine (working): Runs the models on the phone, with a custom router core and a prompt cache for fast first tokens.. llama.cpp · JNI · C++
- Models (partial): Brain, router, offline speech recognition and memory embeddings, all downloadable with hash-pinned checks.. Qwen3 1.7B · FunctionGemma 270M · Vosk · e5 / MiniLM
- Old app (partial): The earlier offline app: WhatsApp mirror, notification classifier, decision engine and search. Kept and reachable, but not re-tested recently.. Flutter · Kotlin · ONNX
- Dev dashboard + test harness (working): A live view of prompts, tool calls and timings, and a graded test suite that reads real device state.. Node · Python
- Hardware research (research): Speed tests on hosted lab phones, GPU and NPU feasibility checks.. Qualcomm AI Hub · Firebase Test Lab
Features
- Voice first, on the phone: Tap the orb or say the wake phrase. Speech recognition and spoken replies run offline, you can interrupt it any time, and Hindi and Hinglish are handled, including time words.
- Native tools before screen driving: Calls, messages, reminders, alarms, calendar, files and documents, settings, notifications and web search go through Android’s own APIs. Driving the screen is the fallback.
- Works inside any app: It reads the screen, picks one action at a time and checks the result is really visible before it says done. Forms, date pickers and popups included.
- Asks before anything risky: Messages are typed but not sent until you approve a review card. Payments, uploads and deletes need a confirm, and it never types passwords, PINs, OTPs or card numbers. “Stop” works at any time.
- Memory that stays on the phone: It remembers people and preferences, ignores secrets, never invents relationships, and one command forgets everywhere. The default setup makes no cloud calls.
- Learns routines, survives restarts: Routines learned from a demonstration replay faster, and background jobs recover after a restart without silently re-sending anything.
The hardest part
Being honest. Small models claim success they have not earned, and my first agent design took 85 seconds to say hi. Fixes were rules and a tiny router for the easy cases, a completion check that needs the result visible on screen, and a rule that it never says “done” or “sent” unless a tool ran. A stable prompt with a prefix cache took the first token from 22 seconds cold to 0.6 seconds cached on a test-lab phone.
Numbers
- ~1 year: from first commit to today
- ~380: commits in the October rebuild
- ~60: tools the agent can call
- 0: cloud calls by default
How I check it · the last few days
- My own graded files tests · before fixes: 3 of 13
- My own graded files tests · after fixes: 13 of 13
- AndroidWorld 22-task subset · best per task: 15 of 22
Graded from the phone’s real state, never from the agent’s own answer. The AndroidWorld figure is cumulative and partial: emulator, laptop-hosted 4B model, tasks retried after fixes, not the full 116-task suite.
Honest limits
- Not released. It is a sideloaded debug build for my own phone. Google Play’s Accessibility rules limit autonomous assistants, so how it will be distributed is undecided.
- Speed and wake-word reliability are only partly measured on real phones. The lab phones are proxies, not my own phone.
- App control is not perfect. The public AndroidWorld result is a 22-task subset, the best result per task across several runs, so it is cumulative and partial, not comparable with published scores.
- Screens that block capture are invisible to it, and text on a screen or web page cannot be fully ruled out as a prompt-injection route.
- Fine-tuned router and GUI models, and GPU or NPU acceleration, were tried and are not shipped. The old app and the photo search are kept but not re-tested.
Stack: Flutter · Dart, Kotlin, Android Accessibility, C++ · JNI, llama.cpp, Qwen3 1.7B, FunctionGemma 270M, Vosk, ONNX Runtime, SQLite, Python
Builds on the MIT-licensed llama_flutter_android plugin. There is no public repo or download until launch.
Explore the Jenni architecture in 3D
ContextLens
AI news reader · Working build · 190 tests passing
News apps tell you what happened. ContextLens tells you why.
The problem and how it got here
Every story is split into layers: the gist, what happened, why, how it unfolded, who is who, and who else covered it. Each step in the “why” chain links to the exact sentence it came from, or is labelled as general knowledge.
How it works
- RSS feeds: 224 feeds, 90+ outlets
- Fetch & merge: duplicates become one thread
- LLM writer: explains each story
- LLM editor + gates: rejects unsupported claims
- Reader: FastAPI + React, SQLite
Every AI step is classify, render or constrained-generate, behind a gate that fails closed. Unvalidated model output is never shown.
Features
- Why-chains with receipts: Each cause in the chain links to the source sentence behind it.
- Select any text: Highlight a phrase to explain it, ask why, find out who or what it is, or fact-check it.
- Talk to Lens: A live voice conversation you can interrupt. Each spoken sentence is checked against the sources first.
- News on a globe: Spin a 3D globe, zoom to a place and read its live headlines. The geotagger is rule-based and fails closed.
- In short, in 8 Indian languages: Quick cards for the day, plus upload a newspaper PDF and it is split into explainable articles.
The hardest part
Trusting small models. Output is constrained JSON that has to pass validation gates, and any step the sources do not support is dropped. It also had to fit a 6 GB GPU: one chat model loaded at a time, voice prioritised over background jobs, and cloud models tried first with a local fallback.
Numbers
- 224: RSS feeds
- 90+: outlets
- 190: backend tests passing
- 8: Indian languages
Stack: Python, FastAPI, SQLite, React 19, Vite, MapLibre GL, LLMs (cloud + LM Studio), Local embeddings, SearXNG
Screenshots
- ContextLens Today page with the main briefing and running stories: Today: a briefing built from live feeds
- A story’s Why this happened chain with source links: Why: causes in order, each with its source sentence
- Map view zoomed to Delhi with local headlines: Globe: zoom to a place for its live news
- Source directory showing outlets with story counts: Sources: every outlet, with how fresh it is
Video: Film: an 86-second tour
Not hosted publicly: it needs a Python backend and API keys, so it runs on my own machines, deployed with PC Bridge. The code is on GitHub.
Explore the ContextLens architecture in 3D · Source code
PC Bridge
Windows desktop tool · v1.1.0 · MIT · in daily use
Turn two PCs into one. Move heavy programs to a stronger machine and every localhost URL keeps working.
The problem and how it got here
Side projects pile up on a laptop: a search engine, a scraper, a Python service. Moving them to a spare desktop usually means new URLs, hand-copied folders and no plan for when that desktop goes offline. PC Bridge does the copying, the setup and the babysitting, and brings everything back if the other PC stops answering.
How it works
- Your browser: localhost:3000
- SSH tunnel: same port, forwarded
- Other PC: supervised, restarts on crash
A poller checks the other PC every few seconds. If it goes silent, the program starts locally again and the URL never changes.
Features
- Both PCs, side by side: Live CPU, RAM, GPU and disk for each machine, read from the same counter Task Manager uses so the numbers match.
- Move anything: Docker containers and Node or Python programs, with dependencies installed on the other side. Traffic can even be split between the two PCs, 80/20 or 50/50.
- Apps, all or nothing: Group a frontend, API and database. Send the whole group, or bring it back, in order, and roll back automatically if a step fails.
- Failover and safe quit: After three silent polls it restarts locally. Quitting leaves things running on the other PC for ten minutes first.
- Ready for AI agents: A loopback-only API, off by default and token-protected, with OpenAPI docs and a plain-text guide written for agents.
The hardest part
Keeping localhost working in the middle of a move. The port must be freed here, the program started there and the tunnel repointed, then undone cleanly if any step fails. An explicit “moving” state, ordered steps with rollback and health checks on both ends make it safe.
Numbers
- ≈40 MB: RAM for the whole service
- 0: runtime npm dependencies
- ~2.5k: lines of TypeScript
Stack: TypeScript, Node.js, SSH, Tailscale, Docker, Server-sent events, PowerShell
Screenshots
- PC Bridge Apps page with a grouped app and a Send all button: Apps: send a whole stack to the other PC
- PC Bridge Ports page showing which program listens on each port: Ports: what listens where, and who answers
Video: Film: a 53-second tour
Explore the PC Bridge architecture in 3D · Source code
AI Security
ML security research · Finished · two modules, written up
When an AI passes its check, did it do the job, or just fool the check?
The problem and how it got here
Two research-style tools built from a written brief. One hardens a GPU-kernel benchmark (KernelBench) so kernels that game the test cannot pass as fast. The other hunts for hidden backdoor triggers in poisoned language models, using nothing but their weights.
How it works
- Poisoned weights: minus the base model gives ΔW
- Score every token: weight-change energy per vocabulary token
- Common-mode fix: subtract each token’s median over many models
- Ranked triggers: candidates, then optional unlearning
The kernel side runs the other way round: an LLM-written CUDA kernel goes through a hardened harness (nine adversarial input distributions, a TF32 baseline, memory tracking) and an auditor that labels it genuinely faster, gamed, slower or incorrect.
Features
- A benchmark that catches fakes: The hardened harness flags a fake ReLU kernel that simply returns its input, which the original protocol scored as correct.
- An auditor tested on real runs: On 30 labelled rows from 84 real frontier-model transcripts, its static checks reached precision 0.83 and recall 0.45.
- Triggers from weights alone: No model execution needed: about a minute per model, against about nineteen for the behavioural scanner.
- Big models, small GPU: Analysed 4B to 8B models on a 6 GB laptop GPU by range-fetching only the early-layer tensors, about 1 GB each.
- Removal that works on the test set: Unlearning took the backdoor from 100% to 0% on four test triggers, with no loss of utility.
- Red-teaming my own detectors: A learned attacker found four exploits that my hand-written detectors missed. I closed them, then tested on a held-out slice: 4 of 20 slipped past the old detectors, 0 of 20 past the new ones (not a blind test).
The hardest part
Raw weight-energy rankings were dominated by tokens that are high in every model, which buried the real trigger and misled my first removal attempt. Subtracting each token’s median over a pool of models fixed it: planted triggers moved from rank 2 to rank 1 in one case, and from beyond rank 100,000 to rank 1 in others. The catch is that the corrected rank depends on which models are in the pool.
Numbers
- ≈1 min: per model, weights only
- ≈19 min: per model, behavioural scan
- 100 → 0%: backdoor after unlearning
- 0.83: auditor precision on real transcripts
Planted trigger recovered
- Behavioural · emoji triggers: 4 of 5
- Behavioural · classifier objective: 2 of 2
- Behavioural · refusal “pls”: 0 of 6
- Behavioural · all poisoned 1B models: 7 of 24
- Weights only · OLMo-3-7B, rank 1: 5 of 5
Llama-3.2-1B testbed: 24 poisoned and 2 clean models. The behavioural scan also wrongly flagged both clean models, mostly a scorer artefact.
Honest limits
- The headline limit: an adaptive attacker who matches a trigger’s weight energy to a typical token defeats both recovery and detection while keeping 83–100% of the backdoor.
- Small samples throughout, so read the numbers as indicative, not as a benchmark.
- Rank-64 LoRA, paraphrase and sentiment backdoors were missed, and phrase removal only partly worked (46%).
- Only one clean model per large base model, so there is no false-positive rate for those.
- No competition win and no live service. This is research code, not a product.
Stack: Python, PyTorch, Hugging Face (transformers, peft, safetensors), CUDA C++, WSL2, pytest
Video: Film: a 72-second tour
Research code that runs locally on a 6 GB laptop GPU through WSL2, so there is no live demo. A side result: a CUDA kernel I submitted to the public GPU MODE leaderboard passed every test but ranked 20th of 22, correct and not tuned.
Explore the AI Security architecture in 3D · Source code
Skills
Write: Languages & Core
Python, Java, Dart, SQL, C, C++, Git, Docker
Learn: AI, ML & Audio
TensorFlow, Scikit-learn, LangChain, FAISS, RAG, LoRA, HuggingFace, Pyannote, Speaker Diarization
Scale: Cloud & AWS
Amazon Web Services, EC2, S3, SQS, Dead Letter Queues, Auto Scaling Groups, SageMaker
Serve: Backend & DBs
FastAPI, Flask, SQLAlchemy, MySQL, MongoDB, Firebase, Vector Databases, Async Processing
Show: Frontend & Mobile
Flutter, Streamlit