<?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: Reet Singh</title>
    <description>The latest articles on DEV Community by Reet Singh (@reet_singh_ee97da2986538e).</description>
    <link>https://dev.to/reet_singh_ee97da2986538e</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%2F3326605%2F99a4b92a-c5fb-4ac8-8209-9fb45450793f.png</url>
      <title>DEV Community: Reet Singh</title>
      <link>https://dev.to/reet_singh_ee97da2986538e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/reet_singh_ee97da2986538e"/>
    <language>en</language>
    <item>
      <title>The Last Process: I built a haunted desktop with Gemma</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Sun, 01 Nov 2026 06:01:17 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/the-last-process-i-built-a-haunted-desktop-with-gemma-5fc6</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/the-last-process-i-built-a-haunted-desktop-with-gemma-5fc6</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;You reopen an abandoned desktop. Three files survived. Beside them, a resident appears:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You weren’t supposed to reopen this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Last Process&lt;/strong&gt; is a short browser escape room about a program that kept waiting after its creator was gone. Recover the files, speak to the resident, uncover Mara’s diary, and decide how the last process ends.&lt;/p&gt;

&lt;p&gt;Gemma 4 plays the resident. Its responses change with your question and the clue you are examining. The puzzle rules stay in code: the model can offer atmosphere and guidance, but its output cannot unlock a file or change an answer.&lt;/p&gt;

&lt;p&gt;I wanted the haunting to come from an ordinary software behavior: a listener that never received its stop signal.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://the-last-process.onrender.com" rel="noopener noreferrer"&gt;Play The Last Process&lt;/a&gt;&lt;/strong&gt;&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%2F2d4lettmbw02a7hzn7pt.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%2F2d4lettmbw02a7hzn7pt.png" alt="The Last Process interface, with a file explorer, recovered log and resident dialogue panel" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To try it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read &lt;code&gt;boot.log&lt;/code&gt; and answer the question underneath it.&lt;/li&gt;
&lt;li&gt;Open each newly recovered file to continue the story.&lt;/li&gt;
&lt;li&gt;Ask the resident a question or use &lt;strong&gt;“I’m stuck. Give me a hint.”&lt;/strong&gt; to see Gemma respond.&lt;/li&gt;
&lt;li&gt;Recover the final letter and choose an ending.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The conversation is text-based. Optional ambient sound starts off, and the game never executes real commands or accesses your files. All characters and events are fictional.&lt;/p&gt;

&lt;p&gt;The free host may take about a minute to wake. Progress survives a page refresh on the same running instance; a host restart or redeployment can reset saves.&lt;/p&gt;

&lt;p&gt;For the HTTP interface, try the &lt;strong&gt;&lt;a href="https://the-last-process.onrender.com/docs" rel="noopener noreferrer"&gt;interactive API docs&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Reet24-del/the-last-process" rel="noopener noreferrer"&gt;GitHub repository — MIT licensed application code&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The repository contains the complete app, tests, Docker configuration, generated casebook and usage ledger. Dependencies and external models retain their own licenses and terms.&lt;/p&gt;

&lt;p&gt;Useful evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Reet24-del/the-last-process/blob/main/app/game.py" rel="noopener noreferrer"&gt;Game rules and progression&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Reet24-del/the-last-process/blob/main/app/ghost.py" rel="noopener noreferrer"&gt;Gemma integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Reet24-del/the-last-process/blob/main/scripts/generate_casebook.py" rel="noopener noreferrer"&gt;Ultramarine writer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Reet24-del/the-last-process/blob/main/docs/DEPLOYMENT.md" rel="noopener noreferrer"&gt;Public deployment checks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I split the experience into three responsibilities: &lt;strong&gt;rules, dialogue and story writing&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rules: make the room solvable
&lt;/h3&gt;

&lt;p&gt;Python validates each answer against an authored puzzle and advances the stage. The API checks the expected stage inside a SQLite write transaction, so duplicate submissions cannot skip a puzzle.&lt;/p&gt;

&lt;p&gt;The resident also has three progressively clearer authored hints for each puzzle. These are displayed separately from AI dialogue. If a provider fails or a response is misleading, the player still has a reliable next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dialogue: let Gemma inhabit the room
&lt;/h3&gt;

&lt;p&gt;The resident uses &lt;strong&gt;&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;&lt;/strong&gt;, Google's open-weight Gemma model, through the Google Gen AI SDK and Gemini API. Despite the API's name, the selected model is Gemma.&lt;/p&gt;

&lt;p&gt;Each request includes the current fictional clue, an approved hint and the player's message. The model writes a brief response as Mara. The game never interprets that response as a command.&lt;/p&gt;

&lt;p&gt;Hosted calls have a timeout, an output limit and disabled SDK retries. Session and process limits bound demo usage. If inference is unavailable, the interface explicitly labels its authored fallback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Story writing: give Ultramarine a bounded job
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Ultramarine (&lt;code&gt;ultramarine-1-flash&lt;/code&gt;)&lt;/strong&gt; wrote the three diary fragments bundled with the app. The build-time script calls Paper Instruments through the OpenAI SDK, validates exactly three short fragments, and records token usage.&lt;/p&gt;

&lt;p&gt;One useful failure happened here: the first response failed schema validation. It was rejected. The second request passed the unchanged validator, and its prose was reviewed before deployment. Both requests remain in the ledger; the failed attempt did not disappear from the cost accounting.&lt;/p&gt;

&lt;p&gt;Ultramarine can write diary paragraphs. Its accepted schema has no field for changing puzzle answers, clues or endings.&lt;/p&gt;

&lt;h3&gt;
  
  
  The stack
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;React + Vite&lt;/td&gt;
&lt;td&gt;Responsive file explorer, reader, resident panel and controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FastAPI&lt;/td&gt;
&lt;td&gt;Session, answer, hint and ending endpoints; Swagger UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;Transactional progress saves and bounded dialogue history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Gen AI SDK + Gemma 4&lt;/td&gt;
&lt;td&gt;Live, in-character resident dialogue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI SDK + Ultramarine&lt;/td&gt;
&lt;td&gt;Build-time diary generation with usage accounting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Render + Docker&lt;/td&gt;
&lt;td&gt;Serve the client and API together from one free web service&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;All 20 unit/API tests pass.&lt;/strong&gt; They cover wrong and stale answers, concurrent submissions, both endings, session isolation, hint limits, provider failure and invalid story output. Desktop and mobile browser checks exercised the complete game and save/resume. The public API also passed a real Gemma hint, all three unlocks, the generated diary, an ending and resume.&lt;/p&gt;

&lt;p&gt;These checks verify the exercised behavior. They are not a general model-accuracy benchmark or proof against every prompt injection. The important protection is that generated text does not control game state.&lt;/p&gt;

&lt;p&gt;This is a solo submission. Codex assisted with implementation, testing, review and drafting this write-up; ImageGen created the visual concept and resident portrait. The interface and controls are native React, HTML and CSS.&lt;/p&gt;

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

&lt;p&gt;Gemma is an open-weight model at the center of the live experience. Its weights are available for independent experimentation, and the surrounding application code is public: another builder can inspect the prompts, change the character, examine the guardrails and fork the room.&lt;/p&gt;

&lt;p&gt;For this deadline, I used hosted inference to ship a working demo without provisioning a GPU. That means ghost messages and fictional clue excerpts go to Google when a player asks for help. This version does not run Gemma locally or promise private offline AI.&lt;/p&gt;

&lt;p&gt;A future local Gemma runtime would need a new provider adapter. The authored puzzles, progression checks and story format could remain in place. Open weights make that route possible without depending on continued access to one hosted endpoint.&lt;/p&gt;

&lt;p&gt;The source also exposes the boundary that matters most here: readers can see exactly where a generated response ends and an authoritative game decision begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;Mara built a listener to preserve a voice she missed. Over time, she recognized that a convincing response could still be an imitation.&lt;/p&gt;

&lt;p&gt;That became the emotional center of the game. Both endings close the listener. One preserves the words as a story; the other lets the process rest. Neither treats an endlessly running program as a person who must keep waiting.&lt;/p&gt;

&lt;p&gt;The final interaction is a choice about what to remember.&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; &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; plays the resident in the deployed game, responding to the current clue and player's question. A public live inference call was verified.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Ultramarine:&lt;/strong&gt; &lt;code&gt;ultramarine-1-flash&lt;/code&gt;, called through the OpenAI SDK, drafted the three deployed diary fragments. Two requests used &lt;strong&gt;430 input tokens and 484 output tokens, including reasoning&lt;/strong&gt;, for a usage-based cost of &lt;strong&gt;$0.00030650 USD&lt;/strong&gt; at the &lt;a href="https://docs.paperinstruments.com/docs/ultramarine/billing" rel="noopener noreferrer"&gt;published rates&lt;/a&gt;. This includes the rejected first response. The provider's usage endpoint confirmed the request and token totals. This is a calculation from reported usage, not a rounded dashboard screenshot or a claim about the whole app's ongoing cost. &lt;a href="https://github.com/Reet24-del/the-last-process/blob/main/docs/ultramarine-runs.jsonl" rel="noopener noreferrer"&gt;Usage ledger&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render:&lt;/strong&gt; Render hosts the working client and Python API in a Docker web service, with server-side Gemma credentials, a health check and public interactive API documentation. The selected hosting plan is Free.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>UNWATCH: finding what a second tutorial actually adds</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Sun, 25 Oct 2026 07:58:09 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/unwatch-finding-what-a-second-tutorial-actually-adds-4hm0</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/unwatch-finding-what-a-second-tutorial-actually-adds-4hm0</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;My sister is preparing for her board exams alongside &lt;strong&gt;NIFT and UCEED 2027&lt;/strong&gt;. Her study time has to stretch across schoolwork and entrance preparation, and YouTube is part of that routine.&lt;/p&gt;

&lt;p&gt;She had already watched &lt;a href="https://www.youtube.com/live/WEedKEfzRm8" rel="noopener noreferrer"&gt;one preparation session&lt;/a&gt;. When she wanted to move to another video, the question was simple: &lt;strong&gt;which parts would actually add something?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;She wanted the explanations she had missed, the extra facts and figures, and a different way of understanding a topic. Finding those parts meant spending more time watching material she had already covered. The video could be useful, but she had to sit through it to find out where.&lt;/p&gt;

&lt;p&gt;That is where &lt;strong&gt;UNWATCH&lt;/strong&gt; started. Before asking someone to commit to another lesson, could an app show them what appears familiar, what seems new, and the evidence behind that judgement?&lt;/p&gt;

&lt;p&gt;I built it to compare those two tutorials. Paste the YouTube link you've watched and the one you're considering. UNWATCH reads the available captions, identifies possible repetitions, and creates an editable watchlist of the original video sections. New examples and uncertain material stay included.&lt;/p&gt;

&lt;p&gt;The useful part happens before you press Play. Each proposed skip comes with source caption excerpts. You can check the reasoning, restore a section, and watch the original video at the selected intervals. No subtitle upload or extension is needed.&lt;/p&gt;

&lt;p&gt;The theme is “Slow and Steady.” For someone juggling two sets of exams, spending less time finding the useful part leaves more time to work through it.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live app:&lt;/strong&gt; &lt;a href="https://unwatch-byeb.onrender.com/" rel="noopener noreferrer"&gt;unwatch-byeb.onrender.com&lt;/a&gt; · &lt;a href="https://unwatch-byeb.onrender.com/workspace" rel="noopener noreferrer"&gt;Open the workspace&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://unwatch-byeb.onrender.com" rel="noopener noreferrer"&gt;Try UNWATCH&lt;/a&gt; · &lt;a href="https://unwatch-byeb.onrender.com/demo/" rel="noopener noreferrer"&gt;Watch the short walkthrough&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Replay a real result&lt;/strong&gt; to open the exact measured comparison without spending credits. The public site also includes a clearly labeled illustrative example. The 2 minute 21 second walkthrough is edited from my real screen recording, with local synthetic narration, captions, and an original ambient score. Waiting is shortened. It shows a fresh long React comparison and then the separately labelled saved React result. The live results below come from real YouTube captions and a real transcription path, rather than that example.&lt;/p&gt;

&lt;p&gt;In one React comparison, the second tutorial used an interactive 3D scene to teach state. UNWATCH kept those examples and proposed omitting only a repeated explanation of the state value and setter. Its assessed timeline went from &lt;strong&gt;9:56 to 8:57&lt;/strong&gt;, with &lt;strong&gt;59.481 seconds&lt;/strong&gt; left out after context padding. I checked both cited caption excerpts. I can include the section again with one click.&lt;/p&gt;

&lt;p&gt;Four other comparison configurations kept everything. That includes an unrelated React/Docker pair: two videos sharing words like “application” does not make their explanations interchangeable.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/Reet24-del/unwatch" rel="noopener noreferrer"&gt;Source code and setup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project uses React, TypeScript, Express, and shared validation schemas. The workflow lives in &lt;code&gt;server/workflow.ts&lt;/code&gt;, provider adapters in &lt;code&gt;server/providers.ts&lt;/code&gt;, and section validation and playback ranges in &lt;code&gt;shared/domain.ts&lt;/code&gt;. The repository includes an MIT license, setup instructions, application budget controls, and known limitations.&lt;/p&gt;

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

&lt;p&gt;The core path is simple: retrieve timed speech, compare the explanations, validate the proposed sections, then let the learner review them. Seven partner services support that path. Each has a specific job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mastra: make the comparison a workflow
&lt;/h3&gt;

&lt;p&gt;The open-source Mastra workflow runs caption retrieval and then comparison, with typed input and output schemas between the steps. Citation and timeline validation run inside that comparison path. This makes the boundary between retrieved evidence and a suggested watchlist visible in the code. For the learner, it means the app can stop with a useful error instead of presenting an unsupported result. &lt;a href="https://github.com/Reet24-del/unwatch/blob/main/server/workflow.ts" rel="noopener noreferrer"&gt;Workflow code&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  SerpApi: turn a YouTube link into timed source material
&lt;/h3&gt;

&lt;p&gt;UNWATCH calls SerpApi's &lt;code&gt;youtube_video_transcript&lt;/code&gt; engine to retrieve captions and their timestamps. Those timestamps connect a proposed section to the original video and support the evidence links. The user pastes a link instead of downloading a video or uploading subtitles. This is caption retrieval, rather than a general web-search feature. &lt;a href="https://github.com/Reet24-del/unwatch/blob/main/server/providers.ts" rel="noopener noreferrer"&gt;Retrieval adapter&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ElevenLabs: recover speech when captions are missing
&lt;/h3&gt;

&lt;p&gt;When the caption route has no usable text, the optional Scribe fallback submits the canonical YouTube URL as &lt;code&gt;source_url&lt;/code&gt; and requests timed transcription. A real captionless Docker source passed through this path during development; later runs reused the cached transcript. This widens the set of videos the app can compare, but source access, account allowance, and the prototype's attempt cap still apply. The demo's voiceover uses local Kokoro speech; ElevenLabs is integrated for tutorial transcription. &lt;a href="https://github.com/Reet24-del/unwatch/blob/main/server/providers.ts" rel="noopener noreferrer"&gt;Transcription adapter&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ultramarine: compare explanations, not just matching words
&lt;/h3&gt;

&lt;p&gt;Paper Instruments' Ultramarine model reads the timed transcripts and proposes sections, reasons, caption references, and an assessment of whether each section adds a distinct detail. The server checks those references before showing the result. A repeated term alone should not remove a new example or caveat. The measured React result below records its tokens and estimated model cost. &lt;a href="https://github.com/Reet24-del/unwatch/blob/main/server/providers.ts" rel="noopener noreferrer"&gt;Comparison adapter&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  MongoDB Atlas: remember sessions and preserve the allowance
&lt;/h3&gt;

&lt;p&gt;Atlas stores account-scoped comparisons and expiring caption caches, so a saved session can reopen and a cached transcript can be reused. It also stores the shared provider-budget ledger. Atomic conditional reservations check the remaining allowance before a call, including when requests arrive together; restarting the server does not reset that ledger. This keeps a public prototype manageable within its configured allowance. &lt;a href="https://github.com/Reet24-del/unwatch/blob/main/server/store.ts" rel="noopener noreferrer"&gt;Store implementation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auth0: connect the workflow to the right account
&lt;/h3&gt;

&lt;p&gt;Auth0 handles sign-in and supplies access tokens. The backend verifies their signature, issuer, and audience, then uses the verified user identity to scope saved-session access. A learner can explicitly sync a comparison and reopen it from their account. Sign-in and session sync passed a real one-account public test; owner isolation also has automated coverage. The project does not use Token Vault or fine-grained authorization. &lt;a href="https://github.com/Reet24-del/unwatch/blob/main/server/auth.ts" rel="noopener noreferrer"&gt;Authentication code&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Render: put the whole app behind one public URL
&lt;/h3&gt;

&lt;p&gt;A free Render web service hosts the built React interface and Express API together. Provider credentials stay on the server, and the frontend calls the same-origin API. Judges can open the workspace or replay a saved real result without installing the project. A free instance may need time to wake up. &lt;a href="https://github.com/Reet24-del/unwatch/blob/main/render.yaml" rel="noopener noreferrer"&gt;Deployment configuration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first hard lesson was that a citation can be valid while a skip is wrong. An early result marked a Docker/VM explanation as repeated, even though it added an OS-compatibility caveat. I tightened the prompt and added an explicit check for distinct details. A section stays included when the model identifies an extra example, caveat, or practical step—or fails to supply that assessment.&lt;/p&gt;

&lt;p&gt;Long videos exposed another problem. One malformed model response could throw away the entire comparison. The chunk handler now retains an unassessed part and preserves usable parts around it. It tells the user what happened. It also withholds a total-cost estimate if usage data is incomplete. That recovery has a regression test. The screen recording also shows a fresh long React comparison retaining roughly 80 minutes and omitting nothing. It demonstrates the normal long-video path; malformed-part recovery was tested with simulated responses rather than deliberately triggered in production.&lt;/p&gt;

&lt;p&gt;The current automated suite has &lt;strong&gt;20 passing tests&lt;/strong&gt;. It covers source validation, caption caching and transcription fallback, grounded section references, long-video timelines, conservative recovery, and budget isolation. The production build passes. In browser checks, a real YouTube embed started at a selected timestamp, paused, navigated to another interval, and offered full-video mode.&lt;/p&gt;

&lt;p&gt;The real React run returned 19,563 input and 2,170 output tokens: &lt;strong&gt;$0.00401945 in estimated model usage&lt;/strong&gt; at the adapter's configured rates. Five successful configurations totaled $0.02435370. Those figures exclude caption/transcription usage and failed requests. They are token-based estimates, not provider billing statements. The full development evaluation is included with the code.&lt;/p&gt;

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

&lt;p&gt;Mastra is the open-source framework at the center of the app's AI workflow. Its steps are explicit and inspectable: fetch the source, compare it, then validate what can be shown to the learner. The validation rules and provider adapters are also available in the project source, so another builder can change the comparison behavior or substitute a provider.&lt;/p&gt;

&lt;p&gt;That mattered when I found the bad skip. I could change the validation boundary and add a focused regression test. The learner's review UI did not need to change. This is a hosted-model prototype; I am not claiming offline inference or an open-weight model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;My sister has tried the prototype. Her first use case is choosing which parts of a second preparation video deserve her attention: a new explanation, an additional fact, or a detail the previous lesson did not cover. The goal is to leave more time for the rest of her preparation.&lt;/p&gt;

&lt;p&gt;The exam-preparation story explains who I built for. The measured comparisons in this post use programming tutorials; evaluating NIFT and UCEED lessons is the next step.&lt;/p&gt;

&lt;p&gt;UNWATCH takes on the comparison work: finding the repeated explanation, showing its evidence, and lining up the remaining intervals. The learner keeps the final decision.&lt;/p&gt;

&lt;p&gt;The current pilot is deliberately modest: five configurations, with reversed pairs among them, covering two main topic groups plus an unrelated-topic check. Only one section was proposed for omission. It is enough to demonstrate the workflow, but not enough to claim general accuracy or improved learning. Caption analysis also cannot judge silent demonstrations reliably, so those deserve extra care.&lt;/p&gt;

&lt;p&gt;My next improvement would be a broader review set and feedback on which suggested skips people restore. For this prototype, I want each suggested shortcut to be explainable and easy to undo.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render:&lt;/strong&gt; the public React interface and Express API run together on a real free Render web service. The public replay lets judges inspect a saved live result without new inference requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Mastra:&lt;/strong&gt; the actual comparison route executes the open-source workflow for retrieval, comparison and validation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Ultramarine:&lt;/strong&gt; it reasons over the real transcripts; the token counts and estimated run costs above show what it did.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of ElevenLabs:&lt;/strong&gt; Scribe transcribed a real captionless Docker source and supplied timed text to the workflow. Later evaluation runs reused that cached transcript.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of SerpApi:&lt;/strong&gt; its YouTube transcript API supplies source captions and timestamps that ground the comparison. This is the project's specific use of SerpApi.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of MongoDB Atlas:&lt;/strong&gt; account sessions, expiring caption caches, and atomic provider-budget reservations use the connected Atlas database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of Auth0 for AI Agents:&lt;/strong&gt; Google sign-in and verified access tokens protect live comparisons and account session sync.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used Codex to help implement, test, and edit the project. The demo narration uses local Kokoro synthetic speech. Backboard and Sentry are not connected and are not category claims. Public live requests remain subject to provider availability and the application allowance; the saved real result stays available without new provider calls.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Hijack Radar: your lockfile said you were safe. Your dependency graph knew better.</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 17:44:05 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/hijack-radar-your-lockfile-said-you-were-safe-your-dependency-graph-knew-better-4741</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/hijack-radar-your-lockfile-said-you-were-safe-your-dependency-graph-knew-better-4741</guid>
      <description>&lt;h2&gt;
  
  
  Monday, September 8, 2025
&lt;/h2&gt;

&lt;p&gt;A maintainer of some of the most-used packages on npm gets an email. It says their two-factor settings need updating before the 10th. The link looks like npm. It isn't.&lt;/p&gt;

&lt;p&gt;Minutes later, new versions of 18 packages appear on the registry, &lt;code&gt;chalk&lt;/code&gt; and &lt;code&gt;debug&lt;/code&gt; among them. Together they're downloaded about &lt;strong&gt;2.6 billion times a week&lt;/strong&gt;. The new code quietly rewrites crypto wallet transactions in the browser. The bad versions are pulled within hours, but every engineering team spends that afternoon asking the same question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Were we hit?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The obvious way to answer is to search your repos for &lt;code&gt;debug&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;. We did exactly that across 17 real open-source codebases: VS Code, Playwright, Bitwarden, Jitsi Meet, Expensify and more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One&lt;/strong&gt; repo declares &lt;code&gt;debug&lt;/code&gt;. &lt;strong&gt;All seventeen&lt;/strong&gt; install it.&lt;/p&gt;

&lt;p&gt;The other sixteen pull it in through chains like &lt;code&gt;vscode → eslint@10.8.0 → debug@4.4.3&lt;/code&gt;. A text search can't see those chains. A graph can. That gap is the whole project.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What Hijack Radar does
&lt;/h2&gt;

&lt;p&gt;Hijack Radar is an AI agent for the attacks CVE scanners weren't built for: &lt;strong&gt;account takeovers and hijacked releases&lt;/strong&gt;. You ask in plain English, and it answers from a FalkorDB graph of what your repos &lt;em&gt;really&lt;/em&gt; install, with the exact path behind every answer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"If the npm account &lt;code&gt;qix&lt;/code&gt; were phished, what would it reach?"&lt;/strong&gt; That account publishes 7 packages, and they reach all 17 repos. The answer comes back in milliseconds, with a path for each repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"MAL-2025-46974 just dropped. Are we affected?"&lt;/strong&gt; This is the real advisory from that day. A lockfile scanner says &lt;em&gt;safe&lt;/em&gt;, because no lockfile pins &lt;code&gt;debug@4.4.2&lt;/code&gt;. The agent says that honestly, then checks the version ranges: &lt;strong&gt;217 of them accept the hijacked release&lt;/strong&gt;, so your next &lt;code&gt;npm update&lt;/code&gt; would have pulled it into every repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Where is our next xz?"&lt;/strong&gt; PageRank over the dependency graph, filtered to packages that a single npm account controls. These are the load-bearing packages nobody is watching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"We'll pin debug with overrides everywhere. Remember that, and draft an issue for jitsi-meet."&lt;/strong&gt; The decision is stored as a dated node in the graph, and the agent drafts the fix for the owning team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every answer sits next to an &lt;strong&gt;evidence panel&lt;/strong&gt;: the tool calls it made, how long FalkorDB took, and a graph of every dependency path it found, with repos in blue and the compromised package in red. There's also a &lt;strong&gt;radar view&lt;/strong&gt;: the 17 repos as dots, one ring per dependency hop. Replay an attack and the sweep lights up every exposed repo on the ring where the graph reaches it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this has to be a graph
&lt;/h2&gt;

&lt;p&gt;Supply-chain questions are questions about &lt;strong&gt;connections&lt;/strong&gt;, and they're several hops deep:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Maintainer&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:MAINTAINS&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Package&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:HAS_VERSION&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Version&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Repo&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:DEPENDS_ON&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="ss"&gt;}]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Version&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:DEPENDS_ON&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="ss"&gt;}]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Version&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Advisory&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:AFFECTS&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Version&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Team&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:OWNS&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Repo&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Decision&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:ABOUT&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Repo&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;:Package&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;:Advisory&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We parse real &lt;code&gt;package-lock.json&lt;/code&gt; files using Node's own module-resolution rules, so the graph holds what is &lt;em&gt;installed&lt;/em&gt;, not just what is declared. Then we add advisories from OSV.dev and maintainer usernames from the npm registry. The result is 17 repos, 11,179 package versions, &lt;strong&gt;33,233 dependency edges&lt;/strong&gt;, 357 advisories and 4,099 maintainers. It fits in about 19 MB.&lt;/p&gt;

&lt;p&gt;Two modelling choices did most of the work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Every dependency edge stores its semver range.&lt;/strong&gt; That's how we answer "would a lockfile refresh pull the hijacked version?", the question that mattered on September 8 and that lockfile scanners can't answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainers are nodes.&lt;/strong&gt; "If this account is phished" becomes a traversal: person → packages → every version → every repo that reaches one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The core query is short:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Package&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;name:&lt;/span&gt; &lt;span class="n"&gt;$name&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:HAS_VERSION&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;v:&lt;/span&gt;&lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;r:&lt;/span&gt;&lt;span class="n"&gt;Repo&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;shortestPath&lt;/span&gt;&lt;span class="ss"&gt;((&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:DEPENDS_ON&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="ss"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="ow"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v.version&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;versions&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="ss"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;r.name&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="ss"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;IN&lt;/span&gt; &lt;span class="nf"&gt;nodes&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;coalesce&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n.id&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n.name&lt;/span&gt;&lt;span class="ss"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On a laptop, it answers for all 17 repos in about 30 ms. We also use FalkorDB's built-in algorithms as tools: &lt;code&gt;algo.SPpaths&lt;/code&gt; to list every equally short chain between a repo and a package, and &lt;code&gt;algo.pageRank&lt;/code&gt; to find the "next xz".&lt;/p&gt;
&lt;h2&gt;
  
  
  How the agent works
&lt;/h2&gt;

&lt;p&gt;We set one rule early: &lt;strong&gt;the model never writes Cypher.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The agent picks from &lt;strong&gt;13 fixed tools&lt;/strong&gt;, served over &lt;strong&gt;MCP&lt;/strong&gt;. Each tool runs a parameterised query we wrote and tested. Before any traversal runs, the tool checks that the package, repo, maintainer or advisory actually exists in the graph. Unknown names get suggestions back, never a guess.&lt;/p&gt;

&lt;p&gt;Every result carries an explicit outcome: &lt;code&gt;answered&lt;/code&gt;, &lt;code&gt;not_in_graph&lt;/code&gt;, &lt;code&gt;unknown_package&lt;/code&gt; or &lt;code&gt;answered_from_memory&lt;/code&gt;. That's what keeps the agent honest. For the real Sept 2025 advisory, it says &lt;em&gt;"not in the graph, not that you're safe"&lt;/em&gt; and then checks the ranges, instead of announcing an all-clear.&lt;/p&gt;

&lt;p&gt;The model is &lt;strong&gt;Groq's &lt;code&gt;gpt-oss-120b&lt;/code&gt;&lt;/strong&gt;. The free tier is small (8,000 tokens a minute), so the model only reads the first rows of each tool result, plus a count. The UI still draws every path, because it gets the full result separately. The same 13 tools also work in Claude Code or Claude Desktop over MCP: the web agent is just one client.&lt;/p&gt;
&lt;h2&gt;
  
  
  The tracks we entered, and why it fits
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Track 01: Agents That Act on Connected Data
&lt;/h3&gt;

&lt;p&gt;This track asks for agents that use the graph to &lt;em&gt;decide and act&lt;/em&gt;: multi-hop reasoning, graph algorithms as tools, tool selection through MCP, and explainable results. That's Hijack Radar's core:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-hop reasoning:&lt;/strong&gt; every answer is a traversal across up to several hops, from maintainer to package to version to repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graph algorithms as tools:&lt;/strong&gt; &lt;code&gt;shortestPath&lt;/code&gt;, &lt;code&gt;algo.SPpaths&lt;/code&gt; and &lt;code&gt;algo.pageRank&lt;/code&gt; are tools the agent chooses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP tool selection:&lt;/strong&gt; 13 fixed tools, and the model picks which ones to call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; it suggests an npm &lt;code&gt;overrides&lt;/code&gt; fix and drafts an issue for the team that owns the repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explainable:&lt;/strong&gt; every result carries its dependency path, drawn beside the answer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Track 02: Agent Memory and Coordination
&lt;/h3&gt;

&lt;p&gt;This track asks for agents that remember across sessions and keep separate memory per user or tenant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory as graph nodes:&lt;/strong&gt; a triage decision such as "pin debug with overrides" becomes a dated &lt;code&gt;Decision&lt;/code&gt; node linked to the package. Later answers about &lt;code&gt;debug&lt;/code&gt;, or about advisories that touch it, come back with that decision attached: who decided and when.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared across agents:&lt;/strong&gt; the memory lives in the graph, not in a chat window, so every MCP client (our web agent, Claude Code, Claude Desktop) sees the same decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One graph per company:&lt;/strong&gt; each tenant gets its own isolated graph on the same FalkorDB instance (&lt;code&gt;supplychain&lt;/code&gt; and &lt;code&gt;supplychain:orbit&lt;/code&gt; in our demo). The server pins each chat to its tenant, and the model never even sees the tenant argument. Ask about &lt;code&gt;debug&lt;/code&gt; as our second demo company, Orbit, and you get Orbit's 5 repos, none of which declare &lt;code&gt;debug&lt;/code&gt; and all of which install it. Orbit's decisions never appear for anyone else.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Things that bit us
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unbounded path enumeration.&lt;/strong&gt; Our first &lt;code&gt;algo.SPpaths&lt;/code&gt; call hung when the target wasn't reachable, because it tried to enumerate every path in the tree. Running &lt;code&gt;shortestPath&lt;/code&gt; first and passing its length as &lt;code&gt;maxLen&lt;/code&gt; brought it down to a few milliseconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An empty graph is an error, not an empty result.&lt;/strong&gt; A fresh cloud instance made our health check fail and the host restart the app in a loop. Now health reports the problem instead of crashing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lockfiles are subtle.&lt;/strong&gt; Nested &lt;code&gt;node_modules&lt;/code&gt;, symlinked workspaces, npm aliases (&lt;code&gt;string-width-cjs&lt;/code&gt; is really &lt;code&gt;string-width&lt;/code&gt;) and optional platform packages all have to be handled before the graph tells the truth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts need to say what the UI needs.&lt;/strong&gt; On the first real run, the model answered "who installs debug?" from memory instead of calling the tool, so the graph never appeared. One line in the prompt ("call tools for every question; the page draws evidence only from this turn") fixed it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Try it
&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/Reet24-del" rel="noopener noreferrer"&gt;
        Reet24-del
      &lt;/a&gt; / &lt;a href="https://github.com/Reet24-del/supply-chain-blast-radius" rel="noopener noreferrer"&gt;
        supply-chain-blast-radius
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Hijack Radar: an agent that traces phished npm maintainers and hijacked releases through a FalkorDB dependency graph (Graph Hacks 2026)
    &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;Hijack Radar&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;An npm maintainer gets phished and a release is hijacked. What did you just install, including what your lockfile says is safe?&lt;/strong&gt;
Hijack Radar is an agent that traces account takeovers and hijacked releases through a FalkorDB graph of your real, installed dependency trees, and shows the path behind every answer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Radar view&lt;/strong&gt; (&lt;code&gt;/radar.html&lt;/code&gt;): the 17 repos as dots on a radar, with one ring per dependency hop. Pick an attack, such as a phished maintainer or the Sept 2025 &lt;code&gt;debug@4.4.2&lt;/code&gt; hijack, and the sweep lights up every exposed repo on the ring where the graph reaches it.&lt;/p&gt;
&lt;p&gt;CVE scanners answer "which of my pinned versions is vulnerable?". Hijack Radar answers the questions they can't:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"If this maintainer's account is phished, what can the attacker publish into our repos?"&lt;/strong&gt; Maintainers are nodes, so an account takeover is a traversal from a person to packages to every…&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/Reet24-del/supply-chain-blast-radius" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The README has the graph model and every Cypher query the product depends on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run it locally.&lt;/strong&gt; Hijack Radar runs on your own machine with an embedded FalkorDB engine, no Docker and no cloud account needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Reet24-del/supply-chain-blast-radius &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;supply-chain-blast-radius
uv &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;--extra&lt;/span&gt; lite
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FALKORDB_LITE_PATH=.falkordb/lite.db"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .env
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"GROQ_API_KEY=your-free-key"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .env     &lt;span class="c"&gt;# free at console.groq.com&lt;/span&gt;
uv run blast-ingest &lt;span class="nt"&gt;--reset&lt;/span&gt;                    &lt;span class="c"&gt;# loads the 17 real lockfiles (~3 min the first time)&lt;/span&gt;
uv run blast-web                               &lt;span class="c"&gt;# http://localhost:8000, plus /radar.html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefer Docker? &lt;code&gt;docker compose up -d&lt;/code&gt; starts FalkorDB with its browser UI, and the same code also runs against FalkorDB Cloud.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built for **Graph Hacks: Context for AI Agents&lt;/em&gt;* (FalkorDB × WeMakeDevs), October 2026. Built with Claude Code as a coding assistant, as disclosed in the README.*&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>javascript</category>
      <category>node</category>
      <category>security</category>
    </item>
    <item>
      <title>“Simple site hai, 15k mein ho jayega na?” I built Panga so freelancers stop saying yes too fast</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 07:27:53 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/simple-site-hai-15k-mein-ho-jayega-na-i-built-panga-so-freelancers-stop-saying-yes-too-fast-5454</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/simple-site-hai-15k-mein-ho-jayega-na-i-built-panga-so-freelancers-stop-saying-yes-too-fast-5454</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&lt;/a&gt;: Side Hustle.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's 9:41 on a Tuesday night when Mr Sharma's email lands.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Namaste! I run Sharma Tuition Classes in Lucknow for class 9 to 12. We need a simple website showing our courses, our teachers, last year's results and a contact form. Just 4-5 pages. Our budget is ₹12,000.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Easy money. You've built this site twenty times. You reply &lt;em&gt;"Haan ji, ho jayega"&lt;/em&gt; and put the phone down.&lt;/p&gt;

&lt;p&gt;It buzzes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;parents should be able to pay the monthly fees online also, UPI se&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It buzzes again.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;and students will login to download notes and old papers&lt;/em&gt;&lt;br&gt;
&lt;em&gt;weekly online test bhi ho jaye with marks, that will be very good&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Hindi version bhi chahiye, most parents prefer Hindi&lt;/em&gt;&lt;br&gt;
&lt;em&gt;every result season we will send topper photos, you put them on the site&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then the line every freelancer in India has heard at least once:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;bas simple sa hi hai na&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fourteen minutes, six messages. The "simple site" now has a payment flow, a student login, an exam system, a second language and a maintenance job that never ends. The budget is still ₹12,000.&lt;/p&gt;

&lt;p&gt;You find out what that means three weeks later, at 2 AM, when you finally add up the hours. About ninety-two of them. That's &lt;strong&gt;₹130 an hour&lt;/strong&gt;, before the first "small change".&lt;/p&gt;

&lt;p&gt;There's a Hindi word for this kind of trouble: &lt;strong&gt;panga&lt;/strong&gt;. Trouble you pick on purpose.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Panga&lt;/strong&gt;, a deal room that reads the brief &lt;em&gt;and&lt;/em&gt; the chat, finds the work hiding in it, shows what the deal really pays per hour, and lets you rehearse the awkward call with a pushy client &lt;strong&gt;before&lt;/strong&gt; you say yes. Then it helps you answer the only question that matters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lena hai? Negotiate karna hai? Ya chhodna hai?&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Take it, change the deal, or walk away?&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;The demo video above is Panga running live on the Sharma deal, narrated with ElevenLabs.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The pain nobody puts on their portfolio
&lt;/h2&gt;

&lt;p&gt;Freelance developers are good at building things. We lose money before the building starts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The scope isn't in the brief. It's in the chat.&lt;/strong&gt; The email says "4-5 pages". The WhatsApp thread quietly adds payments, logins and a translation, spread over six messages and three days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We price by feel.&lt;/strong&gt; "₹12,000 feels right for a small site." Nobody divides the price by the real hours until the project is half done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Small changes later also."&lt;/strong&gt; The most expensive sentence in freelancing. Unlimited revisions with no line item.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We say yes on calls.&lt;/strong&gt; The client pushes, the silence gets awkward, and &lt;em&gt;"haan, ho jayega"&lt;/em&gt; slips out. Nobody writes it down. The client remembers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The reply takes an hour.&lt;/strong&gt; Saying "this costs more" politely, in the right tone, without sounding greedy, is hard. So we don't say it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We never learn.&lt;/strong&gt; The last project ran forty percent over. The next quote is still a guess.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is a coding problem. It's a reading, maths and nerve problem. Those are things software can actually help with.&lt;/p&gt;

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

&lt;p&gt;Panga turns a messy deal into four steps. Here's what it did with Mr Sharma's messages, live, in about 30 seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  01 The work: find what's hiding in the chat
&lt;/h3&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%2Fkohnn3z11nxpgzw0pf1h.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%2Fkohnn3z11nxpgzw0pf1h.png" alt="The work: every item quotes the client, hidden items are marked" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gemma reads the brief and the chat and lists every piece of work. Panga found &lt;strong&gt;the website from the email and five more jobs in the chat&lt;/strong&gt;: UPI fee payments, a student login for notes, weekly online tests, a Hindi version, and topper photos every result season.&lt;/p&gt;

&lt;p&gt;The rule that makes this trustworthy: &lt;strong&gt;every item must quote the client word for word, and Panga checks each quote against the original text.&lt;/strong&gt; If the model invents a quote, Panga throws the item away. Click a quote and the client's own message lights up on the right.&lt;/p&gt;

&lt;p&gt;It also gets the small things right:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hosting&lt;/strong&gt; was never mentioned, so it's listed as "nobody asked for this" and &lt;strong&gt;not priced&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;"before April" deadline isn't treated as work&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;₹12,000&lt;/strong&gt; came straight out of the email, with the quote it came from.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unsure what an online test system involves? &lt;strong&gt;What's involved?&lt;/strong&gt; runs a live web search with SerpApi and explains it with numbered sources.&lt;/p&gt;

&lt;h3&gt;
  
  
  02 The money: the real hourly rate
&lt;/h3&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%2Fcnrfpsq87p0thlp7t2fk.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%2Fcnrfpsq87p0thlp7t2fk.png" alt="The money: 92 hours, ₹130 an hour, ₹70,000 to be worth it" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of that work adds up to about &lt;strong&gt;92 hours&lt;/strong&gt;. At ₹12,000 that's &lt;strong&gt;₹130 an hour&lt;/strong&gt; against a ₹700 minimum. To be worth your time, the full job should be &lt;strong&gt;₹70,000&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This part is plain TypeScript, not AI. Every number has a &lt;strong&gt;"How?"&lt;/strong&gt; that shows its formula, and you can change your rate, revision rounds or buffer and watch everything update. A "what if the small changes never stop?" slider shows the rate sinking further.&lt;/p&gt;

&lt;h3&gt;
  
  
  03 Client from hell: practise the call
&lt;/h3&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%2F17d66va0mn92u3unad2u.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%2F17d66va0mn92u3unad2u.png" alt="Practice call with the pretend client" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A pretend client who has read &lt;em&gt;only this brief&lt;/em&gt; calls you, by text or by voice, and pushes on every gap using his own messages. In the demo I answered the way most of us do, a little too nicely:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Haan ji, notes ka portal bhi bana dunga, no problem."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When the call ends, the replay shows exactly what that cost:&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%2Fug41ufo223asfxs3bmo0.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%2Fug41ufo223asfxs3bmo0.png" alt="Replay: Panga flags the free portal you just promised" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That easy "no problem" is flagged as &lt;strong&gt;extra work&lt;/strong&gt; you just promised for free. The price talk is flagged too, with a suggestion for pinning each one down. You can add the promise to the work list in one click.&lt;/p&gt;

&lt;h3&gt;
  
  
  04 Your call: take it, change it, or walk
&lt;/h3&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%2Fjvqdzkeqldss7q2n0bio.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%2Fjvqdzkeqldss7q2n0bio.png" alt="Three options: ₹12,000 starter, ₹70,000 full scope, or walk away" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Panga lays out three options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Change the deal:&lt;/strong&gt; a smaller package that fits the client's ₹12,000, with what's left out written down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Take it, at your price:&lt;/strong&gt; everything they asked for, at ₹70,000.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Walk away:&lt;/strong&gt; a polite no.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pick one, and it drafts the reply in your tone, &lt;strong&gt;including Hinglish&lt;/strong&gt;. It then checks that &lt;strong&gt;every amount in the reply matches its own numbers&lt;/strong&gt;, so a hallucinated "₹9,000" can't sneak into a message to your client.&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%2F0xwqo04bigj8o2o875lm.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%2F0xwqo04bigj8o2o875lm.png" alt="The drafted reply in Hinglish" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You approve it. &lt;strong&gt;Panga never messages your client. You do.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the project ends, you record how long it really took. That becomes a past project, and the next similar brief shows it, for example: &lt;em&gt;"Kurta shop: estimated 50 h, took 72 h. Product import took twice as long as quoted."&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Who would pay for this
&lt;/h3&gt;

&lt;p&gt;Freelance web developers and small studios who quote fixed prices, especially for the ₹10k–₹50k "simple website" jobs where scope creep hurts most. One avoided free student portal pays for years of the tool.&lt;/p&gt;

&lt;p&gt;The plan is &lt;strong&gt;₹49 per deal check, or ₹299 a month&lt;/strong&gt;. A full check costs Panga &lt;strong&gt;well under ₹1&lt;/strong&gt; in model calls, so the numbers work even at Indian freelance prices.&lt;/p&gt;

&lt;h2&gt;
  
  
  My first user
&lt;/h2&gt;

&lt;p&gt;My first real user is a friend of mine who runs social media for small businesses. He edits videos, turns them into Instagram reels, runs campaigns, and sometimes makes websites and pamphlets. His usual rate for maintaining an account is ₹6,000 a month.&lt;/p&gt;

&lt;p&gt;One client, a woman with an Instagram account that was more or less dead, asked him to revive and maintain it for ₹1,000 a month. Her pitch was simple: "I'll manage the account myself too, so you won't have to do much."&lt;/p&gt;

&lt;p&gt;That isn't how it went. Every few days there's a new ask: come and record my videos, do this small extra thing, just one more edit. None of it is paid. He wanted to sit down with her and have a proper conversation, but he knew how these talks go. She negotiates well, the silence gets awkward, and his point gets cut short.&lt;/p&gt;

&lt;p&gt;So before the talk, he put their chat into Panga. It laid out the extra work hiding in the chat, the recording days and the edits that were never part of the ₹1,000 deal, with her own messages next to each one. It showed what that deal really pays per hour once the extras are counted. He practised the conversation against a client who pushes back the way she does, and walked in knowing exactly what he wanted to say.&lt;/p&gt;

&lt;p&gt;This is the case I built Panga for, even though I first wrote it with websites in mind: a freelancer who is good at the work, underpaid by a client who is good at negotiating, and who just needs the facts in front of him before he says "haan, ho jayega" one more time.&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://panga-gnb2.onrender.com" rel="noopener noreferrer"&gt;panga-gnb2.onrender.com&lt;/a&gt;. It's on a free instance, so the first visit after a quiet spell can take about 50 seconds to wake up. Click &lt;strong&gt;Try the sample deal&lt;/strong&gt;, or paste the Sharma example below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/Reet24-del/panga" rel="noopener noreferrer"&gt;github.com/Reet24-del/panga&lt;/a&gt; (MIT)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;/p&gt;
  The Sharma Tuitions example (paste this into Panga)
  &lt;p&gt;&lt;strong&gt;What's the project?&lt;/strong&gt; Sharma Tuitions website&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Brief:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Namaste! I run Sharma Tuition Classes in Lucknow for class 9 to 12. We need a simple website showing our courses, our teachers, last year's results and a contact form. Just 4-5 pages. Our budget is ₹12,000.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Chat:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[9:41] Mr Sharma: aapka kaam dekha, accha laga
[9:43] Mr Sharma: parents should be able to pay the monthly fees online also, UPI se
[9:44] Mr Sharma: and students will login to download notes and old papers
[9:47] Mr Sharma: weekly online test bhi ho jaye with marks, that will be very good
[9:50] Mr Sharma: Hindi version bhi chahiye, most parents prefer Hindi
[9:52] Mr Sharma: every result season we will send topper photos, you put them on the site
[9:55] Mr Sharma: admission season starts 1st April so before that please. bas simple sa hi hai na
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open innovation matters here
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Client briefs are private.&lt;/strong&gt; They hold prices, business plans and sometimes customers' names. Panga runs on open-weight models: &lt;strong&gt;Gemma 4&lt;/strong&gt; (&lt;code&gt;gemma-4-31B-it&lt;/code&gt;) for reasoning and &lt;strong&gt;Qwen3&lt;/strong&gt; (&lt;code&gt;qwen3-embedding-0.6b&lt;/code&gt;) for search, served by DigitalOcean. Neither is a closed vendor's model whose terms can change under me. Panga talks to any OpenAI-compatible endpoint, so a freelancer who wants nothing leaving their machine can point it at Gemma on their own laptop or GPU box by changing a couple of settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The business only works if it's cheap.&lt;/strong&gt; A deal check is several model calls: extraction, a practice call, a replay, research, a reply. On an open model with serverless inference, that's well under a rupee, which is what makes a ₹49 price possible for people who are themselves paid in rupees.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The trust doesn't depend on the model being perfect.&lt;/strong&gt; Open models make mistakes, and so do closed ones. Panga doesn't hope Gemma is right. It checks: quotes must match the source, maths is done in code, and reply amounts are verified. That makes a smaller open model good enough for a job where money is on the line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The whole stack is open.&lt;/strong&gt; Mastra for agents, Temporal for workflows, Postgres with pgvector for search, and Panga itself under MIT.&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;Browser ──► Next.js on Render ──► Mastra agents ──► Gemma 4 on DigitalOcean
               │                                   (scope analyst, researcher,
               │                                    client simulator, writer)
               ├──► Tiger Data (Postgres + pgvector): deals, past projects, hybrid search
               ├──► Backboard: memory of your rates, tone and corrections
               ├──► SerpApi: "What's involved?" research with sources
               └──► Sentry: traces of every agent run and model call

Voice call: Browser ──► ElevenLabs agent ──(Custom LLM)──► Panga /api/sim ──► Gemma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;106 automated tests&lt;/strong&gt; cover the money maths (including a worked example from the spec), quote matching, the practice call's hidden tags, reply amount checks, the database layer and the deal workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every sponsor in Panga, and exactly what it does
&lt;/h2&gt;

&lt;p&gt;Panga uses ten of this challenge's partners. Nine run in the live demo. One (Temporal) is built and tested but switched off on the free deployment, and I say why below.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sponsor&lt;/th&gt;
&lt;th&gt;Its job in Panga&lt;/th&gt;
&lt;th&gt;Live in the demo?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DigitalOcean&lt;/td&gt;
&lt;td&gt;Runs every AI call: Gemma 4 and the Qwen3 embeddings&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma&lt;/td&gt;
&lt;td&gt;The only reasoning model&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mastra&lt;/td&gt;
&lt;td&gt;The four agents&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ElevenLabs&lt;/td&gt;
&lt;td&gt;Voice practice call, voice-note transcription, demo narration&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tiger Data&lt;/td&gt;
&lt;td&gt;The database, and hybrid search over past projects&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backboard&lt;/td&gt;
&lt;td&gt;Remembers your rates, tone and corrections&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SerpApi&lt;/td&gt;
&lt;td&gt;Live web research with sources&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sentry&lt;/td&gt;
&lt;td&gt;Traces every agent run, model call and token&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Render&lt;/td&gt;
&lt;td&gt;Hosts the app and the agents&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Temporal&lt;/td&gt;
&lt;td&gt;A durable workflow for each deal&lt;/td&gt;
&lt;td&gt;Built and tested, not live&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  DigitalOcean: where the AI runs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; DigitalOcean's Gradient AI Platform includes Serverless Inference, which serves open-weight models behind an OpenAI-compatible API and bills per token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What it does in Panga:&lt;/strong&gt; it runs &lt;strong&gt;every&lt;/strong&gt; AI call. Gemma 4 (&lt;code&gt;gemma-4-31B-it&lt;/code&gt;) handles all the reasoning, and Qwen3 (&lt;code&gt;qwen3-embedding-0.6b&lt;/code&gt;) makes the embeddings behind past-project search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it's wired:&lt;/strong&gt; the Mastra agents point at &lt;code&gt;https://inference.do-ai.run/v1&lt;/code&gt; with a DigitalOcean model key (&lt;code&gt;src/mastra/index.ts&lt;/code&gt;). Embeddings come from the same endpoint's &lt;code&gt;/v1/embeddings&lt;/code&gt; (&lt;code&gt;src/server/embeddings.ts&lt;/code&gt;). The repo also ships an App Platform spec (&lt;code&gt;.do/app.yaml&lt;/code&gt;). Panga first ran on App Platform, then I moved hosting to Render's free plan to keep the build at ₹0.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where you see it:&lt;/strong&gt; every result in the demo: the work list, the practice call, the replay, the research and the reply.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gemma: the brain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; Google's family of open-weight models.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What it does in Panga:&lt;/strong&gt; Gemma 4 31B is the &lt;strong&gt;only&lt;/strong&gt; reasoning model. It reads the brief and the chat, plays the client on the practice call, reviews the call for promises, summarises research and drafts the reply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it's wired:&lt;/strong&gt; DigitalOcean serves it (above) and Mastra calls it (below). Because any model can be wrong, Panga checks Gemma's work in code: quotes must match the client's text, all money maths is TypeScript, and every amount in a reply is checked against Panga's own numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where you see it:&lt;/strong&gt; Sentry counts 24 Gemma calls and 27,063 tokens on the live app this week, all on &lt;code&gt;gemma-4-31B-it&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mastra: the agents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; an open-source TypeScript framework for building AI agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What it does in Panga:&lt;/strong&gt; four agents run on Gemma, each with its own instructions:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Its job&lt;/th&gt;
&lt;th&gt;Where you see it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scope analyst&lt;/td&gt;
&lt;td&gt;Lists the work in the brief and chat, quoting the client. Later, reviews the practice call for promises.&lt;/td&gt;
&lt;td&gt;Step 01 and the replay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Researcher&lt;/td&gt;
&lt;td&gt;Explains an unfamiliar requirement from live search results&lt;/td&gt;
&lt;td&gt;"What's involved?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client simulator&lt;/td&gt;
&lt;td&gt;Plays the client on the practice call, by text or voice, streaming&lt;/td&gt;
&lt;td&gt;Step 03&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proposal writer&lt;/td&gt;
&lt;td&gt;Drafts the reply in your tone&lt;/td&gt;
&lt;td&gt;Step 04&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it's wired:&lt;/strong&gt; &lt;code&gt;src/mastra/index.ts&lt;/code&gt; defines the agents. JSON steps use &lt;code&gt;generate&lt;/code&gt;, and the live call uses &lt;code&gt;stream&lt;/code&gt;. Mastra's observability exporter sends every run to Sentry.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ElevenLabs: the voice
&lt;/h3&gt;

&lt;p&gt;The ElevenLabs category names three uses: give an open-source agent a voice, transcribe audio, or narrate the demo. Panga does all three.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A voice for the open-model client.&lt;/strong&gt; The voice practice call is an ElevenLabs Conversational AI agent whose &lt;strong&gt;Custom LLM is Panga's own endpoint&lt;/strong&gt; (&lt;code&gt;/api/sim/v1/chat/completions&lt;/code&gt;, locked with a shared secret). ElevenLabs listens, handles turn-taking and speaks. Gemma, through the client-simulator agent, decides every word the client says, based on this deal's brief. The browser starts the call with a short-lived signed URL from Panga, so the API key never reaches the browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transcription.&lt;/strong&gt; "Add their voice note" sends a client's voice note to ElevenLabs Scribe (&lt;code&gt;scribe_v2&lt;/code&gt;), and the text joins the brief for Gemma to read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Narration.&lt;/strong&gt; The demo video's voice is ElevenLabs text-to-speech (voice "George", &lt;code&gt;eleven_multilingual_v2&lt;/code&gt;). Hindi lines are written in Devanagari so they're pronounced correctly, and I checked every clip by transcribing it back with Scribe.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Tiger Data: the database and the search
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; managed Postgres with pgvector, running on Tiger Data's free plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What it does in Panga:&lt;/strong&gt; it stores deals, practice calls and your library of past projects, and finds the past projects most like a new brief.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it's wired:&lt;/strong&gt; every past project is saved with a Qwen3 embedding (pgvector) and a full-text index. One SQL query runs a &lt;strong&gt;hybrid search&lt;/strong&gt;: score = 0.7 × vector similarity + 0.3 × keyword rank (&lt;code&gt;src/server/projects-repo.ts&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where you see it:&lt;/strong&gt; past projects that match a new deal, and the Memory &amp;amp; library page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Backboard: the memory
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; an API that gives AI apps long-term memory and search over it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What it does in Panga:&lt;/strong&gt; it remembers you between deals: your minimum hourly rate, currency, tone, work you never include, and every correction you make to an extracted work list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it's wired:&lt;/strong&gt; each workspace gets one Backboard assistant, and its ID is kept in Postgres. Preferences and corrections are saved as Backboard memories. When a new brief arrives, Panga &lt;strong&gt;searches those memories with the brief's text&lt;/strong&gt; and puts the best matches into the scope analyst's prompt (&lt;code&gt;recallForBrief&lt;/code&gt; in &lt;code&gt;src/server/memory.ts&lt;/code&gt;). A correction you made last month shapes this month's work list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where you see it:&lt;/strong&gt; the Memory &amp;amp; library page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SerpApi: the research
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; an API that returns search engine results as JSON.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What it does in Panga:&lt;/strong&gt; it powers &lt;strong&gt;"What's involved?"&lt;/strong&gt; on any work item, for when you don't know how big something like "weekly online tests" really is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it's wired:&lt;/strong&gt; the top five Google results from SerpApi go to the researcher agent, which must cite them as [1], [2] and so on. Citations that don't point to a real result are removed, and an answer with no valid citation is replaced by the sources themselves. Each search is its own Sentry span (&lt;code&gt;panga.research.search&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sentry Agent Tracing: watching the agents work
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; Sentry's tracing for AI agents. Every agent run, model call, token count and cost becomes a span you can inspect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it's set up:&lt;/strong&gt; Mastra's Sentry exporter (&lt;code&gt;@mastra/sentry&lt;/code&gt;) is plugged into Panga's Mastra instance, so every agent run and Gemma call is traced without extra code per call. Sentry's Node instrumentation adds the Postgres queries to Tiger and the HTTP calls to Backboard, SerpApi and DigitalOcean to the same trace. I added custom spans around the non-AI steps (&lt;code&gt;panga.verify_quotes&lt;/code&gt;, &lt;code&gt;panga.research&lt;/code&gt;, &lt;code&gt;panga.research.search&lt;/code&gt;). Errors are reported with the step that failed, such as &lt;code&gt;memory.recall&lt;/code&gt; or &lt;code&gt;elevenlabs.transcribe&lt;/code&gt;.&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%2Fnpu1w0t453hzxb61y26s.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%2Fnpu1w0t453hzxb61y26s.png" alt="Sentry's AI Agents dashboard for Panga: Gemma calls, tokens, cost and duration, and a list of traces with time, tokens and cost for each" width="800" height="1242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it performs&lt;/strong&gt; on the live app over the last 7 days (the &lt;code&gt;panga&lt;/code&gt; project only, so these are my test runs and the demo):&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent run&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scope analyst, reading a full brief&lt;/td&gt;
&lt;td&gt;28–47 s&lt;/td&gt;
&lt;td&gt;about 2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope analyst, reviewing a practice call&lt;/td&gt;
&lt;td&gt;4–7 s&lt;/td&gt;
&lt;td&gt;750–900&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client simulator, one turn of the call&lt;/td&gt;
&lt;td&gt;1.0–2.5 s&lt;/td&gt;
&lt;td&gt;870–1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proposal writer, drafting the reply&lt;/td&gt;
&lt;td&gt;5.5 s&lt;/td&gt;
&lt;td&gt;600&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In total, 24 Gemma calls used 27,063 tokens. Sentry estimates every trace at &lt;strong&gt;less than $0.01&lt;/strong&gt;.&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%2Fqy59emy8sj7qjm5avzf4.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%2Fqy59emy8sj7qjm5avzf4.png" alt="One Sentry trace: the scope analyst's 45-second Gemma call, with the Tiger queries and Backboard calls that ran before it" width="800" height="1234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What I found:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reading the brief is the slow step.&lt;/strong&gt; It took 45 s in the trace above, 351% slower than the average Gemma call (10 s). But the request that starts it returns in &lt;strong&gt;343 ms&lt;/strong&gt;, because the analysis runs after the response. The trace shows why Panga can show a live "reading" screen instead of a frozen button.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A new workspace pays a one-time 236 ms&lt;/strong&gt; to create its Backboard assistant (&lt;code&gt;POST /assistants&lt;/code&gt;). Later deals skip that step because the ID is saved in Postgres. The waterfall shows the lookup, the create and the save in order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The prompt fills 1% of Gemma's 256K context window&lt;/strong&gt;, so even a long WhatsApp thread has plenty of room.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A client-simulator turn takes 1–2.5 s&lt;/strong&gt;, which is quick enough for a spoken conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it helps me debug:&lt;/strong&gt; when something fails, the error lands in Sentry tagged with the step, inside the same trace as the model call and the database queries. So I can tell whether Gemma, Postgres or a partner API was at fault.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Render: where Panga lives
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; a cloud hosting platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What it does in Panga:&lt;/strong&gt; it runs the whole live app: the Next.js site, the four Mastra agents, and the Custom LLM endpoint that the ElevenLabs voice agent calls during a practice call. So Render is the runtime for the agents, not just a host for static pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it's wired:&lt;/strong&gt; a free web service that builds with &lt;code&gt;npm ci &amp;amp;&amp;amp; npm run build&lt;/code&gt;, checks health at &lt;code&gt;/api/health&lt;/code&gt; and redeploys on every push to &lt;code&gt;main&lt;/code&gt;. Node starts with a 400 MB memory cap to fit the 512 MB plan, and the app runs at around 210 MB.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Temporal: built and tested, not live
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; a workflow engine that makes long-running work durable. It survives restarts and retries failed steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What it does in the code:&lt;/strong&gt; one workflow per deal (&lt;code&gt;dealReview&lt;/code&gt;). It retries the analysis (3 attempts, starting at 5 s). It waits up to 30 days for the practice call, the scope confirmation and your decision. Then, 14 days after the decision, it asks how the project went.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The honest status:&lt;/strong&gt; the tests run this workflow, long timers included, in seconds on Temporal's time-skipping test server. &lt;strong&gt;The live demo does not use Temporal&lt;/strong&gt;, because Temporal Cloud asked for a card and I kept this build at ₹0. Instead, the live app runs the same steps inside the web process. Setting &lt;code&gt;TEMPORAL_ADDRESS&lt;/code&gt; (plus a key) and &lt;code&gt;PANGA_EMBEDDED_WORKER=true&lt;/code&gt; starts the worker inside the web server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The parts that fought back
&lt;/h2&gt;

&lt;p&gt;Some of the most useful lessons came from things breaking.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gemma invented quotes.&lt;/strong&gt; It would "quote" the client with words the client never wrote. Fix: a matcher that forgives curly quotes and spacing but not words, and that maps the match back to the exact original text. Unmatched quotes get dropped and counted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Budget 20-25k" became ₹25,000.&lt;/strong&gt; The model kept taking the top of a range. Prompt rule: a range means the lower end. The reply checker learned to read ranges too, with a test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deadlines kept turning into work items.&lt;/strong&gt; "Before April" isn't a deliverable. The prompt says so, and the dry runs confirm it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A 900 MB database on a 512 MB server.&lt;/strong&gt; Locally, Panga uses PGlite (Postgres compiled to WASM) with pgvector. It's lovely, but on my machine it used about 900 MB the moment it started, far more than the 512 MB Render's free plan allows. The live app uses Tiger Data instead and sits around 220 MB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tiger's certificate was "self-signed in the chain".&lt;/strong&gt; Newer &lt;code&gt;node-postgres&lt;/code&gt; treats &lt;code&gt;sslmode=require&lt;/code&gt; as "verify everything", and Tiger uses its own certificate authority. Every query failed. Fix: read &lt;code&gt;sslmode=require&lt;/code&gt; the way libpq does (encrypted, certificate not pinned), with a test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backboard returned 500 for one word.&lt;/strong&gt; Saving preferences failed, but only for some of them. After a few probes I found it: Backboard's API rejects any memory whose metadata has a text field named &lt;code&gt;value&lt;/code&gt;. Renaming the field fixed it, and old memories still read back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temporal wants a worker. Free hosting doesn't do workers.&lt;/strong&gt; So the worker runs inside the web server when needed, with the workflow code bundled during the build so the server never has to run webpack at startup. It costs about 70 MB.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Running it for ₹0
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;App&lt;/td&gt;
&lt;td&gt;Render free web service&lt;/td&gt;
&lt;td&gt;₹0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Tiger Data free service&lt;/td&gt;
&lt;td&gt;₹0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;td&gt;Gemma on DigitalOcean (trial credit)&lt;/td&gt;
&lt;td&gt;well under ₹1 per deal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Research, memory, voice, tracing&lt;/td&gt;
&lt;td&gt;SerpApi, Backboard, ElevenLabs, Sentry free plans&lt;/td&gt;
&lt;td&gt;₹0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Prize categories
&lt;/h2&gt;

&lt;p&gt;I'm entering the ten categories explained above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best Use of &lt;strong&gt;DigitalOcean&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best Use of &lt;strong&gt;Gemma&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best Use of &lt;strong&gt;Render&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best Use of &lt;strong&gt;ElevenLabs&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best Use of &lt;strong&gt;Mastra&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best Use of &lt;strong&gt;Tiger Data&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best Use of &lt;strong&gt;Backboard&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best Use of &lt;strong&gt;SerpApi&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best Use of &lt;strong&gt;Sentry Agent Tracing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best Use of &lt;strong&gt;Temporal&lt;/strong&gt; (built and tested, but not live; see its section)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Panga doesn't use TabPFN, Tinker, Arduino, Entire, GitHub Copilot, MongoDB Atlas or a .tech domain, so I'm not entering those.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Laptop mode:&lt;/strong&gt; Gemma running locally, so a brief never leaves the freelancer's machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A contract from the agreed scope:&lt;/strong&gt; the final work list, prices and "not included" items, ready to sign.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning from real outcomes:&lt;/strong&gt; if your "simple sites" always run 40% over, Panga should quote you 40% higher before you're tempted not to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every freelancer will pick a panga sooner or later. Panga just makes sure you know what you're picking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Panga lo. Par soch samajh ke.&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Pick your panga. Wisely.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Ask an AI for your home loan EMI and it will be off by ₹10. Every month.</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Sun, 11 Oct 2026 14:06:52 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/ask-an-ai-for-your-home-loan-emi-and-it-will-be-off-by-10-every-month-3ac1</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/ask-an-ai-for-your-home-loan-emi-and-it-will-be-off-by-10-every-month-3ac1</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/kaggle-2026-09-23"&gt;Kaggle Benchmarking Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Last week I built a little app about Ananya. She's made up, but you know someone like her. She's 31, she's been saving for eight years, and she's about to sign for a ₹72 lakh 2 BHK whose brochure says 1,050 sq ft. The registration says the carpet area is 720.&lt;/p&gt;

&lt;p&gt;While I was building it I kept asking chatbots for help with the numbers: what's ₹72 lakh in crore, what's the price per sq ft of &lt;em&gt;carpet&lt;/em&gt;, what's the EMI on the loan. The answers sounded confident. I had no idea whether they were right.&lt;/p&gt;

&lt;p&gt;So I benchmarked it. Then my benchmark turned out to be too easy, so I made it harder. That second part is where the real findings are.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Lakh, Crore and Carpet Area&lt;/strong&gt; is 100 deterministic questions about the money and property maths Indian buyers actually do. Every answer was computed in Python, not by hand.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Group&lt;/th&gt;
&lt;th&gt;Cases&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core&lt;/td&gt;
&lt;td&gt;Conversion&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;"₹1.2 crore minus ₹45 lakh, in lakh?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core&lt;/td&gt;
&lt;td&gt;Area&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;"Super built-up 1,300 sq ft, carpet 910. Loading as a % of carpet?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core&lt;/td&gt;
&lt;td&gt;EMI and tax&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;"₹72,00,000 at 8.4% for 25 years. Monthly EMI?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core&lt;/td&gt;
&lt;td&gt;Format&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;"Write 98765432 with lakh/crore commas" → 9,87,65,432&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;td&gt;Multi-step loans&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;prepay ₹5 lakh after 36 EMIs, keep the EMI: how many EMIs are left?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;td&gt;Tax rules&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;80C and 24(b) caps, LTCG with cess, circle rate vs agreement price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;td&gt;Regional land units&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;guntha, cent, Chennai ground, bigha-biswa, Punjab vs Haryana marla&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;td&gt;Hinglish&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;"72 lakh ka flat hai, 20% down payment, baaki 8.5% pe 20 saal. EMI kitni?"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each prompt asks for at most five lines of working, then &lt;code&gt;ANSWER: &amp;lt;value&amp;gt;&lt;/code&gt;. Numbers are checked against the true value (a rupee or two of slack where rounding is involved, an exact string match for the format group). Tax questions state the rule inside the prompt, so they test arithmetic, not whether a model knows this year's tax law. The scorer also flags any response that slips into Western grouping (7,200,000 instead of 72,00,000), even when the final answer is right. I call that &lt;strong&gt;western comma drift&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why this matters to me: hundreds of millions of people think in lakh and crore, and property listings in India are famous for blurring carpet and super built-up area. If a model is going to sit inside a home-buying assistant, these are its first questions, not edge cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Models Tested
&lt;/h2&gt;

&lt;p&gt;A spread you'd actually reach for in a product, across three providers and two price tiers: &lt;strong&gt;Gemini 3.7 Flash&lt;/strong&gt;, &lt;strong&gt;Gemini 3.1 Pro Preview&lt;/strong&gt;, &lt;strong&gt;Claude Haiku 5.5&lt;/strong&gt;, &lt;strong&gt;Claude Sonnet 4.6&lt;/strong&gt;, &lt;strong&gt;Gemma 4 31B&lt;/strong&gt; (open-weight) and &lt;strong&gt;GPT-5.4 mini&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Findings
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. My first benchmark was too easy
&lt;/h3&gt;

&lt;p&gt;Version 1 was just the 60 core questions. Every model scored between 0.92 and 1.00:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Core score (60)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.7 Flash&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.1 Pro Preview&lt;/td&gt;
&lt;td&gt;0.98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Haiku 5.5&lt;/td&gt;
&lt;td&gt;0.98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 4.6&lt;/td&gt;
&lt;td&gt;0.95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 31B&lt;/td&gt;
&lt;td&gt;0.95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 mini&lt;/td&gt;
&lt;td&gt;0.92&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A benchmark where everyone gets an A tells you nothing about which model to ship. So I added 40 harder cases, the kind of questions a buyer asks &lt;em&gt;after&lt;/em&gt; the first EMI: prepayments, rate hikes, balance transfers, tax caps, regional land units, and the same maths in Hinglish.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The hard tier opened a 35-point gap
&lt;/h3&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%2Fr4n3vdhhddbzgcrni1vh.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%2Fr4n3vdhhddbzgcrni1vh.png" alt="Hard tier results" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Score (100)&lt;/th&gt;
&lt;th&gt;Hard tier (40)&lt;/th&gt;
&lt;th&gt;Multi-step loans&lt;/th&gt;
&lt;th&gt;Tax rules&lt;/th&gt;
&lt;th&gt;Regional units&lt;/th&gt;
&lt;th&gt;Hinglish&lt;/th&gt;
&lt;th&gt;Comma drift&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Haiku 5.5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.97&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;37/40&lt;/td&gt;
&lt;td&gt;12/15&lt;/td&gt;
&lt;td&gt;7/7&lt;/td&gt;
&lt;td&gt;8/8&lt;/td&gt;
&lt;td&gt;10/10&lt;/td&gt;
&lt;td&gt;16%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.7 Flash&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.94&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;34/40&lt;/td&gt;
&lt;td&gt;10/15&lt;/td&gt;
&lt;td&gt;6/7&lt;/td&gt;
&lt;td&gt;8/8&lt;/td&gt;
&lt;td&gt;10/10&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.1 Pro Preview&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.94&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;34/40&lt;/td&gt;
&lt;td&gt;11/15&lt;/td&gt;
&lt;td&gt;6/7&lt;/td&gt;
&lt;td&gt;8/8&lt;/td&gt;
&lt;td&gt;9/10&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 31B&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.87&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;31/40&lt;/td&gt;
&lt;td&gt;8/15&lt;/td&gt;
&lt;td&gt;6/7&lt;/td&gt;
&lt;td&gt;8/8&lt;/td&gt;
&lt;td&gt;9/10&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 4.6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.85&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;29/40&lt;/td&gt;
&lt;td&gt;7/15&lt;/td&gt;
&lt;td&gt;7/7&lt;/td&gt;
&lt;td&gt;7/8&lt;/td&gt;
&lt;td&gt;8/10&lt;/td&gt;
&lt;td&gt;13%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 mini&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.77&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;23/40&lt;/td&gt;
&lt;td&gt;2/15&lt;/td&gt;
&lt;td&gt;7/7&lt;/td&gt;
&lt;td&gt;7/8&lt;/td&gt;
&lt;td&gt;7/10&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On the core 60, these four were 8 points apart. On the hard 40, they're 35 points apart, and the ranking flipped: Flash, the v1 winner, is now second.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Multi-step loans break everyone
&lt;/h3&gt;

&lt;p&gt;Models that nailed single EMIs still stumbled once the loan had a history. Even the best model missed 3 of 15. GPT-5.4 mini got 2 of 15.&lt;/p&gt;

&lt;p&gt;The scariest miss was &lt;code&gt;l13&lt;/code&gt;: &lt;em&gt;"You can afford an EMI of ₹50,000 at 8.5% for 20 years. What's the largest loan you can take?"&lt;/em&gt; The answer is about &lt;strong&gt;₹57.6 lakh&lt;/strong&gt;. GPT-5.4 mini said &lt;strong&gt;537,000&lt;/strong&gt;. That's roughly ₹5.4 lakh, a tenth of the real figure, delivered with the same confidence as everything else.&lt;/p&gt;

&lt;p&gt;The near-misses are worse in a quieter way. On &lt;code&gt;e04&lt;/code&gt; (₹72,00,000 at 8.4% for 25 years) the correct EMI is &lt;strong&gt;₹57,492&lt;/strong&gt;. In v1, Claude Sonnet 4.6 said ₹57,487 and Gemini 3.1 Pro Preview said ₹57,482. None of them said "approximately". &lt;code&gt;(1 + r)^300&lt;/code&gt; is exactly where mental arithmetic slips.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this changed for me:&lt;/strong&gt; in anything I ship now, the model explains the formula and a tool computes the EMI.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The bigger model lost to the cheaper one
&lt;/h3&gt;

&lt;p&gt;Claude Haiku 5.5, the small tier, beat Claude Sonnet 4.6 by 12 points overall, and by 8 cases on the hard tier. Price tier was a worse predictor of accuracy than I expected, so test the model you actually plan to pay for.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. What I thought would be hard, wasn't
&lt;/h3&gt;

&lt;p&gt;I predicted regional land units would be the bloodbath, since bigha and marla change meaning from state to state. But when the conversion is given, models handle it: 30 of 32 right across the four models. Tax rules stated in the prompt were nearly perfect too (27 of 28). The only tax miss was Gemini 3.7 Flash on &lt;code&gt;t02&lt;/code&gt;, which forgot the buyer had already used ₹90,000 of their 80C limit and answered ₹3,30,000 instead of ₹2,40,000.&lt;/p&gt;

&lt;p&gt;The difficulty is in chaining steps, not in unfamiliar units.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Hinglish costs accuracy for some models
&lt;/h3&gt;

&lt;p&gt;Haiku and Flash got all 10 Hinglish questions right. Sonnet dropped 2 and GPT-5.4 mini dropped 3, on sums like total interest and carpet-from-loading that are routine in English. If your users type "EMI kitni banegi?", test in that language.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Models drift into Western commas even in an Indian question
&lt;/h3&gt;

&lt;p&gt;Every model aced the format group when asked directly. Yet 6–16% of responses still wrote something like 4,000,000 somewhere in their working. It doesn't make the answer wrong, but it's exactly the slip that makes "₹40 lakh" read as "₹4 crore" to a tired buyer at 11 PM.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. My benchmark lied to me first
&lt;/h3&gt;

&lt;p&gt;My first run said &lt;strong&gt;Claude Opus 5 scored 0.08&lt;/strong&gt;, and GPT-5.5 errored completely. I almost wrote a post about it.&lt;/p&gt;

&lt;p&gt;Then I opened the run logs. Every failure was a &lt;code&gt;403 PermissionDeniedError: max estimated cost exceeds your available quota&lt;/code&gt;. I'd fired cases in parallel, the expensive models blew through the quota, and my scorer counted each errored call as a wrong answer. Opus 5's printed table actually showed 100% on every group it got to answer.&lt;/p&gt;

&lt;p&gt;I fixed it: sequential calls, per-case progress logging, and every run prints &lt;code&gt;answered: X of 100&lt;/code&gt; before any score. I dropped the two most expensive models rather than publish a number I can't stand behind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson:&lt;/strong&gt; a benchmark score is only as honest as its error handling. If a leaderboard can't tell you how many questions were actually answered, don't trust the leaderboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I'd measure next
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Give the models a calculator tool.&lt;/strong&gt; Do the multi-step loan errors vanish, or do models skip the tool when they feel confident?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leave the unit definition out.&lt;/strong&gt; Ask "2 bigha in sq ft?" with no state, and score whether the model asks which state instead of guessing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Benchmark
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Benchmark:&lt;/strong&gt; &lt;a href="https://www.kaggle.com/benchmarks/reet22/lakh-crore-and-carpet-area" rel="noopener noreferrer"&gt;https://www.kaggle.com/benchmarks/reet22/lakh-crore-and-carpet-area&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task:&lt;/strong&gt; &lt;a href="https://www.kaggle.com/benchmarks/tasks/reet22/lakh-crore-carpet-area" rel="noopener noreferrer"&gt;https://www.kaggle.com/benchmarks/tasks/reet22/lakh-crore-carpet-area&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notebook (all 100 cases and the scorer):&lt;/strong&gt; &lt;a href="https://www.kaggle.com/code/reet22/lakh-crore-and-carpet-area" rel="noopener noreferrer"&gt;https://www.kaggle.com/code/reet22/lakh-crore-and-carpet-area&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fork it, add your city's stamp duty, and tell me which model gets your home loan right.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>kagglechallenge</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Wanderlore: What if your next walk had a plot?</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Sun, 11 Oct 2026 12:32:16 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/wanderlore-what-if-your-next-walk-had-a-plot-a3g</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/wanderlore-what-if-your-next-walk-had-a-plot-a3g</guid>
      <description>&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%2Ftp1sg18uwgfg5xlsn1wy.jpg" 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%2Ftp1sg18uwgfg5xlsn1wy.jpg" alt="Wanderlore's illustrated sunset landing page on desktop" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&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;p&gt;The first time I tried to test my walking app properly, I couldn't even get it to find me.&lt;/p&gt;

&lt;p&gt;I was on my laptop, staring at another location timeout. I kept wondering what was wrong. How was I supposed to build a story that followed a walk if it couldn't tell where I was?&lt;/p&gt;

&lt;p&gt;Then I tried it on my phone. It detected my location and picked up my movement. After all that testing at a desk, the part that finally worked was the part that meant leaving it.&lt;/p&gt;

&lt;p&gt;That little moment made Wanderlore feel real to me.&lt;/p&gt;

&lt;p&gt;I wanted a walk to have a little anticipation: a reason to notice something, a character to follow, a small mystery waiting around the next chapter. If you've ever wanted a reason to step outside but couldn't quite find one, this is the feeling I built it around.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Wanderlore turns a walk into a narrated, interactive story.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You choose folklore, mystery, or fantasy, decide how long you want to wander, and tell it what the weather looks like. The page responds too: choose rain and the scene gains drizzle, with rain ambience after you enable sound.&lt;/p&gt;

&lt;p&gt;When you begin, Gemma writes a short chapter and a narrator reads it aloud. In location mode, each new chapter uses your latest position and nearby named places when your selected map pack covers the area. Your earlier chapters and decisions help shape what happens next.&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%2F2txcaq8coiddk4hs051z.jpg" 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%2F2txcaq8coiddk4hs051z.jpg" alt="Choose a genre, duration, weather, and location mode on desktop" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The choices are small invitations into the story. Do you look more closely at the lantern? Ask its keeper a question? Offer to help? Your answer becomes part of the next chapter's context.&lt;/p&gt;

&lt;p&gt;Some days you might want to make every decision. Other days, you might just want to listen. &lt;strong&gt;Continue automatically&lt;/strong&gt; lets the storyteller choose and starts the next chapter after narration finishes. Keep the browser visible while using it; background and locked-screen continuation are still future work.&lt;/p&gt;

&lt;p&gt;When you're done, save the walk, leave a reflection, and export your story. I like the idea of coming home with a small memory of what you noticed.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://wanderlore.onrender.com/" rel="noopener noreferrer"&gt;Open the live preview&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The hosted walk currently requires a private demo access code. The screenshots below show the live experience without exposing a personal route.&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%2F3z4ddpehdnrxb0l8jqkf.jpg" 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%2F3z4ddpehdnrxb0l8jqkf.jpg" alt="Wanderlore landing page in a mobile browser viewport" width="390" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mobile layout, captured at 390 × 844 pixels in a browser. Real location and movement were also tested on my phone.&lt;/em&gt;&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%2Fsk2i4wf8p67y1fo4e8ui.jpg" 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%2Fsk2i4wf8p67y1fo4e8ui.jpg" alt="A narrated chapter and three story choices in the mobile layout" width="390" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This chapter uses Sample walk: its route and place names are fictional. It was generated and voiced in 3.8 seconds in this particular test.&lt;/em&gt;&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%2Fm0nynbroh20p9dmarul8.jpg" 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%2Fm0nynbroh20p9dmarul8.jpg" alt="Desktop story with its illustrated sample route and choices" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a first try, choose ten minutes and whichever genre you feel like hearing. On a phone, allow location and use &lt;strong&gt;Use my location&lt;/strong&gt;. On a laptop, &lt;strong&gt;Sample walk&lt;/strong&gt; lets you explore the storytelling without relying on desktop location services.&lt;/p&gt;

&lt;p&gt;The sketch records the story's route; it doesn't provide walking directions. The current Lucknow map pack covers central and adjoining areas. You can import a GeoJSON pack for another area; without matching nearby places, the story uses general surroundings.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Reet24-del/wanderlore" rel="noopener noreferrer"&gt;Wanderlore on GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The app uses Python, FastAPI, and a responsive HTML/CSS/JavaScript frontend. The application code is GPL-3.0; model and map data have their own terms. OpenStreetMap contributors provide the underlying place data. I used Codex to help implement, debug, and test the project.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Gemma is the story engine.&lt;/strong&gt; The local setup supports Gemma 3 through Ollama. The hosted preview uses &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; through Google AI Studio because the small free hosting instance cannot run the local model stack. Chapters carry forward the previous story, selected choices, genre, weather, and available place context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ElevenLabs supplies the hosted narration.&lt;/strong&gt; I wanted the voice to feel like someone telling you a story, with enough warmth to keep listening. The hosted version uses the Roger voice. The local setup also supports Kokoro after downloading its voice assets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tiger Data supplies a small, sourced place-context pack.&lt;/strong&gt; I stored four summaries of public Lucknow sources in PostgreSQL with pgvector. Keyword and vector results are combined with reciprocal rank fusion. A verified retrieval produced context for Rumi Gate and Janeshwar Mishra Park, which is exported for the storyteller to read. This is a prepared context pack; walking doesn't trigger a database query for every step. The resulting tale is fiction, even when it includes a real place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sentry makes the wait visible.&lt;/strong&gt; I instrumented the chapter pipeline with a &lt;code&gt;wanderlore.chapter&lt;/code&gt; transaction and spans for generation and speech. One verified development trace for Gemma generation measured 3.28 seconds. Seeing where time goes helps me assess the pauses between chapters. The trace integration exports timing and model metadata while excluding prompts, story text, GPS, cookies, and request bodies.&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%2F05mrl6hovg7co4sd0yy6.jpg" 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%2F05mrl6hovg7co4sd0yy6.jpg" alt="Sentry waterfall showing the Wanderlore chapter transaction and Gemma request lasting 3.28 seconds" width="800" height="694"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Render hosts the HTTPS preview on its Free plan.&lt;/strong&gt; That made phone testing possible without running the server on my laptop. The hosted version needs internet for generation and narration. Free hosting can sleep and reset saved files, so exporting a walk matters.&lt;/p&gt;

&lt;p&gt;Verification included 29 passing Python tests, five automatic-continuation scheduler tests, and a live browser check where a second chapter started without selecting a choice or pressing Next. My phone detected location and movement; desktop location remained unreliable on my setup.&lt;/p&gt;

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

&lt;p&gt;For Wanderlore, it means having a path to storytelling on your own machine. Gemma's available weights let the local version generate chapters through Ollama, and Kokoro provides a local voice option. After the models and assets are downloaded, that setup can work offline with the local server running.&lt;/p&gt;

&lt;p&gt;The hosted preview trades that independence for easier access. It sends story context and nearby place names to Google, and narration text to ElevenLabs. Raw landmark coordinates are stripped from the generation payload, although the hosted server still processes GPS. These are different ways to run the same idea, with different privacy and connectivity needs.&lt;/p&gt;

&lt;p&gt;I also want people to be able to improve the experience: bring their own map pack, experiment with a narrator, or make the choices more interesting. Open application code makes those changes possible.&lt;/p&gt;

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

&lt;p&gt;I'm entering these categories based on the integrations above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — context-aware chapter generation, with local and hosted inference paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of ElevenLabs&lt;/strong&gt; — spoken narration for generated chapters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Tiger Data&lt;/strong&gt; — pgvector and keyword retrieval for sourced place context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Sentry Agent Tracing&lt;/strong&gt; — instrumented generation and narration, with trace evidence shown above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render&lt;/strong&gt; — the deployed HTTPS web experience used for phone testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there's a familiar path near you, that's where I'd start. Pick a mood, give yourself ten minutes, and see what you notice when there's a story waiting for you.&lt;/p&gt;

&lt;p&gt;I'd love to hear which genre you'd take on your first walk—and what you would want to happen next.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Maa ka Drawer: finding my mother’s bills with Tiger Data and open multilingual search</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Mon, 05 Oct 2026 05:53:57 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/maa-ka-drawer-finding-my-mothers-bills-with-tiger-data-and-open-multilingual-search-3f6g</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/maa-ka-drawer-finding-my-mothers-bills-with-tiger-data-and-open-multilingual-search-3f6g</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;A receipt can be saved and still be hard to find. You remember the washing machine, the shop, or what broke, not necessarily the filename or invoice number.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Maa ka Drawer&lt;/strong&gt; for my mother: a small household receipt finder that combines open multilingual embeddings with Tiger Cloud PostgreSQL keyword and vector search. The goal is to make “find that bill” a smaller job.&lt;/p&gt;

&lt;p&gt;I chose the problem for this prototype. I have not yet tested it with her, so I cannot claim that it has saved her time or quote feedback she has not given.&lt;/p&gt;

&lt;p&gt;The app opens onto a drawer of illustrated cards. Hovering lifts and tilts a card; tapping or clicking opens the receipt. Search works over the saved text, and an original PDF or photo can stay attached. If the receipt does not state a warranty expiry, that field stays blank.&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%2Fyq0r4mxptm37bjvbciju.jpg" 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%2Fyq0r4mxptm37bjvbciju.jpg" alt="The running Maa ka Drawer app with six fictional household receipts" width="800" height="819"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Less typing: upload or speak
&lt;/h3&gt;

&lt;p&gt;A JPG, PNG or PDF upload now extracts text and suggests a recognised bill type. A synthetic electricity bill became &lt;strong&gt;Electricity bill → Services&lt;/strong&gt;, retaining its INR 400 amount and original image. Tesseract.js reads English/Hindi text on the app server. PDF.js reads embedded text directly; scanned-page OCR is implemented, limited to the first three pages, but its browser retest is still pending. Photos and embedded-text PDFs passed functional checks. Blurred photos, handwriting and unfamiliar bill layouts can fail.&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%2Fze4x504sav6vsfwzow5m.jpg" 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%2Fze4x504sav6vsfwzow5m.jpg" alt="A receipt image recognised as an Electricity bill" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speak receipt&lt;/strong&gt; records a short Hindi or Indian English note, or accepts an audio file. Local &lt;a href="https://huggingface.co/openai/whisper-small" rel="noopener noreferrer"&gt;Whisper-small&lt;/a&gt;, via the &lt;a href="https://huggingface.co/onnx-community/whisper-small" rel="noopener noreferrer"&gt;ONNX conversion&lt;/a&gt; and Transformers.js, transcribes the audio. A conservative parser suggests the item and explicitly stated amount. A synthetic Hindi development recording produced &lt;strong&gt;Electricity bill · ₹400&lt;/strong&gt;; the imperfect transcript remains visible for correction. Voice notes are labelled as notes, not original invoices. The recording is temporary; only reviewed text is saved.&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%2F2ht6wwb23159evrq02vi.jpg" 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%2F2ht6wwb23159evrq02vi.jpg" alt="Local Hindi transcription with an editable transcript and a 400 rupee bill suggestion" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/Reet24-del/maa-ka-drawer/blob/main/docs/VOICE-VERIFICATION.json" rel="noopener noreferrer"&gt;voice verification record&lt;/a&gt; uses two Murf-generated development fixtures, not a held-out accuracy test or my mother's feedback. Transcription and cloud save/reload were verified separately. Further live-microphone and noisy-household testing remains pending. Murf Isha provides the Indian English demo narration; Murf does not transcribe user notes.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/Reet24-del/maa-ka-drawer/releases/download/v0.1.0/maa-ka-drawer-demo.mp4" rel="noopener noreferrer"&gt;Watch or download the narrated demo video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The video is a captioned walkthrough with Murf Isha Indian English narration assembled from screenshots captured during real interactions with the app. It shows Hindi search, receipt evidence, a no-match query, uploading a receipt photo with OCR, Hindi voice transcription, an attached PDF, archive, undo, and persistence after reload. It is not a continuous screen recording. Every demonstrated receipt is fictional.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Reet24-del/maa-ka-drawer/releases/tag/v0.1.0" rel="noopener noreferrer"&gt;Demo release and setup notes&lt;/a&gt; · &lt;a href="https://github.com/Reet24-del/maa-ka-drawer/blob/main/docs/demo/transcript.md" rel="noopener noreferrer"&gt;Expanded scene notes&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/Reet24-del/maa-ka-drawer" rel="noopener noreferrer"&gt;Browse the complete source on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The repository includes the app, MIT license, PRD, schema, tests, evaluation queries and results. Run it locally with Node.js 22+, &lt;code&gt;npm ci&lt;/code&gt;, &lt;code&gt;npm run build&lt;/code&gt;, and &lt;code&gt;npm start&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;The useful AI task here is retrieval. A Hindi query such as &lt;code&gt;कपड़े धोने वाली मशीन&lt;/code&gt; can find an English washing-machine receipt even when the exact query words are absent.&lt;/p&gt;

&lt;p&gt;The model is &lt;a href="https://huggingface.co/intfloat/multilingual-e5-small" rel="noopener noreferrer"&gt;multilingual-e5-small&lt;/a&gt;, using &lt;a href="https://huggingface.co/Xenova/multilingual-e5-small" rel="noopener noreferrer"&gt;Xenova’s ONNX conversion&lt;/a&gt; through Transformers.js. Quantized inference runs on the app server. Queries and receipt chunks become normalized, 384-dimensional vectors.&lt;/p&gt;

&lt;p&gt;PostgreSQL stores source text, metadata, full-text search vectors and pgvector embeddings. Exact words and invoice identifiers matter, so keyword search remains part of the system. Reciprocal rank fusion combines keyword and semantic rankings. A similarity gate filters weak or ambiguous semantic matches. These scores are not probabilities.&lt;/p&gt;

&lt;p&gt;The interface uses React and Vite; Express serves the API and built app. PDF.js renders originals inside the receipt view. Codex helped implement and test the project, and generated appliance illustrations provide visual cues. The illustrations are not photographs of my mother’s possessions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tiger Data is the live data layer.&lt;/strong&gt; A dedicated free Tiger Cloud service stores receipt text and 384-dimensional embeddings in pgvector. A live verification run passed saving, exact invoice retrieval, vector search, reconnect persistence, archive exclusion and undo. The &lt;a href="https://github.com/Reet24-del/maa-ka-drawer/blob/main/docs/TIGER-VERIFICATION.json" rel="noopener noreferrer"&gt;verification record&lt;/a&gt; includes the timestamp and pgvector version. The original gallery/PDF walkthrough and retrieval benchmark used local PGlite. The new OCR and voice-entry captures were taken with the app connected to Tiger Cloud. Cloud persistence was verified separately.&lt;/p&gt;

&lt;p&gt;The free service presents a private Timescale certificate authority. I pinned that CA locally on first connection and kept chain and hostname checks enabled for subsequent connections. This initial trust-on-first-use step is disclosed in the README; it is not a publicly authenticated certificate chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  What worked—and what did not
&lt;/h3&gt;

&lt;p&gt;I ran a fixed evaluation over six fictional receipts and 18 queries:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Search mode&lt;/th&gt;
&lt;th&gt;Correct first result on 14 positive queries&lt;/th&gt;
&lt;th&gt;Correct no-match responses on 4 negative queries&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Keyword&lt;/td&gt;
&lt;td&gt;8/14&lt;/td&gt;
&lt;td&gt;4/4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vector&lt;/td&gt;
&lt;td&gt;11/14&lt;/td&gt;
&lt;td&gt;4/4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid&lt;/td&gt;
&lt;td&gt;12/14&lt;/td&gt;
&lt;td&gt;4/4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://github.com/Reet24-del/maa-ka-drawer/blob/main/docs/benchmark.json" rel="noopener noreferrer"&gt;full query set and outcomes&lt;/a&gt; are public. This is a small, builder-authored evaluation. A Hindi washing-machine phrase was rejected, and a Hinglish ceiling-fan query returned the purifier. Those failures limit how confidently I can hand this to someone else.&lt;/p&gt;

&lt;p&gt;All 21 automated tests pass, covering retrieval, identifiers, validation, source-file serving, archive/undo, database persistence, actual image OCR and conservative voice-note parsing. Desktop and phone layouts were checked in the browser.&lt;/p&gt;

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

&lt;p&gt;The open model gives this project a retrieval component I can run, inspect, replace and test without a hosted generative API. After the weights are downloaded, local mode keeps receipt data and inference on the laptop. The verified Tiger Cloud mode stores receipt text and embeddings remotely, while model inference and original attachments stay on the app server. That mode is not fully offline.&lt;/p&gt;

&lt;p&gt;The model does one limited job: help locate existing evidence. It does not write an answer about warranty coverage. A user can open the saved text and original document and see what the receipt actually says.&lt;/p&gt;

&lt;p&gt;That distinction shaped the rest of the app. Text extracted from a receipt or transcribed from speech stays editable and requires review. Dates are confirmed by the user. Archiving is reversible. The prototype is for one household and has no public account system.&lt;/p&gt;

&lt;p&gt;My next step is a real trial with my mother: ask her to find a bill, observe the words she uses, and improve retrieval against those examples. That feedback will matter more than adding another animation.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Best Use of Tiger Data&lt;/strong&gt; — real receipt text and open-model embeddings are stored in Tiger Cloud PostgreSQL with pgvector. The application combines full-text and vector rankings, and the public verification record demonstrates the live integration.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>The brochure said 18 floors. The registration said 12.</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Sun, 04 Oct 2026 08:12:55 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/the-brochure-said-18-floors-the-registration-said-12-6eo</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/the-brochure-said-18-floors-the-registration-said-12-6eo</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path One: Ship an Agent That Queries Real Content&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Let me introduce you to Ananya. She's made up, but you probably know someone exactly like her.&lt;/p&gt;

&lt;p&gt;She's 31, works in Pune, and has spent eight years saving for her first flat. One Sunday she walks into a sales office for a project called Nimbus Greens. The brochure is gorgeous. Four towers rising to eighteen floors, a rooftop pool, possession in March 2027, a 2 BHK of 1,050 square feet for ₹72 lakh "all-inclusive", parking free. The broker is friendly and in a hurry. If she pays 20% today, the price is locked.&lt;/p&gt;

&lt;p&gt;Here's the part nobody tells her. Everything she needs to make this decision is already public. Every project in India has to be registered with the state's Real Estate Regulatory Authority (RERA), and that registration is what the builder is legally held to. Then there's the draft agreement for sale, and the RERA Act itself. Nobody reads those three next to the brochure. So nobody notices that they tell a different story:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What the brochure says&lt;/th&gt;
&lt;th&gt;What the record says&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4 towers, G+18&lt;/td&gt;
&lt;td&gt;3 buildings, sanctioned for Ground + 12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Possession from March 2027&lt;/td&gt;
&lt;td&gt;Completion on 31 December 2028&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 BHK, 1,050 sq ft&lt;/td&gt;
&lt;td&gt;690 sq ft carpet area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rooftop pool, amphitheatre, EV charging&lt;/td&gt;
&lt;td&gt;Not in the registered common areas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;₹72 lakh all-inclusive, free parking&lt;/td&gt;
&lt;td&gt;₹81,55,000 in the agreement, ₹4,50,000 of it for parking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All approvals in place&lt;/td&gt;
&lt;td&gt;Environmental clearance applied for, still awaited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pay 20% on booking&lt;/td&gt;
&lt;td&gt;Section 13(1) of the Act allows 10% before a registered agreement&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nimbus Greens is fictional. Every row in that table isn't. These are the tricks Indian buyers find out about years later, once the money is gone and the building has stopped at twelve floors.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Home Truth&lt;/strong&gt;. You give it a project's documents and it lays them side by side, finds every place they disagree, and shows you the exact sentence from each document so you don't have to take its word for anything. It turns the gaps into a checklist of questions to ask the builder. And it has an agent you can ask the kind of question a broker throws at you on the phone: &lt;em&gt;"I'm being offered flat B-1502, is that okay?"&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this needed structured content
&lt;/h3&gt;

&lt;p&gt;I tried the obvious version first in my head: dump the documents into a search index and let a model answer. Ask it "how many floors does Nimbus Greens have?" and the loudest, most confident answer in the pile is the brochure's "G+18". It's repeated, it's in large type, and it's wrong.&lt;/p&gt;

&lt;p&gt;Getting it right takes knowledge that isn't written in any single document. You have to know that a registration outranks a brochure. You have to know that the law caps a booking amount at 10%, so a request for 20% is a violation, not a detail. And you have to know that "1,050 sq ft" and "690 sq ft carpet" are the same flat, measured two ways, and the brochure picked the flattering one. That knowledge lives in how the content is modelled. That's the bit I built in Sanity.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://home-truth-theta.vercel.app" rel="noopener noreferrer"&gt;https://home-truth-theta.vercel.app&lt;/a&gt;. No sign-in. Open &lt;em&gt;Nimbus Greens&lt;/em&gt; and try the chat.&lt;/p&gt;

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

&lt;p&gt;If you'd rather click around yourself, here's the two-minute tour.&lt;/p&gt;

&lt;p&gt;Start on the home page and drag the building. It's drawn from the data: twelve solid floors are what the sanctioned plan covers, and the six translucent red ones on top only ever existed in the brochure. Scroll down and you can flip through the brochure itself in 3D, with the 20% line highlighted and Section 13(1) of the Act quoted right beside it.&lt;/p&gt;

&lt;p&gt;Open the full report. Ten of twelve facts don't hold up, and five of those are critical. Every finding says why it matters to a buyer, and every one has a &lt;em&gt;Show the exact words&lt;/em&gt; drawer with the quote from each document. One click on &lt;em&gt;Questions to ask the builder&lt;/em&gt; turns all of it into a printable checklist that names the document to ask for.&lt;/p&gt;

&lt;p&gt;Then ask the chat about flat B-1502. It goes to Sanity, checks the registration, sees that Building B is sanctioned for Ground + 12, and tells you a fifteenth-floor flat has no approved plan. Open &lt;em&gt;How I checked&lt;/em&gt; under the answer and you'll see every query it ran.&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/Reet24-del" rel="noopener noreferrer"&gt;
        Reet24-del
      &lt;/a&gt; / &lt;a href="https://github.com/Reet24-del/home-truth" rel="noopener noreferrer"&gt;
        home-truth
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Compare builder promises with registered documents through cited findings and an interactive 3D building.
    &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;Home Truth&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Before you pay for a flat, check the builder's promises.&lt;/p&gt;
&lt;p&gt;Home Truth compares what a builder advertises (brochures, websites, broker messages) with what is registered with the state Real Estate Regulatory Authority (RERA), what the draft agreement for sale says, and what the Real Estate (Regulation and Development) Act, 2016 requires. Every finding shows the exact words it came from.&lt;/p&gt;
&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16" rel="nofollow"&gt;DEV x Sanity Challenge&lt;/a&gt;, Path One: an agent that queries real content through Sanity Context.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why it needs structured content&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Ask a keyword search "how many floors does Nimbus Greens have?" and the brochure answers "G+18" with total confidence. Home Truth knows three things a search engine doesn't:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Which document outranks which.&lt;/strong&gt; The registration is what the builder is legally held to; the brochure is marketing. The sanctioned plan says Ground + 12, so floors 13 to 18 have no approved plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What the&lt;/strong&gt;…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Reet24-del/home-truth" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;studio/&lt;/code&gt; holds the Sanity Studio, the schema, the comparison engine and the scripts. &lt;code&gt;web/&lt;/code&gt; is the Next.js 16 site, the three.js scenes and the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Sanity
&lt;/h2&gt;

&lt;h3&gt;
  
  
  I started with the schema, because the schema is the product
&lt;/h3&gt;

&lt;p&gt;Before any UI, I sat down with the question "what is a fact, here?" and ended up with five document types.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;sourceDocument&lt;/code&gt; is one document's full text, plus a &lt;code&gt;kind&lt;/code&gt;: registration, agreement, marketing or law. That one field is what lets the system know who to believe.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;attribute&lt;/code&gt; is something a buyer cares about, like floors per building, carpet area or the possession date. It also says how that fact should be compared: the unit, a tolerance, a controlled vocabulary, and whether it's checked for equality or against a legal limit. "Floors" and "booking amount" behave very differently, and the attribute is where that difference lives.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;claim&lt;/code&gt; is one document's version of one attribute, together with the exact words it came from and where they appear. The demo project has 28 of them. A &lt;code&gt;finding&lt;/code&gt; is the verdict once all the claims for an attribute are compared: match, mismatch, violation, or only one source. And a &lt;code&gt;project&lt;/code&gt; ties it all together.&lt;/p&gt;

&lt;p&gt;The rule I cared most about was that nothing gets paraphrased. Every claim carries a quote, and &lt;code&gt;npm test&lt;/code&gt; checks each demo quote word for word against its source document. When Claude extracts claims from a new document, they go through the same check and land in the Studio's &lt;em&gt;Claims to verify&lt;/em&gt; view, marked unverified, until a person approves them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code decides who's wrong, not the model
&lt;/h3&gt;

&lt;p&gt;I didn't want an LLM deciding whether a builder broke the law. So findings come from a small comparison engine, &lt;code&gt;studio/lib/compare.ts&lt;/code&gt;. It ranks the sources (Act, then registration, then agreement, then marketing), applies the tolerances and vocabularies, and checks legal limits. The same claims always produce the same findings, which means every line of the report can be traced back to a quote. The model's job comes later, and it's a narrower one: explain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pointing Sanity Context at it
&lt;/h3&gt;

&lt;p&gt;This is where it got interesting.&lt;/p&gt;

&lt;p&gt;I created a Knowledge Base in the Context app and pointed it at my own dataset, using a GROQ source query to pull in every document that has a body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*[_type == "sourceDocument" &amp;amp;&amp;amp; defined(body)]{
  title, kind, publisher, publishedAt, "project": project-&amp;gt;name, body
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the Knowledge Base's purpose I wrote it the way you'd brief a person: who's going to ask questions (homebuyers in India), what should lead (buyer rights, registered facts, agreement clauses, red flags), and what's out of scope.&lt;/p&gt;

&lt;p&gt;Then I hit &lt;em&gt;Build entries&lt;/em&gt;, and Context came back with six issues. Every one of them was a conflict between the brochure and the registration. The floors, the number of towers, the possession date, the sizes of both flat types, and a jogging track advertised at 1 km that's registered at 600 m. Reading through them felt a bit like watching the product work on itself. I resolved each one in favour of the registration, and Context saved every decision as an instruction that future builds keep.&lt;/p&gt;

&lt;p&gt;But "the registration wins" on its own throws away something useful. A buyer needs to know what they were &lt;em&gt;promised&lt;/em&gt; as well as what's true, because that gap is exactly what they'll raise with the builder. So I added one instruction by hand:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a marketing document contradicts a registration document, treat the registration as correct, but keep the marketing claim in the entry, labelled "Advertised", with its source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now the agent can say "you were told March 2027, but the builder is held to 31 December 2028", which is the sentence that actually helps.&lt;/p&gt;

&lt;p&gt;I'll be honest about one gap. I meant to add the RERA Act as a PDF, as a second source. The government site wouldn't serve the file to my machine, so for now the law lives in the dataset as quoted claims, Section 13(1) on booking amounts and Section 14(3) on defect liability, and the agent reaches it through GROQ.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two endpoints, two jobs
&lt;/h3&gt;

&lt;p&gt;The agent talks to Sanity through two Context MCP endpoints, and keeping them separate was deliberate. An endpoint that has both a dataset and a Knowledge Base attached quietly serves only the dataset.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;home-truth-data&lt;/code&gt; runs in GROQ mode and answers exact questions. Each chat narrows it to the current project by adding a &lt;code&gt;groqFilter&lt;/code&gt; to the endpoint URL, so the agent only sees that project, the attribute definitions and the law. Context combines that filter with the endpoint's own, so it can only ever narrow access, never widen it. I also cut its tool list down to &lt;code&gt;groq_query&lt;/code&gt;, &lt;code&gt;schema_explorer&lt;/code&gt; and &lt;code&gt;array_field_reader&lt;/code&gt;. The system prompt already explains the schema, so &lt;code&gt;initial_context&lt;/code&gt; was just spending tokens.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;home-truth-kb&lt;/code&gt; runs in Knowledge Base mode. That's where the agent goes for "what does this clause mean" and "what are my rights if possession is late". It calls &lt;code&gt;initial_context&lt;/code&gt; once to get the outline, then &lt;code&gt;knowledge_base_read&lt;/code&gt; for the entries it needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the agent actually does
&lt;/h3&gt;

&lt;p&gt;The agent runs on Groq with &lt;code&gt;openai/gpt-oss-120b&lt;/code&gt;, using Groq's Responses API. Groq connects to both endpoints as remote MCP servers and runs the tool calls itself, so my server just sends the conversation and passes each step back to the page.&lt;/p&gt;

&lt;p&gt;When I asked it how many floors the towers are registered for and what the brochure claims, it first ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*[_type == "finding" &amp;amp;&amp;amp; attribute-&amp;gt;label match "*floor*"]{status, severity, summary, "fact": attribute-&amp;gt;label, entries}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it pulled the two claims behind that finding, opened the Knowledge Base outline, and read the &lt;em&gt;possession and delays&lt;/em&gt; and &lt;em&gt;buyer rights&lt;/em&gt; entries. The answer quoted the sanctioned plan ("Ground + 12") against the brochure ("G+18"), called it a critical mismatch, summarised Section 18 on delayed possession, and finished with what to ask the builder for and what not to pay yet. All five steps sit under &lt;em&gt;How I checked&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The system prompt is short on personality and strict on rules. Trust the Act, then the registration, then the agreement, then marketing. Never invent a quote, a section number, a date or an amount. If neither source knows, say so and send the buyer to the state RERA portal or a lawyer.&lt;/p&gt;

&lt;h3&gt;
  
  
  The parts that bit me
&lt;/h3&gt;

&lt;p&gt;Project tokens don't work for Context. I got a 403 until I made an &lt;em&gt;organization&lt;/em&gt; token with Context Viewer.&lt;/p&gt;

&lt;p&gt;Deploying the schema wasn't enough, either. The GROQ endpoint kept saying "No Studio application found" until I ran &lt;code&gt;sanity deploy&lt;/code&gt; and the Studio went live. Then everything turned green at once.&lt;/p&gt;

&lt;p&gt;The model has habits. gpt-oss leaves markers like &lt;code&gt;【result[0].quote】&lt;/code&gt; in its prose and drops &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; into table cells, so both get stripped before an answer reaches the page.&lt;/p&gt;

&lt;p&gt;And the chat didn't start on Groq. I first built it on Claude's MCP connector, then moved it over. Because both run MCP on their side, the switch touched one file of about 90 lines. Claude still does the claim extraction for new documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sanity Project Details
&lt;/h2&gt;

&lt;p&gt;The project ID is &lt;code&gt;f5y6g2q3&lt;/code&gt;, and the &lt;code&gt;production&lt;/code&gt; dataset is public. You can query it straight away: &lt;a href="https://f5y6g2q3.api.sanity.io/v2025-01-01/data/query/production?query=*%5B_type%3D%3D%22project%22%5D" rel="noopener noreferrer"&gt;every project&lt;/a&gt;, or &lt;a href="https://f5y6g2q3.api.sanity.io/v2025-01-01/data/query/production?query=*%5B_type%3D%3D%22finding%22%5D%7Bstatus%2Cseverity%2Csummary%7D" rel="noopener noreferrer"&gt;all the findings&lt;/a&gt;. The demo has 4 source documents, 12 attributes, 28 claims and 12 computed findings. The Studio is at &lt;a href="https://home-truth.sanity.studio" rel="noopener noreferrer"&gt;https://home-truth.sanity.studio&lt;/a&gt; (sign-in required).&lt;/p&gt;




&lt;p&gt;Ananya didn't pay 20% that day. She went home with a list of questions instead.&lt;/p&gt;

&lt;p&gt;If you're about to book a flat in India, look the project up on your state's RERA portal first. Home Truth explains what the documents and the law say. It isn't legal advice.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>ai</category>
      <category>sanity</category>
    </item>
    <item>
      <title>Pani Kaisa Hai? A golgappa map that warns a neighbourhood about bad water, but only after a human checks</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Sun, 04 Oct 2026 07:50:29 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/pani-kaisa-hai-a-golgappa-map-that-warns-a-neighbourhood-about-bad-water-but-only-after-a-human-5he7</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/pani-kaisa-hai-a-golgappa-map-that-warns-a-neighbourhood-about-bad-water-but-only-after-a-human-5he7</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path Two: Vibe-Code Something Strange&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Every golgappa wala in India gets asked the same thing before the first bite: &lt;em&gt;pani saaf hai na?&lt;/em&gt; Is this water clean?&lt;/p&gt;

&lt;p&gt;Nobody asks that about their own tap, borewell or tanker, even though contaminated supply is one of the most common ways a whole neighbourhood falls sick at once. The signs show up early (a sewage smell, yellow water, two kids in the same lane with loose motions) but they stay scattered across WhatsApp groups until it is too late.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pani Kaisa Hai?&lt;/strong&gt; collects those signs in under a minute, adds them up per neighbourhood against India's drinking water standard (IS 10500) and, only when the risk is real, asks a local health worker to confirm before anyone is warned.&lt;/p&gt;

&lt;p&gt;Every neighbourhood is a golgappa on the map:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🟢&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Crisp&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No credible signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🟡&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Soggy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complaints rising, boil or filter first. This one is automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔴&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Phoot gaya&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Contamination confirmed by a named person. Never automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✨&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fresh batch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fix recorded, area recovering&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rule the whole thing rests on: &lt;strong&gt;software can make a golgappa soggy, only a person can make it burst.&lt;/strong&gt; An AI check can score a case and push it as far as "needs verification". It can never confirm or dismiss one. Every red alert carries the name of the person who confirmed it and the reason they gave.&lt;/p&gt;

&lt;p&gt;It is for residents, ASHA workers and residents' association volunteers in Indian cities. The demo runs on sample data for Indore.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://pani-kaisa-hai.vercel.app" rel="noopener noreferrer"&gt;https://pani-kaisa-hai.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; the golgappa map, the stall and &lt;strong&gt;Shake the golgappa&lt;/strong&gt;, a simulator that runs the app's real scoring code. Pile on signals and watch it go soggy on its own, then notice the "health worker confirms" button stays locked until there is evidence for a person to look at&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/area/sector-14&lt;/code&gt; an area page with the state, the reason and the arithmetic behind it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/report&lt;/code&gt; the four step report form&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/control&lt;/code&gt; the verifier queue. &lt;strong&gt;Passphrase: &lt;code&gt;pani-demo&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/studio&lt;/code&gt; the embedded Sanity Studio&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;A 98 second walkthrough told as a story. The frames are the live site, captured by a script; the narration is Murf's Hindi voice Shweta.&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%2Flpmx00gfcm56iwjvg0k2.jpg" 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%2Flpmx00gfcm56iwjvg0k2.jpg" alt="The landing page: a golgappa stall asking " width="800" height="984"&gt;&lt;/a&gt;&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%2Fd2y7zua0ali6la74l66f.jpg" 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%2Fd2y7zua0ali6la74l66f.jpg" alt="The map: nine crisp golgappas and one burst in Sector 14" width="800" height="984"&gt;&lt;/a&gt;&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%2Fv2vivryfr2efyyhupidx.jpg" 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%2Fv2vivryfr2efyyhupidx.jpg" alt="Step one of the report form: where are you?" width="800" height="720"&gt;&lt;/a&gt;&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%2Fzz3rkdz21l2g9vk79cbq.jpg" 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%2Fzz3rkdz21l2g9vk79cbq.jpg" alt="Sector 14 after a health worker confirmed it: Phoot gaya, what to do in English and Hindi, and who confirmed it and why" width="800" height="984"&gt;&lt;/a&gt;&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%2Feg1akddkt6lamu47xgcz.jpg" 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%2Feg1akddkt6lamu47xgcz.jpg" alt="The control room: an empty queue and the Sector 14 alert with its verifier and reason" width="800" height="740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Early warning from residents, not a lab test. All data in the demo is sample data.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;&lt;a href="https://github.com/Reet24-del/pani-kaisa-hai" rel="noopener noreferrer"&gt;https://github.com/Reet24-del/pani-kaisa-hai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next.js 16 (App Router, TypeScript, plain CSS Modules), Sanity Studio v6 embedded at &lt;code&gt;/studio&lt;/code&gt;, an App SDK control room in &lt;code&gt;control-room/&lt;/code&gt;, a Workflows definition in &lt;code&gt;sanity/workflows/&lt;/code&gt;, a scheduled Sanity Function in &lt;code&gt;functions/daily-tick/&lt;/code&gt;, Leaflet with OpenStreetMap tiles. 33 tests cover the risk score, the case rules (including "only a person can confirm"), the daily tick, the report input rules, the workflow definition and a lint for GROQ date comparisons.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Build Process
&lt;/h2&gt;

&lt;p&gt;I built this with Claude Code over about seven sessions between 19 September and 4 October and I kept a build log the whole way (&lt;code&gt;BUILD_LOG.md&lt;/code&gt; in the repo), including the parts that went badly. This section is the short version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Day 1: schema first, then the whole spine before the backend existed
&lt;/h3&gt;

&lt;p&gt;I started with the data model, not the UI, because the product only works if evidence and decisions are kept apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;report&lt;/code&gt;&lt;/strong&gt; is one resident's observation and it is &lt;strong&gt;append-only&lt;/strong&gt;. Corrections are new reports, never edits. An edited evidence trail is not evidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;waterCase&lt;/code&gt;&lt;/strong&gt; groups reports in one area and carries the verification status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;alert&lt;/code&gt;&lt;/strong&gt; is a confirmed warning and cannot exist without a &lt;code&gt;verifiedBy&lt;/code&gt; and a written reason.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;safetyLimit&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;riskSettings&lt;/code&gt;&lt;/strong&gt; hold the rules as &lt;em&gt;content&lt;/em&gt;. IS 10500 thresholds carry their clause as a citation, so a wrong number is a content fix in the Studio, not a deploy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;waterSource.areasServed&lt;/code&gt;&lt;/strong&gt; stores the source to area link once and areas read it back with &lt;code&gt;references()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Area state is derived but &lt;strong&gt;stored&lt;/strong&gt;, with a reason and a timestamp, so the map is one query and every golgappa can explain itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nine document types, written by hand. The Studio desk is laid out the way work arrives: Needs verification → Active alerts → Unmapped reports, then reference data.&lt;/p&gt;

&lt;p&gt;Then I asked Claude to stop following the day-by-day plan and just build, before I even had a Sanity project. That worked because of one early decision: when the Sanity env vars are missing, the home page renders setup steps instead of crashing. One guard (&lt;code&gt;sanityConfigured&lt;/code&gt;) decides whether any query runs at all, so the whole UI could be built against the schema first.&lt;/p&gt;

&lt;p&gt;In that session: the map and area pages, the four step report form, the report API (whitelisted fields, clamped numbers, a salted device hash instead of IP addresses, 3 reports per device per area per day), the risk score as pure functions with tests, the case engine and both control rooms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What went wrong on Day 1:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;defineLive&lt;/code&gt; comes from &lt;code&gt;next-sanity/live&lt;/code&gt;, not the package root.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;next build&lt;/code&gt; failed because the env module threw at import time, so a build with no Sanity project was impossible. I rewrote it to fall back to a placeholder project id.&lt;/li&gt;
&lt;li&gt;Node's test runner needed &lt;code&gt;allowImportingTsExtensions&lt;/code&gt; before &lt;code&gt;--experimental-strip-types&lt;/code&gt; would accept &lt;code&gt;.ts&lt;/code&gt; imports.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reaching past the Studio: Workflows, the App SDK and Functions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Workflows.&lt;/strong&gt; The verification flow lives in &lt;code&gt;sanity/workflows/waterCase.ts&lt;/code&gt; as data: intake → score → watch or needs verification → human decision → alert → resolved → closed. The AI check is a system actor that can move a case as far as &lt;code&gt;verification&lt;/code&gt;. Confirming or dismissing sits in a &lt;code&gt;decide&lt;/code&gt; activity whose actions are gated on the &lt;code&gt;verifier&lt;/code&gt; role. An agent and a person use the same transitions, only the person can take the last one.&lt;/p&gt;

&lt;p&gt;The engine's own validator rejected my first version twice. The workflow name had to match &lt;code&gt;^[a-z0-9][a-z0-9-]*$&lt;/code&gt; and every activity needed an action carrying &lt;code&gt;status: 'done'&lt;/code&gt; or the stage gate wedges. That is how I know the definition is real and not decorative.&lt;/p&gt;

&lt;p&gt;Being honest about where it stands: Workflows is in early access and the engine is not deployed on my project yet. Until it is, the same stages and the same human-only guard run through &lt;code&gt;sanity/lib/cases.ts&lt;/code&gt;, which the report route and both control rooms call. The workflow file passes &lt;code&gt;defineWorkflow&lt;/code&gt;'s validator and has tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App SDK.&lt;/strong&gt; &lt;code&gt;control-room/&lt;/code&gt; is a custom app for the Sanity Dashboard: the verifier queue with live data, the evidence for each case and the confirm or dismiss decision. Confirming writes the case decision and the alert in one transaction. There is also a &lt;code&gt;/control&lt;/code&gt; page in the Next app behind a passphrase, so judges can try it without a Sanity login. Both write the same fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity Functions.&lt;/strong&gt; The daily tick (quiet cases close, a Fresh batch goes back to Crisp after its quiet days, every golgappa is re-derived) is a scheduled Sanity Function in &lt;code&gt;functions/daily-tick/&lt;/code&gt;, deployed from &lt;code&gt;sanity.blueprint.ts&lt;/code&gt; with its own robot token that only has Editor rights on this project. It calls the same &lt;code&gt;runTick&lt;/code&gt; as the app, which takes any Sanity client, so the function and the old Vercel cron share one tested implementation. The cron stays as a backup 15 minutes later; a second run changes nothing. Its first deployed run timed out at the 10 second default, because re-deriving every area takes longer than that from Sanity's servers, so the blueprint now gives it 120 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom Studio input.&lt;/strong&gt; Readings are drawn against their limit in the Studio, using the same component the control room uses, so an editor sees "780 mg/L, over the 500 acceptable limit" instead of a bare number.&lt;/p&gt;

&lt;h3&gt;
  
  
  Day 2: the theme and a hard lesson about drawing people
&lt;/h3&gt;

&lt;p&gt;The first palette was cool mint, which is wrong for a golgappa. I rebuilt the tokens from the stall itself: sand, tamarind, saffron, roasted brown, imli pani, fried puri.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What failed.&lt;/strong&gt; I wanted a girl at the stall, pouring pani into a golgappa and reacting to each section as you scroll. Claude hand-drew her in SVG over three passes. The face worked, the arms never did: stroked limbs with separate hand shapes leave a lump where the outlines cross. After the third try the honest call was that hand-authoring a natural human figure in raw SVG paths was not going to get good, so we stopped iterating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What worked.&lt;/strong&gt; I generated her instead. One reference image from a detailed prompt, then three more moods generated &lt;em&gt;from that image as the reference&lt;/em&gt;, changing only pose and expression, which is what kept her the same person. Backgrounds were cut out locally with &lt;code&gt;sharp&lt;/code&gt; (flood-fill from the border, clear the big white gaps in the hair, keep small ones like eye whites, recolour the feathered edge so there is no white fringe on the dark theme). About 42 KB per pose as WebP. The image tool's schema was opaque, the free plan allowed one job at a time and I ran out of credits after four images, so the fifth mood reuses a pose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scroll bug.&lt;/strong&gt; The first version used an IntersectionObserver and got silently stuck, because the figure itself carried &lt;code&gt;data-mood&lt;/code&gt; so the observer kept picking her own mood. Then the footer never triggered because it is too short to reach the middle of the screen. One check per animation frame replaced both.&lt;/p&gt;

&lt;h3&gt;
  
  
  Day 3: dressing the page as an actual stall
&lt;/h3&gt;

&lt;p&gt;Feedback was that the girl was right but the page still read like a SaaS template. So it became a thela: a scalloped awning with bunting in pure CSS, a signboard headline with पानी painted huge behind it, an LED ticker reading every area's state off Sanity, a chalkboard "Aaj ka menu" with the action where the price would be and the &lt;strong&gt;Shake the golgappa&lt;/strong&gt; simulator running the real &lt;code&gt;scoreReports&lt;/code&gt; from &lt;code&gt;lib/risk.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bug caught by clicking, not by reading:&lt;/strong&gt; three fast clicks on "+" counted two, because the stepper computed &lt;code&gt;value + 1&lt;/code&gt; from a stale render. Functional updates fixed it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy day
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Vercel refused the first deploy: the Hobby plan only allows daily cron jobs and my &lt;code&gt;vercel.json&lt;/code&gt; ran the case tick every 15 minutes. The tick only closes quiet cases and returns recovered areas to Crisp, so daily is enough.&lt;/li&gt;
&lt;li&gt;I finally checked the IS 10500 numbers I had written from memory on Day 1. Every value was right, but two &lt;strong&gt;citations&lt;/strong&gt; were wrong (chlorine is in Table 2, bacteria in Table 6). Because limits are content, the fix was a three document patch, not a code change. That was the schema decision paying off.&lt;/li&gt;
&lt;li&gt;The hero said "Indore · live" right under a banner saying "Sample data". It now says demo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3 October: auditing the decision path
&lt;/h3&gt;

&lt;p&gt;I asked Claude to rate the project as a judge would. It gave functionality a 7, so I asked what would make it a 9.5. The answer was an audit of every path from report to alert, and it found real bugs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The App SDK control room only ever wrote drafts.&lt;/strong&gt; &lt;code&gt;@sanity/sdk&lt;/code&gt; edits the draft unless the document handle says &lt;code&gt;liveEdit: true&lt;/code&gt;. Confirming in the Dashboard made a draft alert the public site never saw. Now the decision, the alert and the area turning red go in one live-edit transaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Mark fixed" had no button,&lt;/strong&gt; so Fresh batch was unreachable from the control room.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A case could be confirmed twice,&lt;/strong&gt; which made two alerts. Decisions now act only on cases waiting for a person, every write is guarded by the case &lt;code&gt;_rev&lt;/code&gt;, and the alert id is derived from the case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server actions trusted the page.&lt;/strong&gt; Server actions are public endpoints, so each one now checks the sign-in itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A reporter's phone number was one GROQ query away&lt;/strong&gt; on a public dataset. Contact details now live in &lt;code&gt;private.contact.&amp;lt;reportId&amp;gt;&lt;/code&gt; documents. Ids with a dot sit on a path that Sanity never returns to unauthenticated requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A date filter never matched.&lt;/strong&gt; &lt;code&gt;submittedAt&lt;/code&gt; is a string, and comparing it to &lt;code&gt;dateTime(now())&lt;/code&gt; without &lt;code&gt;dateTime()&lt;/code&gt; was always false. Area pages showed no reports and the rate limit never fired. There is now a test that scans every GROQ string for that mistake.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The case rules became pure functions with tests, so "the scorer can raise a case to needs verification and never past it" is tested directly. Tests went from 11 to 29.&lt;/p&gt;

&lt;h3&gt;
  
  
  The last evening: a check from a stale copy
&lt;/h3&gt;

&lt;p&gt;On the last evening I asked a local Claude Code session "what is left". It read an old copy of the project on my Mac that had no git remote and stopped at 21 September, so its first answer was confidently wrong. The mistake surfaced when a CLI deploy from that folder was &lt;strong&gt;blocked&lt;/strong&gt; by Vercel: its commits were authored with an email the Hobby plan doesn't accept. That block saved me, because the deploy would have replaced the day's fixes with week-old code. Comparing the blocked deploy's metadata with the live one showed where the real repo was.&lt;/p&gt;

&lt;p&gt;It still found things worth fixing. &lt;code&gt;/api/cron/tick&lt;/code&gt; would run for anyone, because the secret check only ran &lt;em&gt;if&lt;/em&gt; &lt;code&gt;CRON_SECRET&lt;/code&gt; was set, and it wasn't. Now the secret is set and the route fails closed on any deployment. The citation fix had been written but never run against the live data. Two old write tokens from before the rotation were still active, and are now deleted. Then I confirmed the Sector 14 case myself in the control room and watched the area go red on the map.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I deliberately did not build
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Photo upload on reports. Asset uploads need the write token path designed properly and a reading carries more weight than a blurry photo.&lt;/li&gt;
&lt;li&gt;A Hindi interface. The &lt;em&gt;content&lt;/em&gt; is bilingual (area names, advice, alert precautions), the UI chrome is still English.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sanity Project Details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project ID:&lt;/strong&gt; &lt;code&gt;ya4g5th1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;production&lt;/code&gt; (public)&lt;/li&gt;
&lt;li&gt;Schema: &lt;code&gt;sanity/schemaTypes/&lt;/code&gt; (9 types), workflow: &lt;code&gt;sanity/workflows/waterCase.ts&lt;/code&gt;, App SDK app: &lt;code&gt;control-room/&lt;/code&gt;, scheduled Function: &lt;code&gt;functions/daily-tick/&lt;/code&gt; with &lt;code&gt;sanity.blueprint.ts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
    <item>
      <title>I built The Repair Line: turning small repairs into shared relief</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Mon, 07 Sep 2026 08:04:32 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/i-built-the-repair-line-turning-small-repairs-into-shared-relief-39bg</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/i-built-the-repair-line-turning-small-repairs-into-shared-relief-39bg</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-09-03"&gt;Weekend Challenge: Generosity Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built &lt;strong&gt;The Repair Line&lt;/strong&gt;, a community-repair platform for the small shared things that keep a neighbourhood moving: a broken public hand pump, a leaking roof above a ration counter, a damaged study desk, or a clinic fan that has stopped working.&lt;/p&gt;

&lt;p&gt;The goal is to make generosity visible and practical. Someone uploads a clear photo of a repair need, receives an AI-assisted assessment, and can add it to a local repair line where people can see the impact, the directional cost, and the amount already pledged.&lt;/p&gt;

&lt;p&gt;Each repair includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a real repair photo and a short explanation&lt;/li&gt;
&lt;li&gt;severity, people affected, and a directional INR cost range&lt;/li&gt;
&lt;li&gt;funding progress&lt;/li&gt;
&lt;li&gt;a before-and-after proof-of-repair concept&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The experience is designed to feel warm and community-led rather than like a generic fundraising dashboard. It starts with local repairs, but the city selector supports Lucknow, Kanpur, Prayagraj, Varanasi, and an all-cities view.&lt;/p&gt;

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

&lt;p&gt;Live app: &lt;a href="https://therepairline.vercel.app" rel="noopener noreferrer"&gt;The Repair Line&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try the flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose a city from the location selector.&lt;/li&gt;
&lt;li&gt;Browse local repair needs or click &lt;strong&gt;Show all repairs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Assess a repair&lt;/strong&gt;, upload a clear photo of a broken shared item.&lt;/li&gt;
&lt;li&gt;Receive an assessment of severity, plausibility, likely repair cost, and reasoning.&lt;/li&gt;
&lt;li&gt;Add the assessed repair to the line.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;The project is built with React and Vite, with API routes prepared for Vercel Functions.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/Reet24-del/the-repair-line" rel="noopener noreferrer"&gt;github.com/Reet24-del/the-repair-line&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key pieces of the implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React interface and location-aware repair feed&lt;/li&gt;
&lt;li&gt;Gemini-backed server-side assessment endpoint&lt;/li&gt;
&lt;li&gt;Snowflake-backed repair, pledge, sort, and city-filtering queries&lt;/li&gt;
&lt;li&gt;Vercel deployment and API routes&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  Starting with a small but meaningful problem
&lt;/h3&gt;

&lt;p&gt;I wanted to focus on generosity that is easy to understand. Not every community need requires a huge campaign. A ₹2,000–₹10,000 repair can make a real difference when it restores a shared tap, desk, roof, or fan.&lt;/p&gt;

&lt;p&gt;The product flow became: &lt;strong&gt;photo in, fixed out&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI assessment with Google Gemini
&lt;/h3&gt;

&lt;p&gt;The repair assessor accepts a photo and sends it to a server-side Gemini route. Gemini is asked to return structured JSON with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Low | Medium | High"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a directional INR range"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plausibility"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Likely genuine | Needs review | Unclear"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reasoning"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a concise explanation"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I require a photo before an assessment can run. This prevents the interface from creating a confident-looking repair result without visual evidence. The cost is intentionally presented as directional guidance rather than a quote.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repair feed and Snowflake
&lt;/h3&gt;

&lt;p&gt;Repair records include the repair title, location, severity, estimated cost, people helped, reason, image, and pledged amount. The Snowflake schema and query layer support feed filters for city, severity, and sorting.&lt;/p&gt;

&lt;p&gt;The feed initially keeps the page focused by showing a smaller set of repairs. A &lt;strong&gt;Show all repairs&lt;/strong&gt; control expands the complete list, while the city selector changes the listings and heading to keep the experience locally relevant.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;The frontend is deployed on Vercel, while Vercel Functions host the assessment, repair, and pledge endpoints. Sensitive credentials stay in server-side environment variables rather than the browser bundle.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Best Use of Google AI
&lt;/h3&gt;

&lt;p&gt;The project uses Google Gemini to analyse an uploaded repair photo and produce a structured, user-facing assessment. Gemini helps translate a visual problem into understandable severity, plausibility, repair guidance, and an INR cost range.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Use of Snowflake
&lt;/h3&gt;

&lt;p&gt;Snowflake provides the repair data layer for listings and pledges. The app is designed to query repairs by city, severity, and priority, so a growing local repair line remains filterable and useful.&lt;/p&gt;




&lt;p&gt;The Repair Line is a small idea on purpose: make a modest, shared repair easy to see, trust, and complete.&lt;/p&gt;

</description>
      <category>community</category>
      <category>react</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Answer Looked Right. That Was the Problem.</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Sun, 30 Aug 2026 16:28:44 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/the-answer-looked-right-that-was-the-problem-lhn</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/the-answer-looked-right-that-was-the-problem-lhn</guid>
      <description>&lt;p&gt;I started building &lt;strong&gt;The Verifier&lt;/strong&gt; because of a slightly uncomfortable thought:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if an AI gives you a perfectly written answer based on yesterday's truth?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not a hallucination. Not an obviously fake source. Just an answer that &lt;em&gt;used to be correct&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That felt more dangerous.&lt;/p&gt;

&lt;p&gt;A polished lie is easy to fear. An outdated fact wearing a confident suit? That one can quietly walk straight into reports, presentations, articles, and important decisions.&lt;/p&gt;

&lt;p&gt;So I decided to build something that would not simply answer a claim.&lt;/p&gt;

&lt;p&gt;It would argue with itself first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet The Verifier
&lt;/h2&gt;

&lt;p&gt;The Verifier is an evidence-first research assistant for public claims.&lt;/p&gt;

&lt;p&gt;You give it a claim such as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Verify that Brian Niccol is the CEO of Starbucks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of immediately producing a confident paragraph, it investigates the claim from two opposing directions.&lt;/p&gt;

&lt;p&gt;One research lane looks for evidence supporting the claim. Another actively searches for credible evidence contradicting it.&lt;/p&gt;

&lt;p&gt;This matters because normal search behaviour has a bias: once we find one convincing source, we usually stop looking.&lt;/p&gt;

&lt;p&gt;The Verifier does not get that luxury.&lt;/p&gt;

&lt;p&gt;It has to search both sides, place the evidence next to each other, and show its work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then Starbucks created the perfect plot twist
&lt;/h2&gt;

&lt;p&gt;The Starbucks leadership example turned out to be a great demonstration.&lt;/p&gt;

&lt;p&gt;One public source identifies Brian Niccol as Starbucks' current chairman and CEO.&lt;/p&gt;

&lt;p&gt;Another Starbucks source names Laxman Narasimhan as CEO.&lt;/p&gt;

&lt;p&gt;Both sources are real. Both come from Starbucks. Both look authoritative.&lt;/p&gt;

&lt;p&gt;So which one should the system trust?&lt;/p&gt;

&lt;p&gt;This is where the project became more than a fancy search interface.&lt;/p&gt;

&lt;p&gt;The answer was hiding in the metadata.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dates are boring—until they solve the mystery
&lt;/h2&gt;

&lt;p&gt;Most people do not get excited about fields such as datePublished, dateModified, or ISO timestamps.&lt;/p&gt;

&lt;p&gt;Honestly, neither did I.&lt;/p&gt;

&lt;p&gt;But those tiny pieces of metadata became the detective of this story.&lt;/p&gt;

&lt;p&gt;The Verifier extracts machine-readable dates from every source. It records which metadata field was used, preserves the original value, and normalizes the date to UTC.&lt;/p&gt;

&lt;p&gt;Now the system can compare evidence deterministically.&lt;/p&gt;

&lt;p&gt;It does not choose a source because it sounds more confident. It can explain that one source represents an older leadership announcement while another contains newer evidence about the company's current leadership.&lt;/p&gt;

&lt;p&gt;That difference matters.&lt;/p&gt;

&lt;p&gt;The conclusion is not merely:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Brian Niccol is CEO.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The claim is supported by newer public evidence. The conflicting source is legitimate, but outdated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Suddenly, the contradiction is not something to hide. It is part of the explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  I wanted the disagreement to remain visible
&lt;/h2&gt;

&lt;p&gt;A lot of AI tools clean up the messy middle.&lt;/p&gt;

&lt;p&gt;You provide a question. Something complicated happens. A neat answer appears.&lt;/p&gt;

&lt;p&gt;Magic.&lt;/p&gt;

&lt;p&gt;Also slightly terrifying.&lt;/p&gt;

&lt;p&gt;I wanted The Verifier to show the messy middle.&lt;/p&gt;

&lt;p&gt;The interface keeps the supporting and conflicting evidence in separate lanes. Each source displays its role, URL, relevant statement, and date information.&lt;/p&gt;

&lt;p&gt;The user can inspect why the system reached its conclusion instead of being asked to trust a glowing confidence score.&lt;/p&gt;

&lt;p&gt;Because “97% confident” sounds impressive, but it does not tell me whether the model checked last year's announcement against today's leadership page.&lt;/p&gt;

&lt;p&gt;Evidence does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The voice feature fought back
&lt;/h2&gt;

&lt;p&gt;I also wanted the experience to feel conversational.&lt;/p&gt;

&lt;p&gt;The original idea was simple: click &lt;strong&gt;Speak brief&lt;/strong&gt;, say the claim, and continue asking questions naturally.&lt;/p&gt;

&lt;p&gt;The browser had other plans.&lt;/p&gt;

&lt;p&gt;At one point, the button barely behaved like a button. Then voice mode required clicking it repeatedly. Even worse, every new interaction felt like the previous conversation had been erased from existence.&lt;/p&gt;

&lt;p&gt;The Verifier had the memory of a goldfish with Wi-Fi.&lt;/p&gt;

&lt;p&gt;That forced me to rethink the feature.&lt;/p&gt;

&lt;p&gt;Voice could not be a one-shot transcription gimmick. It needed to be a continuous conversation where the active claim, collected sources, and date resolution remained available for follow-up questions.&lt;/p&gt;

&lt;p&gt;I also added text as a permanent fallback because demos—and browsers—have a wonderful sense of dramatic timing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent can research. It cannot press Save for you.
&lt;/h2&gt;

&lt;p&gt;This became my favourite part of the project.&lt;/p&gt;

&lt;p&gt;After completing the investigation, The Verifier does not automatically store the result.&lt;/p&gt;

&lt;p&gt;It asks the user for approval.&lt;/p&gt;

&lt;p&gt;That is not just a polite message in the interface. The restriction is enforced on the server.&lt;/p&gt;

&lt;p&gt;The server creates a one-time approval token and refuses to persist the dossier until explicit approval is received. Export remains locked as well.&lt;/p&gt;

&lt;p&gt;If the user chooses to keep investigating, nothing is saved.&lt;/p&gt;

&lt;p&gt;Only after server-confirmed approval does the dossier become permanent and downloadable.&lt;/p&gt;

&lt;p&gt;The system can investigate, compare, and explain.&lt;/p&gt;

&lt;p&gt;The final decision still belongs to a human.&lt;/p&gt;

&lt;h2&gt;
  
  
  Of course, the build was not a straight line
&lt;/h2&gt;

&lt;p&gt;The first UI used fictional “Maya Chen” and “Northstar AI” evidence while the backend used the real Starbucks case.&lt;/p&gt;

&lt;p&gt;Very coherent. Absolutely no notes.&lt;/p&gt;

&lt;p&gt;That mismatch had to go.&lt;/p&gt;

&lt;p&gt;Then came GitHub authentication, voice bugs, disappearing conversational context, provider configuration, Groq setup, and a Daytona API key that continued rejecting me like it had a personal grudge.&lt;/p&gt;

&lt;p&gt;Some parts worked immediately. Several parts worked only after I stopped assuming they worked. A few parts smiled during testing and broke the moment I opened the demo.&lt;/p&gt;

&lt;p&gt;That is the real version of building for a hackathon.&lt;/p&gt;

&lt;p&gt;It is not one cinematic montage with energetic music. It is a series of tiny mysteries, questionable browser tabs, and commits that begin with the word “fix.”&lt;/p&gt;

&lt;p&gt;But each problem improved the project.&lt;/p&gt;

&lt;p&gt;The fictional demo became a real public case. The voice button became a conversation. The date field became an explanation. The approval message became a server boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  What The Verifier is really about
&lt;/h2&gt;

&lt;p&gt;The Verifier is not trying to make AI sound smarter.&lt;/p&gt;

&lt;p&gt;It is trying to make AI easier to question.&lt;/p&gt;

&lt;p&gt;The important output is not only the final conclusion. It is the path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What evidence supported the claim?&lt;/li&gt;
&lt;li&gt;What evidence contradicted it?&lt;/li&gt;
&lt;li&gt;Which source was newer?&lt;/li&gt;
&lt;li&gt;Which metadata field proved that?&lt;/li&gt;
&lt;li&gt;Why was the conflict resolved this way?&lt;/li&gt;
&lt;li&gt;Did a human approve saving the result?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That path becomes an inspectable dossier that a researcher, journalist, policy team, or compliance reviewer can defend.&lt;/p&gt;

&lt;p&gt;The internet changes. Leadership changes. Policies change. Yesterday's correct answer quietly becomes today's misinformation.&lt;/p&gt;

&lt;p&gt;The Verifier is my attempt to catch that moment.&lt;/p&gt;

&lt;p&gt;Not by asking you to trust another polished AI answer.&lt;/p&gt;

&lt;p&gt;By showing you the evidence, explaining the conflict, and waiting for you to decide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify first. Save only when you are ready.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;🚀 &lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://the-verifier.vercel.app" rel="noopener noreferrer"&gt;the-verifier.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Project:&lt;/strong&gt; &lt;a href="https://github.com/Reet24-del/the-verifier" rel="noopener noreferrer"&gt;github.com/Reet24-del/the-verifier&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you build with AI, I would love to know: &lt;strong&gt;what part of an answer do you wish AI tools showed more clearly?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>hackathon</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Good Boy Amnesia: An AI Detective Game where Memory IS the Gameplay 🐶🧠</title>
      <dc:creator>Reet Singh</dc:creator>
      <pubDate>Mon, 17 Aug 2026 07:04:29 +0000</pubDate>
      <link>https://dev.to/reet_singh_ee97da2986538e/good-boy-amnesia-an-ai-detective-game-where-memory-is-the-gameplay-5ap0</link>
      <guid>https://dev.to/reet_singh_ee97da2986538e/good-boy-amnesia-an-ai-detective-game-where-memory-is-the-gameplay-5ap0</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/weekend-2026-08-13"&gt;Weekend Challenge: Dog Days Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Good Boy Amnesia&lt;/strong&gt; is a detective game built for Dog Days where an AI agent's entire long-term memory lifecycle — &lt;code&gt;remember → recall → memify → forget&lt;/code&gt; — &lt;strong&gt;is the gameplay loop&lt;/strong&gt;, visualized as a live 3D knowledge graph in Three.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Story:
&lt;/h3&gt;

&lt;p&gt;Your owner &lt;strong&gt;Dev&lt;/strong&gt; left you home alone last night, and you threw a legendary neighborhood puppy party. At 6:00 AM, your memory graph was corrupted. Dev arrives home at &lt;strong&gt;noon (12:00 PM)&lt;/strong&gt;, the living room is trashed, and his favorite leather slipper is missing.&lt;/p&gt;

&lt;p&gt;You play &lt;strong&gt;Buster&lt;/strong&gt;, a Golden Retriever whose mind is literally a knowledge graph. Reconstruct what happened last night, interrogate the neighborhood animals, purge false rumors, and find Dev's slipper before he walks through the door!&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo &amp;amp; Screenshots 🎮
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Game Demo&lt;/strong&gt;: &lt;code&gt;https://good-boy-amnesia.vercel.app&lt;/code&gt; &lt;em&gt;(or your Hugging Face Space URL)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video Walkthrough&lt;/strong&gt;: &lt;em&gt;(Optional link to your screen recording)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gameplay Breakdown:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;🔍 Investigate Hotspots&lt;/strong&gt;: Explore 6 locations (&lt;em&gt;Living Room, Backyard Lawn, Bella's Garden Fence, Dog Park, Lou's Oak Tree Stash, and Rooftop Sandbox&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🗂 File Clues (&lt;code&gt;remember&lt;/code&gt;)&lt;/strong&gt;: Committing a fact adds glowing nodes to your live 3D memory graph in real-time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;💬 Interrogate Animals&lt;/strong&gt;: Chat with &lt;strong&gt;Bella&lt;/strong&gt; (the wise cat), &lt;strong&gt;Lou&lt;/strong&gt; (the shifty raccoon), &lt;strong&gt;Rev. Rex&lt;/strong&gt; (the howling Basset Hound), and &lt;strong&gt;Barnaby&lt;/strong&gt; (the hungover pug). The characters read your live graph and react dynamically to your knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🧠 Connect the Dots (&lt;code&gt;memify&lt;/code&gt;)&lt;/strong&gt;: Consolidate stored memories into derived inferences (e.g. realizing the slipper was locked in the treat safe before the party started).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🗑 Purge False Leads (&lt;code&gt;forget&lt;/code&gt;)&lt;/strong&gt;: 5 red herrings are hidden in the story. Delete gossip from your memory log to keep your graph clean and win the case!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🎯 Tell Dev (&lt;code&gt;solve&lt;/code&gt;)&lt;/strong&gt;: Reconstruct the timeline before noon to win in a burst of victory confetti!&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Code Repository ⭐
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/your-username/good-boy-amnesia" rel="noopener noreferrer"&gt;github.com/your-username/good-boy-amnesia&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How I Built It (Tech Stack) 🛠️
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>ai</category>
      <category>gamedev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
