<?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: Soumwadeep Guha</title>
    <description>The latest articles on DEV Community by Soumwadeep Guha (@soumwadeep).</description>
    <link>https://dev.to/soumwadeep</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%2F530140%2F7dc9516d-8d94-4317-87b5-5b1127f7853a.png</url>
      <title>DEV Community: Soumwadeep Guha</title>
      <link>https://dev.to/soumwadeep</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/soumwadeep"/>
    <language>en</language>
    <item>
      <title>Dormant: an open-weight model read my Mac's Spotlight logs and found 71 GB I will never open again</title>
      <dc:creator>Soumwadeep Guha</dc:creator>
      <pubDate>Wed, 21 Oct 2026 10:59:15 +0000</pubDate>
      <link>https://dev.to/soumwadeep/dormant-an-open-weight-model-read-my-macs-spotlight-logs-and-found-71-gb-i-will-never-open-again-27j4</link>
      <guid>https://dev.to/soumwadeep/dormant-an-open-weight-model-read-my-macs-spotlight-logs-and-found-71-gb-i-will-never-open-again-27j4</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;&lt;strong&gt;Dormant answers one question about a file on my Mac: is this ever coming back?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not "is this file important", which is a different and much harder question. Just this: the file has been shut for three weeks, will it be opened again inside ninety days? If the answer is no, it goes on a list. If I approve the list, Dormant moves those files out of the way.&lt;/p&gt;

&lt;p&gt;The core is &lt;a href="https://github.com/PriorLabs/TabPFN" rel="noopener noreferrer"&gt;TabPFN&lt;/a&gt;, an open-weight tabular foundation model, running locally on CPU. No internet, no API key, no account, no bill. It was built and benchmarked on an 8 GB Apple M1, which is the kind of machine most of us actually have.&lt;/p&gt;

&lt;h3&gt;
  
  
  The chore it removes
&lt;/h3&gt;

&lt;p&gt;I know exactly which folder is the problem. I have opened it eleven times, looked at four hundred file names, felt the cost of deciding about each one, and closed it. That is not a memory problem. It is a &lt;em&gt;thousand small decisions&lt;/em&gt; problem, and no human with a deadline is going to make them on a Tuesday.&lt;/p&gt;

&lt;p&gt;So the sloth part is literal. Dormant makes the thousand decisions overnight, in a form I can approve with one keypress.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it found on my machine
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dormant found 519 files worth 71.0 GB it is 99% sure you will not reopen
inside 90 days. On the held-out slice it was right 99% of the time it said stop.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;68.2 GB of that is one drone footage folder I have not opened since the week I filled it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three levels of letting go
&lt;/h3&gt;

&lt;p&gt;The ladder is deliberately uneven, because the destructive rung should be harder to reach than the recoverable ones.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;action&lt;/th&gt;
&lt;th&gt;what happens&lt;/th&gt;
&lt;th&gt;reversible by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;moves files into a dated folder, writes a manifest&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;undo&lt;/code&gt;, from inside Dormant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Trash&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;moves files to the macOS Trash&lt;/td&gt;
&lt;td&gt;Finder's Put Back, or &lt;code&gt;undo&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Delete permanently&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the only path that calls &lt;code&gt;unlink&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;nothing in this program&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Permanent delete requires the caller to supply the literal word &lt;code&gt;DELETE&lt;/code&gt;, writes the manifest of what is about to be lost &lt;em&gt;before&lt;/em&gt; the first file goes, and &lt;code&gt;undo&lt;/code&gt; refuses to touch a delete manifest. Stage and Trash are tested against a tripwire: &lt;code&gt;os.remove&lt;/code&gt;, &lt;code&gt;os.unlink&lt;/code&gt; and &lt;code&gt;os.rmdir&lt;/code&gt; are patched to raise, so if they ever learn to delete, the suite fails.&lt;/p&gt;

&lt;p&gt;And before any of it, there is a preview. Selecting six rows and pressing &lt;strong&gt;view&lt;/strong&gt; shows the actual images, PDFs, text and video in a drawer, because the fastest way to trust a list of 519 files is to look at six of them and see that it is right.&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%2Fdub9p2yleh9k6dlagxex.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%2Fdub9p2yleh9k6dlagxex.png" alt="The dormancy field" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The dashboard is a local FastAPI service plus one page of vanilla JavaScript. The three.js build is vendored into the repository rather than loaded from a CDN, because a product whose whole argument is "this never needs the internet" cannot afford to depend on one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run it locally
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

python cli.py scan      &lt;span class="c"&gt;# index files from stat() and Spotlight metadata (~12s)&lt;/span&gt;
python cli.py brief     &lt;span class="c"&gt;# the two-line morning brief&lt;/span&gt;
python cli.py top       &lt;span class="c"&gt;# the files it thinks are dead&lt;/span&gt;
python cli.py bench     &lt;span class="c"&gt;# the scoreboard, on your machine&lt;/span&gt;
python cli.py serve     &lt;span class="c"&gt;# mission control on http://127.0.0.1:8712&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  See it without touching anyone's disk
&lt;/h3&gt;

&lt;p&gt;The index contains file paths, sizes and the dates I opened things. That is personal, so the repository ships a synthetic corpus with the same shape and none of the names. Every screenshot in this post came from it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli.py &lt;span class="nt"&gt;--demo&lt;/span&gt; demo &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python cli.py &lt;span class="nt"&gt;--demo&lt;/span&gt; run &lt;span class="nt"&gt;--bench&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python cli.py &lt;span class="nt"&gt;--demo&lt;/span&gt; serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What the dashboard shows
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Morning brief.&lt;/strong&gt; Two lines. Every number in them is computed, never generated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dormancy field.&lt;/strong&gt; A 3D plot where radius is a file's age and height is the model's dormancy score, so the shape of a neglected disk is visible before you read anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volume forecast.&lt;/strong&gt; A gauge, the growth curve, and the date the volume reaches a warning level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reclaim ledger.&lt;/strong&gt; Gigabytes identified, files on the stop list, days bought at the current growth rate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model bench.&lt;/strong&gt; The scoreboard below, plus a chart of how each model degrades as the labelled corpus shrinks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dormant register.&lt;/strong&gt; The ranked list: filterable, sortable, multi-selectable, with preview, stage, trash and delete on the selection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent console.&lt;/strong&gt; One sentence in, validated tool calls out.&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%2Fqd8k3f0ddhwnkes9p7s7.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%2Fqd8k3f0ddhwnkes9p7s7.png" alt="Model bench and register" width="800" height="289"&gt;&lt;/a&gt;&lt;br&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%2F8cbkup7upfod42t86x4m.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%2F8cbkup7upfod42t86x4m.png" alt="Light theme, cyan accent" width="800" height="667"&gt;&lt;/a&gt;&lt;br&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%2Fxcucno6v0k4nvs4aogek.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%2Fxcucno6v0k4nvs4aogek.png" alt="Mobile at 390px" width="390" height="844"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

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

&lt;p&gt;GPL-3.0. Six commits, 43 tests, no build step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dormant/
  scanner.py   two-pass ingestion: os.walk for the universe, mdls for history
  features.py  observation points inside each dormancy streak, and their labels
  dataset.py   time-split holdout and rolling-origin folds
  model.py     TabPFN provider, four baselines, the scarcity benchmark
  forecast.py  disk projection from measured snapshots or a reconstructed curve
  brief.py     the two lines, as a template over computed integers
  action.py    stage, trash, permanent delete, undo, preview metadata
  agent.py     a sentence in, validated tool calls out
  demo.py      the synthetic corpus
api/app.py     FastAPI service, bound to 127.0.0.1
cli.py         scan, brief, top, bench, run, preview, archive, trash, purge, undo, serve
web/           one page, vendored three.js, two themes, four accents, mobile tabs
tests/         43 tests: label leakage, evaluation integrity, file safety
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h3&gt;
  
  
  The model, and why it is the right shape for this
&lt;/h3&gt;

&lt;p&gt;TabPFN is not a language model doing arithmetic. It is a transformer trained once, offline, on millions of synthetic tabular datasets, which then does &lt;strong&gt;in-context inference&lt;/strong&gt;: your labelled rows go in as context and a posterior comes out. No gradient step on my data, no training run, no per-token bill.&lt;/p&gt;

&lt;p&gt;That matters here because a personal file corpus is &lt;em&gt;small&lt;/em&gt;. This machine produced about seven thousand labelled rows from 669 personal documents. That is precisely the regime an in-context model is built for, and precisely the regime where "let me fine-tune something" is a bad afternoon.&lt;/p&gt;

&lt;h3&gt;
  
  
  The labels were already on my machine
&lt;/h3&gt;

&lt;p&gt;This is the part that made the project possible in a week rather than a month. macOS records every date a document app opened a file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mdls &lt;span class="nt"&gt;-name&lt;/span&gt; kMDItemUsedDates ~/Documents/tax.pdf
&lt;span class="c"&gt;#   "2024-02-11 09:14:02 +0000",&lt;/span&gt;
&lt;span class="c"&gt;#   "2024-09-27 18:30:00 +0000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I did not have to run a logger and hope. I read three years of my own file-open history on the first pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Turning that into a supervised problem
&lt;/h3&gt;

&lt;p&gt;For a file created at &lt;code&gt;C&lt;/code&gt; with recorded opens &lt;code&gt;d1..dk&lt;/code&gt;, Dormant builds one observation row per sampled point &lt;strong&gt;inside each dormancy streak&lt;/strong&gt;. A row's features are only ever what existed at that date: age, days since last open, days since modification, how many times it has been opened, mean and max gap between opens, size, extension, folder depth, weekday and hour.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;label&lt;/th&gt;
&lt;th&gt;rule&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;some later open falls within 90 days of the observation date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the next open is more than 90 days away, or never arrives, and the window has closed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;dropped&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the 90-day window is still open, because the outcome has not happened yet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That third row is the difference between an evaluation and a fiction. An unclosed window is censored, and Dormant throws the row away rather than guessing at it.&lt;/p&gt;

&lt;p&gt;The split is on the observation date, never random. Two rows from the same file share a history, so a random split puts yesterday inside tomorrow. Validation is rolling-origin: train on all history up to a cut, score the slice immediately after it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two passes for ingestion
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;os.walk&lt;/code&gt; plus &lt;code&gt;os.stat&lt;/code&gt; gives the whole universe in under two seconds. &lt;code&gt;mdls&lt;/code&gt; is a subprocess round trip to the Spotlight daemon, so it only runs on personal files, in a thread pool, ten seconds.&lt;/p&gt;

&lt;p&gt;My first version paid 180 seconds to ask eight thousand repository files whether they had been opened. That was both slow and wrong: nobody double-clicks a vendored PHP file, and a model trained on those rows learns that everything in a repository is dead weight, which is true and useless. Files under &lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;vendor&lt;/code&gt;, &lt;code&gt;Pods&lt;/code&gt;, any build-system marker, or any directory that looks like a checkout are indexed but never scored.&lt;/p&gt;

&lt;h3&gt;
  
  
  The forecast is arithmetic, not a model
&lt;/h3&gt;

&lt;p&gt;Free space comes from &lt;code&gt;disk_usage()&lt;/code&gt;. The growth rate comes from a Theil-Sen fit, which is robust to the one day a phone backup lands. The projection is a line. TabPFN is offered a second, learned projection of the same series, because Prior Labs describes the product as forecasting, but the headline date is always the one you could check with a calculator. If the growth rate is below 0.05 GB a day, Dormant says "no measurable fill rate" instead of printing a date eighty years out, which is exactly what my first version did.&lt;/p&gt;

&lt;h3&gt;
  
  
  Previewing files is a new kind of exposure
&lt;/h3&gt;

&lt;p&gt;The preview endpoints hand out the &lt;em&gt;contents&lt;/em&gt; of real files, so they are not open to anything that can reach &lt;code&gt;127.0.0.1:8712&lt;/code&gt;. The server generates a token at startup and injects it into the page's own HTML; every content endpoint requires it and returns 403 without it. Another process, or a website your browser visits while the dashboard is open, gets nothing. There is a test for that too.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it measured
&lt;/h3&gt;

&lt;p&gt;Real index on this machine: 88,250 files walked in about 12 seconds, 12,719 openable files stored, 669 personal documents, 283 of them carrying recorded open history, 6,918 labelable observation rows. Time-split holdout of 4,842 train and 1,800 test rows, cut 2025-03-01, 10.6% positive.&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;AUC&lt;/th&gt;
&lt;th&gt;precision&lt;/th&gt;
&lt;th&gt;recall&lt;/th&gt;
&lt;th&gt;GB reclaimed&lt;/th&gt;
&lt;th&gt;wrong calls&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;rule: 90 days idle&lt;/td&gt;
&lt;td&gt;0.378&lt;/td&gt;
&lt;td&gt;0.862&lt;/td&gt;
&lt;td&gt;0.704&lt;/td&gt;
&lt;td&gt;3.9&lt;/td&gt;
&lt;td&gt;181&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;logistic regression&lt;/td&gt;
&lt;td&gt;0.821&lt;/td&gt;
&lt;td&gt;0.959&lt;/td&gt;
&lt;td&gt;0.714&lt;/td&gt;
&lt;td&gt;45.0&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;random forest&lt;/td&gt;
&lt;td&gt;0.920&lt;/td&gt;
&lt;td&gt;0.985&lt;/td&gt;
&lt;td&gt;0.758&lt;/td&gt;
&lt;td&gt;44.4&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HistGradientBoosting&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.962&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.988&lt;/td&gt;
&lt;td&gt;0.895&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;45.3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TabPFN-2 (open weights, what ships)&lt;/td&gt;
&lt;td&gt;0.956&lt;/td&gt;
&lt;td&gt;0.987&lt;/td&gt;
&lt;td&gt;0.885&lt;/td&gt;
&lt;td&gt;45.1&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The first row is the finding.&lt;/strong&gt; "Archive anything untouched for ninety days", which is what I would have written by hand in an afternoon, scores &lt;em&gt;worse than a coin flip&lt;/em&gt;. Ninety days idle is exactly what a file looks like in the week before a deadline drags it back. The model is not beating a strawman. It is beating the heuristic that motivated the product, and that heuristic was mine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The second finding is less comfortable, so it is in here.&lt;/strong&gt; I benchmarked the models as the labelled corpus shrinks, expecting the open-weight model to take over at small sizes. It does not:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;labelled rows&lt;/th&gt;
&lt;th&gt;TabPFN&lt;/th&gt;
&lt;th&gt;hist gb&lt;/th&gt;
&lt;th&gt;random forest&lt;/th&gt;
&lt;th&gt;logistic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;0.934&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.936&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.883&lt;/td&gt;
&lt;td&gt;0.654&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;240&lt;/td&gt;
&lt;td&gt;0.944&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.961&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.906&lt;/td&gt;
&lt;td&gt;0.716&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;480&lt;/td&gt;
&lt;td&gt;0.943&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.952&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.885&lt;/td&gt;
&lt;td&gt;0.935&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;960&lt;/td&gt;
&lt;td&gt;0.943&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.956&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.885&lt;/td&gt;
&lt;td&gt;0.775&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,920&lt;/td&gt;
&lt;td&gt;0.947&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.953&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.902&lt;/td&gt;
&lt;td&gt;0.801&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;HistGradientBoosting wins at every corpus size on my machine. TabPFN still ships as the default for reasons that are not the last decimal: no training run, no feature engineering loop, no hyperparameters, 444 MB of RAM, and changing the question from 30 days to 90 is a constant and a re-run rather than a re-fit. The baselines stay in the scoreboard precisely so that claim can be checked, and this table is what happened when I checked it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What went wrong, because that is the useful part
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An orientation error worth 0.6 AUC.&lt;/strong&gt; My first benchmark reported TabPFN at 0.33, which I briefly believed about my own model. The model predicts &lt;em&gt;will reopen&lt;/em&gt;; the product decides &lt;em&gt;is dormant&lt;/em&gt;; I had scored the complement as if it were the class.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A threshold that was not a decision.&lt;/strong&gt; With 91% of rows dormant, a threshold of 0.03 "meets 95% precision" by flagging everything. That is a description of the majority class, not a model. There is now a test that refuses any operating point below 0.5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A stale index.&lt;/strong&gt; Rows from an earlier scan were never removed, so file types I had excluded kept appearing in the list. A full scan now prunes what it did not see, but only when the walk completed, so a capped scan cannot delete the half it never looked at.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo files on the stop list.&lt;/strong&gt; Files found through Spotlight were labelled personal even inside a checkout, which is how a vendored asset ended up ranked first. Directory context is now derived while walking, and for index-only files, from the path.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;There is no upload path.&lt;/strong&gt; The training set is my Spotlight database: every date I opened every file on this machine. A closed API cannot have that, not because of a policy I would object to, but because the product would have to ship my filesystem's behavioural history to someone else's server in order to do something that takes 444 MB of RAM locally. The privacy argument here is not a promise. It is an absence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Per-user adaptation costs nothing and happens every run.&lt;/strong&gt; The model is fitted to &lt;em&gt;this&lt;/em&gt; machine's habits each time, in 0.3 seconds, because in-context inference is just putting the rows in the prompt. A hosted model would need my history on its infrastructure. A fine-tuned model would need a GPU and a training run. Neither is what a personal utility should ask for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It fits the laptop that has to run it.&lt;/strong&gt; This is an 8 GB M1 with about 65 GB free, which is the constraint the whole project lives inside. TabPFN-2's checkpoint is 28 MB and peaks at 444 MB of RSS. I tested the recommended TabPFN-3.5 first: its fast checkpoint is 334 MB, the full model 876 MB, and the package puts a licence-acceptance wall plus an account in front of it. So 3.5 is wired in behind one environment variable, &lt;code&gt;DORMANT_TABPFN_MODEL=3.5-fast&lt;/code&gt;, and is not the default. A product about doing nothing should not require a signup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost to run is zero, permanently.&lt;/strong&gt; 2,500 predictions in about 10 seconds on CPU. No meter. I can run it nightly for three years and it will never become a bill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swapping the model is a config change, not a rewrite.&lt;/strong&gt; &lt;code&gt;dormant/model.py&lt;/code&gt; treats the predictor as a provider, and the baselines sit in the same scoreboard on purpose, so the open-weight claim stays falsifiable rather than decorative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where open beat closed in practice:&lt;/strong&gt; the moment I changed what "dormant" means, from 30 days to 90, the whole thing stayed mine. That is a horizon constant and a re-run. With a hosted model I would be re-deciding what I was willing to upload every time I changed my mind.&lt;/p&gt;

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

&lt;p&gt;The engine, the dashboard and this post were built in one long agent session against a live index of my own machine, which is the fastest way I have found to check a claim: every number in this post came from a terminal, not from a paragraph I wrote first.&lt;/p&gt;

&lt;p&gt;Two moments were worth the whole session.&lt;/p&gt;

&lt;p&gt;The first was the go/no-go test before any architecture existed. Install TabPFN, load the smallest checkpoint, predict three thousand rows, watch peak RSS. Ninety seconds later I had the answer: 444 MB, fits, continue. If it had needed 4 GB there would have been no project, and I would have known in five minutes rather than five evenings.&lt;/p&gt;

&lt;p&gt;The second was the orientation bug, which only surfaced because the baselines were already in the scoreboard. A model that reports 0.33 AUC next to a logistic regression at 0.82 is telling you something about your code, not about your model. Without the boring baseline sitting in the same table, I would have shipped it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(DevRelay session embed goes here.)&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I ran it on my own machine, so these are my numbers, not a projection of them.&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;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Files identified as never coming back&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;519&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Space they hold&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;71.0 GB, of which 68.2 GB is one folder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Decisions I made instead of four hundred&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;one, plus a preview of six files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wrong calls, measured on a 1,800-row holdout&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Full scan of 88,250 files&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0 and zero API calls, permanently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Recovery if it is wrong&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;undo&lt;/code&gt;, or Finder's Put Back, for anything but a typed DELETE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The honest part: only 283 of my 669 personal documents carry any recorded open history at all. The other two thirds are scored from age, size, type and folder alone, which is why the product is named after an animal that is in no hurry. Every night it runs, it converts more of that population from unknown to observed, and the cold start stops being a cold start. The disk projection is the same story: it needs two distinct days of snapshots before it will give you a date, and on a first run it says "no measurable fill rate" instead of inventing one.&lt;/p&gt;

&lt;p&gt;I have not deleted anything yet. That is deliberate: the list is 519 files, I have previewed six of them, and the folder holding most of the weight is one I am ready to let go of. Staging it tonight, &lt;code&gt;undo&lt;/code&gt; if I change my mind.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Best Use of TabPFN.&lt;/strong&gt; TabPFN is the product, not a dependency. The open-weight tabular foundation model is the thing that decides whether 71 GB of my disk is a library or a landfill. It runs locally on CPU in 444 MB of RAM from a 28 MB checkpoint, it is re-fitted to this machine's habits on every run with no training step, and it is benchmarked against logistic regression, a random forest, HistGradientBoosting and the naive 90-day rule on a leak-free, time-split holdout of my own file history. The recommended TabPFN-3.5 is supported behind one environment variable and documented, with the reason it is not the default stated plainly: 334 MB of weights and an account wall on an 8 GB laptop defeats the point.&lt;/p&gt;




&lt;p&gt;Thanks for reading. If you want to run it against your own disk, the five commands are above, and &lt;code&gt;python cli.py bench&lt;/code&gt; will tell you whether these numbers reproduce on your machine. They may not, and that is the interesting part: the model is fitted to whatever history your Mac happens to have kept, so the report is yours.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>A 1B model isn't smart enough to read a contract. So I never asked it to.</title>
      <dc:creator>Soumwadeep Guha</dc:creator>
      <pubDate>Wed, 14 Oct 2026 06:03:32 +0000</pubDate>
      <link>https://dev.to/soumwadeep/a-1b-model-isnt-smart-enough-to-read-a-contract-so-i-never-asked-it-to-1j54</link>
      <guid>https://dev.to/soumwadeep/a-1b-model-isnt-smart-enough-to-read-a-contract-so-i-never-asked-it-to-1j54</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — RedPen is an offline contract reviewer for freelancers. 65 open rules decide what is dangerous; a local Gemma 3 1B model only rewrites that into language you can send. Nothing uploads, nothing costs per review, and $19 once is a survivable price &lt;em&gt;because&lt;/em&gt; the model runs on the user's own laptop.&lt;/p&gt;

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

&lt;p&gt;A developer who just received a nine-page MSA has three options: sign it unread, pay a lawyer $200–400 an hour, or spend an evening googling "is pay-when-paid enforceable".&lt;/p&gt;

&lt;p&gt;RedPen is the fourth option. Drop in an agreement — PDF, DOCX, or pasted from an email — and it returns the clauses that will cost you money or time, &lt;strong&gt;quotes the exact words that triggered each one&lt;/strong&gt;, gives you replacement wording, and drafts the negotiation email. It runs entirely on your laptop: open weights, open rules, no account, no API key, no upload.&lt;/p&gt;

&lt;p&gt;The buyer is any independent who signs things. The pitch is one sentence: &lt;em&gt;your client's NDA never leaves your machine, because it never goes anywhere.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Demo — the whole review, from drop to drafted email.&lt;/strong&gt; Captured headlessly at&lt;br&gt;
progressive points while Gemma streamed over loopback: the 36 findings land first&lt;br&gt;
(the rule pass is ~20 ms), then the brief, then the explanations, then the email.&lt;br&gt;
Reproducible with &lt;code&gt;python3 scripts/build_demo.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3v6cryd11w1v1mj2c7nq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3v6cryd11w1v1mj2c7nq.gif" alt="RedPen demo" width="600" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full-resolution MP4: &lt;a href="https://raw.githubusercontent.com/soumwadeep/RedPen/main/assets/demo.mp4" rel="noopener noreferrer"&gt;assets/demo.mp4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A deliberately hostile agency MSA — 2 pages, 687 words:&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%2Fbtx5eoqf42x5xi8nv6a8.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%2Fbtx5eoqf42x5xi8nv6a8.png" alt="Verdict" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;36 findings&lt;/strong&gt;, nine of them STOP. The strip under the gauge isn't the model guessing — it's the numbers the contract actually states, pulled out with regex: Net 90, no deposit, 7-day notice, unlimited revisions, Delaware.&lt;/p&gt;

&lt;p&gt;Every finding cites its source, so you can check the tool's work against the page:&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%2Fm7blq9092yelm17i5gac.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%2Fm7blq9092yelm17i5gac.png" alt="Evidence" width="534" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then the local model writes the email you'd actually send:&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%2F3fy16msgrk13kovm9z7w.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%2F3fy16msgrk13kovm9z7w.png" alt="Email" width="799" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the result that matters most — a genuinely fair contractor agreement, which comes back empty:&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%2Fo440qvmlinbhq9ee0xqi.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%2Fo440qvmlinbhq9ee0xqi.png" alt="Clean" width="800" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A tool that cries wolf gets uninstalled the first time it wastes an evening on a good contract.&lt;/p&gt;

&lt;p&gt;And an internship offer letter, where the header reads &lt;code&gt;DOC OFFER LETTER OR EMPLOYMENT TERMS&lt;/code&gt;&lt;br&gt;
and the amber panel counts fields nobody has filled in. Different document, different rules:&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%2Fk551ogurt7hic7rgsloi.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%2Fk551ogurt7hic7rgsloi.png" alt="Offer letter" width="800" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The top STOP finding on that page is &lt;em&gt;"The start date is before the letter itself"&lt;/em&gt; — a date&lt;br&gt;
anomaly no keyword rule could catch — and below it, that the employer holds the intern's&lt;br&gt;
original degree certificates.&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/soumwadeep/RedPen.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;RedPen
brew &lt;span class="nb"&gt;install &lt;/span&gt;llama.cpp &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
redpen                       &lt;span class="c"&gt;# opens http://127.0.0.1:8790&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/soumwadeep/RedPen" rel="noopener noreferrer"&gt;github.com/soumwadeep/RedPen&lt;/a&gt;&lt;/strong&gt; — MIT, 4,092 lines of app code and 2,200 lines of tests, 65 rules, 191 tests, no compiled bindings to break on install.&lt;/p&gt;

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

&lt;p&gt;One decision drives everything: &lt;strong&gt;the model never decides what is dangerous.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1 — 65 open rules, no model.&lt;/strong&gt; Plain Python in &lt;code&gt;redpen/rules/&lt;/code&gt;, in three libraries: freelance agreements, offer letters and internships, NDAs. Each rule carries its own explanation, a counter-clause you can paste, and the sentence to say in the email. PyMuPDF extracts the text, segmentation recovers clause numbering and keeps a page number and character span for every clause, and every finding quotes verbatim words.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2 — Gemma 3 1B via llama.cpp, language only.&lt;/strong&gt; It reads what layer 1 already found and rewrites it for &lt;em&gt;this&lt;/em&gt; contract: a three-line brief, a per-finding explanation, the negotiation email, and one pass at vagueness patterns can't see.&lt;/p&gt;

&lt;p&gt;That split isn't modesty about small models. A 1B model is not reliable enough to judge a clause, and a rules engine is not good enough to write a persuasive email to a client. Each layer does the half it is actually competent at — and the report is complete with the model switched off entirely.&lt;/p&gt;

&lt;p&gt;It runs on an &lt;strong&gt;8 GB Apple Silicon MacBook&lt;/strong&gt;, no GPU, no Docker: 769 MB of weights, 2.3 s to load, 0.83 GB resident. The rule pass takes 12–28 ms; a full review with the model layer, 11–17 s. Findings render instantly and the model's work streams in over SSE, so nothing blocks on a small model composing an email.&lt;/p&gt;

&lt;h3&gt;
  
  
  Then I fed it my own paperwork
&lt;/h3&gt;

&lt;p&gt;Everything above was built against synthetic contracts I wrote myself. Then I ran it on six real documents — two internship letters, an offer letter with an NDA, an onboarding checklist, a freelance agreement — and it failed in ways my own samples could not have produced.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What it got wrong&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Silently discarded page 1&lt;/strong&gt; of an offer letter&lt;/td&gt;
&lt;td&gt;Segmentation only emitted text &lt;em&gt;after&lt;/em&gt; the first numbered clause. In real offer letters page 1 is unnumbered prose — so the unpaid training period and the 6-day, 11am–8pm schedule were never analysed. It scored a document whose worst terms it had thrown away.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Told an intern they had no deposit clause&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Freelance rules ran on employment terms: no deposit, no late-payment interest, no right to suspend. True, worthless — and printed directly above the real finding, which was that the employer was &lt;strong&gt;holding their original degree certificates&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Missed impossible dates&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One internship was offered on 29/06/2023 for a term that started 3-Jul-2022 and ended 28-Apr-2023 — finished before the offer was written. No keyword rule can see that, so dates are now parsed in six formats and cross-checked.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Missed disguised perpetuity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An NDA ended its obligations "until all Confidential Information becomes publicly known" — never. A search for `perpetual\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flagged sane drafting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"The Freelancer will not incur new expenses without approval" fired the expense-denial rule, because an unanchored {% raw %}&lt;code&gt;no&lt;/code&gt; matched inside &lt;code&gt;not&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read blanks as hostility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[city, state] will have exclusive jurisdiction&lt;/code&gt; scored at full severity. Unfilled fields are now counted, shown as their own panel, and any finding triggered by a blank is demoted — an unfinished draft is not a decision being made against you.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Six real documents, six bugs. That's the loop this architecture exists for: when it misjudges a document type, the fix is a rule, not a retraining run or a support ticket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guard-rails, all learned from the model failing
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Failure&lt;/th&gt;
&lt;th&gt;Guard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cites a clause that doesn't exist&lt;/td&gt;
&lt;td&gt;Resolved against real clauses, else dropped. It often answers with the vague &lt;em&gt;word&lt;/em&gt; it spotted instead of a number, so that's resolved too — but only when the word appears in exactly one clause.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drops three of your six asks&lt;/td&gt;
&lt;td&gt;Coverage checked against the wording you were told to request. Format is not checked: my first validator rejected a perfectly good bulleted email for not being numbered.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signs your email "Max"&lt;/td&gt;
&lt;td&gt;Stripped and replaced with &lt;code&gt;[your name]&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claims to be a model it isn't&lt;/td&gt;
&lt;td&gt;When I swapped weights to test model-independence, the UI still said "gemma" while Qwen had written it. The label was hard-coded; now it reads from the model that ran.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Returns junk, or no engine is running&lt;/td&gt;
&lt;td&gt;Every role has a deterministic fallback, so the report is always complete.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;Four things a closed API structurally cannot offer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The client's NDA never leaves the laptop.&lt;/strong&gt; A freelancer's most sensitive document is the one describing work for the client who is &lt;em&gt;already&lt;/em&gt; paying them. "We promise to delete it in 30 days" is not the same as "it was never transmitted." This is enforced in code, not policy: the HTTP client raises if a base URL isn't loopback, so a stray environment variable cannot turn a privacy tool into an uploader — there's a test for that. Uploads are parsed from bytes and never written to disk; the last eight reviews live in a bounded in-memory cache; the UI and exported brief contain no remote &lt;code&gt;src&lt;/code&gt; or &lt;code&gt;href&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;scripts/offline_proof.sh&lt;/code&gt; runs a full review while sampling every socket the process holds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;· sockets observed during the run:
    19876 127.0.0.1:52704-&amp;gt;127.0.0.1:8777
    7599  127.0.0.1:8777-&amp;gt;127.0.0.1:52704
✓ PASS -- every socket was loopback. Review score 99/99, no request left the machine.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first version of that script passed by observing &lt;em&gt;nothing&lt;/em&gt;, because I built the PID list with literal parentheses and &lt;code&gt;lsof&lt;/code&gt; never got a valid argument. A proof that looks at nothing proves nothing, so it now prints what it saw.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Zero marginal cost is what makes a one-time price survivable.&lt;/strong&gt; I looked at hosting. A box big enough for the weights runs about $25/month for 2–5 tokens/second on shared CPU — slower than the user's own laptop, with every contract landing on a server they don't control. Worst of both. Locally, user #500 costs nothing extra, which is what lets this be $19 once instead of a subscription defending a per-seat API bill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The rules are editable, which is the actual moat.&lt;/strong&gt; If you edit video, "perpetual, all-media, universe-wide usage rights" is a red flag you know and no general API reliably flags. You add it as JSON in &lt;code&gt;~/.redpen/rules/&lt;/code&gt; — no code, no approval:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"all-media-perpetual-usage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usage rights are unlimited"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ip"&lt;/span&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"why"&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 perpetual all-media licence is a different price than a 12-month single-platform run."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usage is limited to one platform for 12 months; further usage is priced per the rate card."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Which platforms, and for how long? That changes the fee."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"any_of"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"all media"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"any media now known or hereafter devised"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"perpetual licen"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"all_of"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="s2"&gt;"usage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"licen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rights"&lt;/span&gt;&lt;span class="p"&gt;]]&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;With a closed model you cannot see the standard being applied, and you cannot change it. Here a lawyer could audit all 65 rules in an afternoon, and a community can maintain its own fork for its own trade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Swapping models is a config line, so nobody's pricing page is my cost base.&lt;/strong&gt; Verified: the same contract under Gemma 3 1B and Qwen 2.5 1.5B produced &lt;strong&gt;identical findings&lt;/strong&gt; — same rules, same pages, same evidence — only the brief and the email changed. That's the payoff of keeping judgement out of the model: choosing weights becomes a wording preference, not a correctness risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where open beat closed, specifically:&lt;/strong&gt; a hosted API would have been better at prose and worse at the product. It cannot promise the document never left the machine, cannot let a user encode their own trade's traps, makes per-review cost non-zero, and its judgement is unauditable. The thing it was better at — writing — is the half I deliberately gave away.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results, including the ones that hurt
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Document&lt;/th&gt;
&lt;th&gt;Type detected&lt;/th&gt;
&lt;th&gt;Findings&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hostile agency MSA (synthetic)&lt;/td&gt;
&lt;td&gt;services&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical design gig (synthetic)&lt;/td&gt;
&lt;td&gt;services&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;83&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fair contractor deal (synthetic)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;services&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internship offer letter (synthetic)&lt;/td&gt;
&lt;td&gt;employment&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;97&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One-way NDA (synthetic)&lt;/td&gt;
&lt;td&gt;nda&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real offer letter (Skolar)&lt;/td&gt;
&lt;td&gt;employment&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real internship letter (Pentonix)&lt;/td&gt;
&lt;td&gt;employment&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real offer letter (Eubrics)&lt;/td&gt;
&lt;td&gt;employment&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;85&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real NDA (Eubrics)&lt;/td&gt;
&lt;td&gt;nda&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real onboarding checklist&lt;/td&gt;
&lt;td&gt;&lt;em&gt;not an agreement&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;refused&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real freelance template&lt;/td&gt;
&lt;td&gt;services&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Five synthetic fixtures, six real documents. The fair contract scoring zero and the&lt;br&gt;
checklist being refused are the two rows I would defend hardest: an instruction list&lt;br&gt;
makes no promises, and scoring it would have manufactured findings out of prose.&lt;/p&gt;

&lt;h3&gt;
  
  
  What two comments on this post changed
&lt;/h3&gt;

&lt;p&gt;I published before this was as tested as it should have been, and two comments&lt;br&gt;
in the first day were more useful than anything I had written myself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/arhancanli"&gt;@arhancanli&lt;/a&gt;&lt;/strong&gt; pointed out that my six real documents had quietly become my&lt;br&gt;
training set — every fix was written to make a document I had already opened come&lt;br&gt;
out right — and suggested minimal pairs: the same clause asserted and refused, to&lt;br&gt;
see which rules actually survive negation. That test is now&lt;br&gt;
&lt;code&gt;tests/test_negation_pairs.py&lt;/code&gt;, 30 pairs, and &lt;strong&gt;it found five over-flag bugs the&lt;br&gt;
first time it ran.&lt;/strong&gt; The best one: the negation look-back window was 52&lt;br&gt;
characters, so in "Nothing in this Agreement shall make the Contractor's&lt;br&gt;
liability unlimited" it scanned "othing", found no negator, and flagged a clause&lt;br&gt;
that refuses the very thing it is being accused of. Fixing it properly meant&lt;br&gt;
abandoning character windows altogether and cutting at clause boundaries —&lt;br&gt;
punctuation and conjunctions — because "Nothing shall &lt;em&gt;limit&lt;/em&gt; liability, which is&lt;br&gt;
unlimited" contains a negator that governs the wrong verb.&lt;/p&gt;

&lt;p&gt;They also noted that &lt;code&gt;lsof&lt;/code&gt; sampling can miss a connection that opens and closes&lt;br&gt;
between samples, which is true, and that my fair-contract result was one data&lt;br&gt;
point. Both are now addressed: &lt;code&gt;tests/test_offline_enforcement.py&lt;/code&gt; intercepts&lt;br&gt;
&lt;code&gt;socket.connect&lt;/code&gt; for the duration of a whole review and raises on any non-loopback&lt;br&gt;
target, so the property is enforced rather than observed, and&lt;br&gt;
&lt;code&gt;tests/test_precision_variants.py&lt;/code&gt; holds eight fair drafts across five&lt;br&gt;
jurisdictions, seven of them paired with a near-miss where one hostile clause is appended.&lt;/p&gt;

&lt;p&gt;That second file immediately found four more gaps, all in the &lt;em&gt;absence&lt;/em&gt; detectors:&lt;br&gt;
a liability cap written as "is limited to the fees paid" was not recognised as a&lt;br&gt;
cap, a deposit "payable on signature" was not recognised as a deposit, a&lt;br&gt;
translation memory retained by the translator was not recognised as a tooling&lt;br&gt;
carve-out, and a normal five-day week was being flagged as employee-style&lt;br&gt;
control. Writing more good contracts turned out to be a better test than writing&lt;br&gt;
more bad ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/phaz"&gt;@phaz&lt;/a&gt;&lt;/strong&gt; described the same failure in their own cold-email checker — a&lt;br&gt;
small model inventing an opt-out that was not there — which is exactly why every&lt;br&gt;
quote in RedPen must appear verbatim in the source document, asserted by a test&lt;br&gt;
that walks every finding and checks the string exists in the text. Their question,&lt;br&gt;
"do you run the rules against fair contracts to count false alarms, or mostly&lt;br&gt;
against hostile ones?", had an uncomfortable answer when I wrote it down: mostly&lt;br&gt;
hostile, and one fair file. It now has eight, plus a control case proving a clean&lt;br&gt;
result is not just the rules being asleep.&lt;/p&gt;

&lt;p&gt;One thing I did not do: quietly delete the cases the new tests could not pass.&lt;br&gt;
Four limitations are now encoded as tests that &lt;strong&gt;fail if someone fixes them&lt;br&gt;
without updating the list&lt;/strong&gt; — statutory carve-outs read as unlimited liability,&lt;br&gt;
legally mandated insurance, a negator two promises earlier in the same&lt;br&gt;
comma-joined sentence, and the "nothing shall limit liability, which is&lt;br&gt;
unlimited" construction above. A limitation you can see is worth more than one I&lt;br&gt;
have quietly tuned away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limits, honestly.&lt;/strong&gt; 8 GB RAM is the floor — 1–3B at Q4 fit, 7B doesn't. Scanned PDFs aren't supported: no selectable text, and RedPen won't send your pages to an OCR service, so it says so rather than returning an empty review. The model layer is a 1B model and its explanations are sometimes generic, which is why the library's own wording sits underneath it. A clean report is weak evidence — no rule matched is not a guarantee of fairness, and the UI says that out loud instead of letting a green gauge imply safety. And the library is written from a freelancer's and an intern's point of view: it flags commercial risk patterns, not legal validity, across jurisdictions it does not claim to know.&lt;/p&gt;

&lt;p&gt;RedPen is a pattern-matching tool with an open rule library, not a lawyer.&lt;/p&gt;

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

&lt;p&gt;Built agent-assisted — the agent did the typing, I owned the claims. The work log is committed at &lt;strong&gt;&lt;a href="https://github.com/soumwadeep/RedPen/blob/main/docs/agent-session.md" rel="noopener noreferrer"&gt;docs/agent-session.md&lt;/a&gt;&lt;/strong&gt;: every milestone mapped to a commit, and every mistake listed with the test that caught it.&lt;/p&gt;

&lt;p&gt;Two things that log is honest about which a summary wouldn't be. The first architecture sketch assumed a hosted web version, and the cost and privacy math above is what killed it. And most of the bugs in the failure table were &lt;em&gt;introduced by the agent during this session&lt;/em&gt; and caught by tests written in the same session — including a validation script that passed by observing nothing.&lt;/p&gt;

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

&lt;p&gt;Shreshtha Das, a freelance developer who tests tools like this, ran RedPen on a real agreement. His feedback, verbatim:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a freelance tester, I tested &lt;strong&gt;RedPen&lt;/strong&gt; and found it to be a genuinely useful tool for freelancers who want to understand their contracts before signing them. I tried reviewing an agreement and was impressed by how clearly it highlighted potentially risky clauses, quoted the exact wording that needed attention, and suggested more freelancer-friendly alternatives. The negotiation email draft was another helpful feature, as it made it easier to communicate concerns professionally without spending hours figuring out what to say. I especially liked that RedPen works entirely offline, which is a major advantage when dealing with confidential client agreements and NDAs. Overall, RedPen makes contract review more accessible, saves valuable time, and gives freelancers more confidence when negotiating terms with clients. It's a practical tool that I can see myself recommending to other developers, designers, and independent professionals.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'd rather keep two things in view than round them off. He reviewed one agreement, so this is a single data point, not validation — and the one thing I most wanted from him, &lt;strong&gt;a false positive&lt;/strong&gt;, is the thing he didn't report. Precision is the claim this tool can least afford to get wrong, and it's the reason the fair-contract test exists.&lt;/p&gt;

&lt;p&gt;What he did confirm is the part enforced in code rather than promised in a README: that the offline behaviour holds, and that it matters most exactly where he says it would — client agreements and NDAs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did he pay?&lt;/strong&gt; Yes — ₹89, which is more than ₹0 and less than the $19 I'm asking. The honest read is that a friend paid something to be supportive, not that a stranger paid a price. The next test is someone with no reason to be kind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A second voice — from someone who read the project, not someone who used it.&lt;/strong&gt; The founding team of &lt;a href="https://actizant.com/" rel="noopener noreferrer"&gt;Actizant&lt;/a&gt;, which builds what they call intelligent operating systems for rural India, wrote this after reviewing the repo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Privacy should be a fundamental design principle, not an afterthought, especially when dealing with confidential client agreements, statements of work, and NDAs."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They also handed me a roadmap in three lines, which is more useful than praise: &lt;strong&gt;customisable risk rules per profession&lt;/strong&gt;, &lt;strong&gt;jurisdiction-aware guidance&lt;/strong&gt;, and &lt;strong&gt;transparent statements of what automated analysis cannot do&lt;/strong&gt;. The first two are exactly what an open rule library is built for — a profession-specific rule set is a JSON file, and a jurisdiction profile is a second rule set with different safe-harbours. The third is why the UI says "no rule matched is not a guarantee of fairness" instead of showing a green tick.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Best Use of Gemma.&lt;/strong&gt; Gemma 3 1B (instruct) is the default and only shipped model — &lt;code&gt;ggml-org/gemma-3-1b-it-GGUF&lt;/code&gt;, Q4_K_M, downloaded on first run and served by llama.cpp on loopback. It writes the brief, the per-finding explanations, the negotiation email and the ambiguity pass. It is the model small enough to fit in 8 GB of RAM and cost nothing per review, which is the precondition for the privacy promise being true rather than a policy.&lt;/p&gt;




&lt;p&gt;MIT licensed. Model weights stay under their own licences — RedPen ships none, it downloads them for you.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>privacy</category>
    </item>
    <item>
      <title>🌱 I Built an AI That Wants You to Stop Using It — Meet TerraLens</title>
      <dc:creator>Soumwadeep Guha</dc:creator>
      <pubDate>Tue, 06 Oct 2026 15:28:48 +0000</pubDate>
      <link>https://dev.to/soumwadeep/i-built-an-ai-that-wants-you-to-stop-using-it-meet-terralens-cln</link>
      <guid>https://dev.to/soumwadeep/i-built-an-ai-that-wants-you-to-stop-using-it-meet-terralens-cln</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  🌱 I Built an AI That Wants You to Stop Using It — Meet TerraLens
&lt;/h1&gt;

&lt;p&gt;We are putting increasingly powerful AI into our pockets.&lt;/p&gt;

&lt;p&gt;And then spending increasingly more time staring at those pockets.&lt;/p&gt;

&lt;p&gt;Every app seems to want the same thing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;one more click, one more message, one more minute of attention.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So while thinking about the &lt;strong&gt;"Touch Grass"&lt;/strong&gt; theme, I started with a slightly ridiculous question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What if the best possible outcome for an AI app was that you stopped using it?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not because it failed.&lt;/p&gt;

&lt;p&gt;Because it succeeded.&lt;/p&gt;

&lt;p&gt;That question became &lt;strong&gt;TerraLens&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  TerraLens — AI that sends you outside.
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;TerraLens is an &lt;strong&gt;offline-first, open-weight AI field companion&lt;/strong&gt; designed to help you notice more of the physical world while spending less time looking at a screen.&lt;/p&gt;

&lt;p&gt;It gives you small real-world missions.&lt;/p&gt;

&lt;p&gt;You put your phone away.&lt;/p&gt;

&lt;p&gt;You walk.&lt;/p&gt;

&lt;p&gt;You look.&lt;/p&gt;

&lt;p&gt;You listen.&lt;/p&gt;

&lt;p&gt;You discover something.&lt;/p&gt;

&lt;p&gt;Then, and only then, you come back.&lt;/p&gt;




&lt;h1&gt;
  
  
  ## What I Built
&lt;/h1&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%2F09qvp0vlaon5rv69sg0o.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%2F09qvp0vlaon5rv69sg0o.png" alt="TerraLens" width="575" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TerraLens turns an ordinary walk into an &lt;strong&gt;AI-guided expedition&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But I deliberately didn't build another chatbot.&lt;/p&gt;

&lt;p&gt;There is no giant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What would you like to ask?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;box at the centre of the experience.&lt;/p&gt;

&lt;p&gt;Instead, TerraLens asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ready to go outside?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You choose an expedition style and duration.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌿 Nature&lt;/li&gt;
&lt;li&gt;📷 Photographer&lt;/li&gt;
&lt;li&gt;🧭 Explorer&lt;/li&gt;
&lt;li&gt;🎲 Surprise Me&lt;/li&gt;
&lt;li&gt;😌 Chill&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then TerraLens gives you &lt;strong&gt;one real-world mission at a time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Find two leaves with visibly different edges.
&lt;/h3&gt;

&lt;p&gt;Don't photograph the first thing you see.&lt;/p&gt;

&lt;p&gt;Look around.&lt;/p&gt;

&lt;p&gt;Compare.&lt;/p&gt;

&lt;p&gt;Come back when you've found them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then you press:&lt;/p&gt;

&lt;h1&gt;
  
  
  GO FIND IT
&lt;/h1&gt;

&lt;p&gt;That's when something unusual happens.&lt;/p&gt;

&lt;p&gt;The application basically tells you to stop using the application.&lt;/p&gt;




&lt;h1&gt;
  
  
  📱 → 🌳 The TerraLens Loop
&lt;/h1&gt;

&lt;p&gt;The whole product revolves around one simple loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Get a mission
      ↓
Put the phone away
      ↓
Explore the real world
      ↓
Notice something
      ↓
Capture an observation
      ↓
AI understands the context
      ↓
Get another physical-world action
      ↓
Put the phone away again
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last part matters.&lt;/p&gt;

&lt;p&gt;The goal isn't:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI → answer → another question → answer → another question&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI → action → world → discovery&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  🌱 Touch Grass Mode
&lt;/h1&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%2Fqigwlumz0n9y11czbsx0.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%2Fqigwlumz0n9y11czbsx0.png" alt="Pocket Mode" width="575" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I built a dedicated &lt;strong&gt;Touch Grass / Pocket Mode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you begin a mission, TerraLens intentionally removes most of the interface.&lt;/p&gt;

&lt;p&gt;You might see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;YOUR MISSION

Find two leaves with
visibly different edges.

04:58 remaining


PUT YOUR PHONE AWAY 🌱
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's basically it.&lt;/p&gt;

&lt;p&gt;No infinite feed.&lt;/p&gt;

&lt;p&gt;No notifications asking you to come back.&lt;/p&gt;

&lt;p&gt;No AI typing animation trying to hold your attention.&lt;/p&gt;

&lt;p&gt;The mission is outside.&lt;/p&gt;

&lt;p&gt;TerraLens will still be there when you return.&lt;/p&gt;




&lt;h1&gt;
  
  
  📷 🎙️ ✍️ Bring Back What You Discover
&lt;/h1&gt;

&lt;p&gt;When you find something interesting, TerraLens lets you capture an observation as:&lt;/p&gt;

&lt;h3&gt;
  
  
  📷 A photo
&lt;/h3&gt;

&lt;p&gt;See an interesting plant, leaf, flower, texture or object?&lt;/p&gt;

&lt;p&gt;Capture it.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎙️ A sound
&lt;/h3&gt;

&lt;p&gt;Hear a bird call or an interesting environmental sound?&lt;/p&gt;

&lt;p&gt;Record it.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✍️ A field note
&lt;/h3&gt;

&lt;p&gt;Notice something that doesn't need a camera?&lt;/p&gt;

&lt;p&gt;Write it down.&lt;/p&gt;

&lt;p&gt;Those observations become part of your local nature journal and can be used by the Curiosity Engine to determine what you should investigate next.&lt;/p&gt;




&lt;h1&gt;
  
  
  🧠 The Curiosity Engine
&lt;/h1&gt;

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

&lt;p&gt;Most AI systems are optimized to &lt;strong&gt;answer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;TerraLens is optimized to create &lt;strong&gt;curiosity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose I photograph a flower.&lt;/p&gt;

&lt;p&gt;A traditional assistant might respond with several paragraphs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This appears to be Hibiscus rosa-sinensis. It belongs to the family Malvaceae...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Useful?&lt;/p&gt;

&lt;p&gt;Absolutely.&lt;/p&gt;

&lt;p&gt;But I'm still staring at my phone.&lt;/p&gt;

&lt;p&gt;TerraLens should instead say something closer to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Possible match: Hibiscus&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before I tell you more, look at the newest leaves near the end of the branch.&lt;/p&gt;

&lt;p&gt;Are they the same colour as the older leaves?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go check. I'll wait.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difference is small technically but enormous conceptually.&lt;/p&gt;

&lt;p&gt;One response makes me read.&lt;/p&gt;

&lt;p&gt;The other makes me &lt;strong&gt;look&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And TerraLens keeps trying to turn information into physical actions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LOOK&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LISTEN&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WALK&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;COMPARE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTICE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WAIT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SEARCH&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;REFLECT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The AI isn't supposed to become the experience.&lt;/p&gt;

&lt;p&gt;It's supposed to trigger the experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  🏆 Grass Score — Rewarding the Opposite of Screen Time
&lt;/h1&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%2Fyms36sotoknl5vzjp7ie.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%2Fyms36sotoknl5vzjp7ie.png" alt="Evening Walk Grass Score" width="575" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I ran into another interesting problem.&lt;/p&gt;

&lt;p&gt;How should TerraLens measure success?&lt;/p&gt;

&lt;p&gt;Normal software metrics didn't make sense.&lt;/p&gt;

&lt;p&gt;Time in app?&lt;/p&gt;

&lt;p&gt;Bad.&lt;/p&gt;

&lt;p&gt;More sessions?&lt;/p&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;More clicks?&lt;/p&gt;

&lt;p&gt;Definitely not.&lt;/p&gt;

&lt;p&gt;So I created:&lt;/p&gt;

&lt;h1&gt;
  
  
  🌱 GRASS SCORE
&lt;/h1&gt;

&lt;p&gt;A score from &lt;strong&gt;0 to 1000&lt;/strong&gt; based on exploration behaviour.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GRASS SCORE

847 / 1000

🌱 EXPLORER


Outdoor time          42 min
Screen interaction     4 min
Distance               2.3 km
Observations               11
New discoveries             7
Missions completed          3

Screen Avoidance Bonus   +120
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grass Score is NOT generated by an LLM.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is deterministic.&lt;/p&gt;

&lt;p&gt;Actual expedition events feed a scoring algorithm.&lt;/p&gt;

&lt;p&gt;That means TerraLens can't simply ask AI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Give this person a score."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and magically produce 847.&lt;/p&gt;

&lt;p&gt;The score has a visible breakdown and can be explained.&lt;/p&gt;




&lt;h1&gt;
  
  
  📊 Nature / Screen Ratio
&lt;/h1&gt;

&lt;p&gt;I also wanted one metric that captured the entire philosophy of TerraLens.&lt;/p&gt;

&lt;p&gt;So I added:&lt;/p&gt;

&lt;h1&gt;
  
  
  Nature / Screen Ratio
&lt;/h1&gt;

&lt;p&gt;Suppose you explored for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;42 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;but interacted with TerraLens for only:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your ratio is roughly:&lt;/p&gt;

&lt;h1&gt;
  
  
  10.5×
&lt;/h1&gt;

&lt;p&gt;And in TerraLens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;higher is better.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think about how strange that is for software.&lt;/p&gt;

&lt;p&gt;The product is celebrating the fact that you barely used it.&lt;/p&gt;

&lt;p&gt;That's exactly the point.&lt;/p&gt;




&lt;h1&gt;
  
  
  📴 What Happens When the Internet Disappears?
&lt;/h1&gt;

&lt;p&gt;This was one of the biggest reasons I wanted an open and offline-first architecture.&lt;/p&gt;

&lt;p&gt;Imagine this:&lt;/p&gt;

&lt;p&gt;You're walking along a trail.&lt;/p&gt;

&lt;p&gt;You finally find something interesting.&lt;/p&gt;

&lt;p&gt;You open your "AI nature assistant."&lt;/p&gt;

&lt;p&gt;And it says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Network error.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That felt completely backwards.&lt;/p&gt;

&lt;p&gt;Nature doesn't come with guaranteed Wi-Fi.&lt;/p&gt;

&lt;p&gt;So TerraLens treats offline operation as a normal state rather than a failure state.&lt;/p&gt;

&lt;p&gt;The app can be installed as a &lt;strong&gt;Progressive Web App&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The core expedition experience uses local browser storage.&lt;/p&gt;

&lt;p&gt;Missions, observations, scores and the journal can continue locally.&lt;/p&gt;

&lt;p&gt;When connectivity disappears, the philosophy is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You're offline. Good. Keep exploring.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fx3d77piuss7lfa2i99mm.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%2Fx3d77piuss7lfa2i99mm.png" alt="Offline Mode" width="575" height="1280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And when connectivity returns, queued work can synchronize again.&lt;/p&gt;




&lt;h1&gt;
  
  
  🤖 Why I Chose Gemma
&lt;/h1&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%2Fwrhj1vf9m251d25drrsx.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%2Fwrhj1vf9m251d25drrsx.png" alt="Gemma Model" width="800" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main prize category I'm entering TerraLens for is:&lt;/p&gt;

&lt;h1&gt;
  
  
  🏆 Best Use of Gemma
&lt;/h1&gt;

&lt;p&gt;Gemma isn't here because I needed an AI logo on the architecture diagram.&lt;/p&gt;

&lt;p&gt;It fits the fundamental problem.&lt;/p&gt;

&lt;p&gt;TerraLens needs an intelligence layer that can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;open-weight&lt;/li&gt;
&lt;li&gt;replaceable&lt;/li&gt;
&lt;li&gt;adaptable&lt;/li&gt;
&lt;li&gt;deployable in different environments&lt;/li&gt;
&lt;li&gt;moved closer to the user&lt;/li&gt;
&lt;li&gt;eventually optimized for local inference&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Curiosity Engine therefore has an AI adapter instead of hard-wiring the entire product into one closed provider.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Observation
     ↓
AI Adapter
     ↓
Gemma
     ↓
Structured understanding
     ↓
Curiosity Engine
     ↓
Physical-world action
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gemma helps turn an observation into context that TerraLens can use to produce the next outdoor action.&lt;/p&gt;

&lt;p&gt;And because the model layer is abstracted, TerraLens isn't permanently tied to one inference environment.&lt;/p&gt;

&lt;p&gt;Gemma can be served through compatible runtimes while the rest of the application continues speaking the same structured language.&lt;/p&gt;




&lt;h1&gt;
  
  
  🧠 AI That Is Allowed To Say "I Don't Know"
&lt;/h1&gt;

&lt;p&gt;There was another rule I cared about:&lt;/p&gt;

&lt;h3&gt;
  
  
  Never fake intelligence.
&lt;/h3&gt;

&lt;p&gt;If the model doesn't answer, TerraLens doesn't invent an answer.&lt;/p&gt;

&lt;p&gt;If an integration isn't configured, TerraLens doesn't display a fake green checkmark.&lt;/p&gt;

&lt;p&gt;If an evaluation hasn't run, it doesn't invent benchmark numbers.&lt;/p&gt;

&lt;p&gt;If there isn't enough data for a prediction, it doesn't ask an LLM to manufacture a percentage.&lt;/p&gt;

&lt;p&gt;This sounds obvious.&lt;/p&gt;

&lt;p&gt;But it becomes incredibly important in AI demos.&lt;/p&gt;

&lt;p&gt;TerraLens uses explicit integration states such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;READY

DEGRADED

NOT RUN YET

UNVERIFIED

NOT CONFIGURED

UNREACHABLE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of my rules while building the project became:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Configured ≠ working.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A key existing in an environment variable isn't proof that an integration works.&lt;/p&gt;




&lt;h1&gt;
  
  
  🔬 Fine-Tuning Curiosity with Tinker
&lt;/h1&gt;

&lt;p&gt;Another category TerraLens explores deeply is:&lt;/p&gt;

&lt;h1&gt;
  
  
  🧪 Best Use of Tinker
&lt;/h1&gt;

&lt;p&gt;There's an interesting AI problem hidden inside TerraLens.&lt;/p&gt;

&lt;p&gt;Generic assistants are trained to be helpful by answering.&lt;/p&gt;

&lt;p&gt;But TerraLens sometimes needs to be helpful by &lt;strong&gt;not answering yet&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;h3&gt;
  
  
  Generic response
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;This appears to be a mango tree. Mango trees belong to the family Anacardiaceae...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;versus:&lt;/p&gt;

&lt;h3&gt;
  
  
  TerraLens response
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Looks like a mango tree.&lt;/p&gt;

&lt;p&gt;Find the newest leaves near the end of a branch.&lt;/p&gt;

&lt;p&gt;Are they the same colour as the older ones?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go look before reading anything else.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That behaviour can be adapted.&lt;/p&gt;

&lt;p&gt;So TerraLens includes a dedicated &lt;strong&gt;Curiosity Adapter&lt;/strong&gt; fine-tuning/evaluation workflow.&lt;/p&gt;

&lt;p&gt;The training examples map:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Observation
+
Context
+
Generic response

        ↓

Desired outdoor response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The evaluation isn't simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Does the model sound good?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It looks at things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Outdoor Action Rate&lt;/li&gt;
&lt;li&gt;Screen Dependency Rate&lt;/li&gt;
&lt;li&gt;response length&lt;/li&gt;
&lt;li&gt;safety compliance&lt;/li&gt;
&lt;li&gt;mission relevance&lt;/li&gt;
&lt;li&gt;action diversity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The question becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Can we measurably make an AI better at getting humans away from the AI?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I love the contradiction in that experiment.&lt;/p&gt;




&lt;h1&gt;
  
  
  🎙️ ElevenLabs — Because Voice Means Less Screen
&lt;/h1&gt;

&lt;p&gt;Another natural fit was &lt;strong&gt;ElevenLabs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If TerraLens wants you to stop looking at your screen, making you read every mission isn't ideal either.&lt;/p&gt;

&lt;p&gt;So Pocket Mode supports voice narration.&lt;/p&gt;

&lt;p&gt;Imagine walking with your phone in your pocket and hearing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You've been exploring for eight minutes.&lt;/p&gt;

&lt;p&gt;Stop here.&lt;/p&gt;

&lt;p&gt;Listen carefully for ten seconds.&lt;/p&gt;

&lt;p&gt;Can you hear two different natural sounds?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You don't need to unlock the phone.&lt;/p&gt;

&lt;p&gt;You don't need to scroll.&lt;/p&gt;

&lt;p&gt;You don't even need to look down.&lt;/p&gt;

&lt;p&gt;Voice isn't being added because voice AI is cool.&lt;/p&gt;

&lt;p&gt;It's being added because &lt;strong&gt;audio reduces the amount of visual attention TerraLens needs from you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the external voice service isn't available, TerraLens can fall back to browser speech capabilities.&lt;/p&gt;




&lt;h1&gt;
  
  
  🧭 Mastra — The Field Agent
&lt;/h1&gt;

&lt;p&gt;Individual observations aren't very interesting if the system forgets everything five seconds later.&lt;/p&gt;

&lt;p&gt;TerraLens therefore includes a higher-level &lt;strong&gt;Field Agent&lt;/strong&gt; architecture using Mastra.&lt;/p&gt;

&lt;p&gt;Its responsibilities are separated conceptually into areas such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                FIELD AGENT
                     │
       ┌─────────────┼─────────────┐
       │             │             │
       ▼             ▼             ▼
 Observation      Mission        Safety
    logic          logic          logic
       │             │             │
       └─────────────┼─────────────┘
                     │
                     ▼
                Curiosity
                     │
                     ▼
                  Summary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means an expedition can eventually be understood as a journey rather than a collection of unrelated AI calls.&lt;/p&gt;




&lt;h1&gt;
  
  
  ⏳ Temporal — Because Outdoor Networks Fail
&lt;/h1&gt;

&lt;p&gt;Imagine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start expedition
       ↓
Complete mission
       ↓
Record observation
       ↓
NETWORK DISAPPEARS
       ↓
Walk for 20 minutes
       ↓
Create more observations locally
       ↓
NETWORK RETURNS
       ↓
Synchronize
       ↓
Continue workflow
       ↓
Generate expedition recap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a very different environment from a normal web request.&lt;/p&gt;

&lt;p&gt;So TerraLens uses a durable workflow architecture with &lt;strong&gt;Temporal&lt;/strong&gt; for cloud-side work that should survive failures and process restarts.&lt;/p&gt;

&lt;p&gt;The important idea is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;losing connectivity should pause cloud work, not destroy the expedition.&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  🔮 TabPFN — Predicting When Exploration Might Be Interesting
&lt;/h1&gt;

&lt;p&gt;I also wanted TerraLens to eventually learn from structured outdoor observations.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;TabPFN&lt;/strong&gt; fits.&lt;/p&gt;

&lt;p&gt;Instead of asking an LLM:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What are the chances I'll see birds this evening?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and accepting whatever percentage it invents, structured information can be used.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time
Temperature
Humidity
Season
Recent observations
Environment
Previous activity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXPLORATION FORECAST

Bird activity
HIGH

Insect activity
MEDIUM

Flower observations
HIGH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if there isn't enough information?&lt;/p&gt;

&lt;p&gt;TerraLens should simply say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Not enough data yet.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"No prediction" is better than a fake prediction.&lt;/p&gt;




&lt;h1&gt;
  
  
  🗃️ MongoDB Atlas — Cloud Memory Without Making Cloud Mandatory
&lt;/h1&gt;

&lt;p&gt;TerraLens stores the core expedition experience locally first.&lt;/p&gt;

&lt;p&gt;That's deliberate.&lt;/p&gt;

&lt;p&gt;But synchronized journals and cross-device history are useful too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MongoDB Atlas&lt;/strong&gt; provides the optional server-side observation layer.&lt;/p&gt;

&lt;p&gt;The distinction matters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEVICE

Your current expedition
Your observations
Your score
Your journal

        ↓ optional sync

CLOUD

Backup / synchronized journal
Cross-device information
Agent context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cloud storage enhances the experience.&lt;/p&gt;

&lt;p&gt;It doesn't own the experience.&lt;/p&gt;




&lt;h1&gt;
  
  
  🐯 Tiger Data + pgvector — Nature Knowledge
&lt;/h1&gt;

&lt;p&gt;Personal observations and nature knowledge aren't the same thing.&lt;/p&gt;

&lt;p&gt;So TerraLens keeps those concerns separate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tiger Data / PostgreSQL + pgvector&lt;/strong&gt; provides a retrieval layer for nature knowledge.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Question / observation
        ↓
Embedding
        ↓
Vector similarity
        ↓
Relevant field-guide knowledge
        ↓
Gemma
        ↓
Grounded response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If vector retrieval isn't available, the architecture can fall back toward PostgreSQL text retrieval and ultimately bundled local knowledge.&lt;/p&gt;

&lt;p&gt;Again:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;degrade gracefully instead of simply breaking.&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  🧠 Backboard — Remembering the Explorer
&lt;/h1&gt;

&lt;p&gt;Imagine TerraLens remembers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Last weekend you spent most of your expedition photographing flowers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then next time it can say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Last time you focused on colour.&lt;/p&gt;

&lt;p&gt;Today let's ignore flowers for ten minutes.&lt;/p&gt;

&lt;p&gt;Listen instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's where long-term agent memory becomes interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backboard&lt;/strong&gt; provides the integration path for richer long-term memory, while local memory remains available when the external service isn't configured.&lt;/p&gt;




&lt;h1&gt;
  
  
  🔎 SerpApi — Online Context, Not Online Dependency
&lt;/h1&gt;

&lt;p&gt;Sometimes fresh web information is useful.&lt;/p&gt;

&lt;p&gt;So TerraLens can optionally enrich observations using &lt;strong&gt;SerpApi&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But there's an important distinction in the UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LOCAL / MODEL RESULT

Possible identification:
...

ONLINE CONTEXT

Additional current information:
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SerpApi isn't the identification engine.&lt;/p&gt;

&lt;p&gt;It doesn't secretly turn TerraLens back into a cloud-only search wrapper.&lt;/p&gt;

&lt;p&gt;The Internet &lt;strong&gt;enhances&lt;/strong&gt; TerraLens.&lt;/p&gt;

&lt;p&gt;The Internet doesn't &lt;strong&gt;enable&lt;/strong&gt; TerraLens.&lt;/p&gt;




&lt;h1&gt;
  
  
  🔭 Sentry — Seeing What the AI Actually Did
&lt;/h1&gt;

&lt;p&gt;AI systems become difficult to debug when all you know is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It felt slow."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So TerraLens includes observability designed around actual stages.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FIELD AGENT TRACE

Mission generation       320 ms
Gemma inference          1.8 sec
Safety check             120 ms
Mission update           190 ms
Voice generation         620 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sentry provides the tracing/error path.&lt;/p&gt;

&lt;p&gt;But TerraLens deliberately avoids sending things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;photographs&lt;/li&gt;
&lt;li&gt;private field notes&lt;/li&gt;
&lt;li&gt;precise coordinates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;into telemetry by default.&lt;/p&gt;

&lt;p&gt;Debugging shouldn't quietly become surveillance.&lt;/p&gt;




&lt;h1&gt;
  
  
  🔐 Privacy Isn't a Settings Checkbox
&lt;/h1&gt;

&lt;p&gt;TerraLens supports three conceptual privacy modes:&lt;/p&gt;

&lt;h2&gt;
  
  
  LOCAL ONLY
&lt;/h2&gt;

&lt;p&gt;Keep the experience on the device wherever possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  HYBRID
&lt;/h2&gt;

&lt;p&gt;Local-first processing with selected synchronization.&lt;/p&gt;

&lt;h2&gt;
  
  
  CLOUD ENHANCED
&lt;/h2&gt;

&lt;p&gt;Allow configured online capabilities.&lt;/p&gt;

&lt;p&gt;Precise location isn't required to go exploring.&lt;/p&gt;

&lt;p&gt;Photos are processed with privacy in mind.&lt;/p&gt;

&lt;p&gt;External credentials remain server-side.&lt;/p&gt;

&lt;p&gt;And cloud media processing isn't silently enabled just because an API key exists.&lt;/p&gt;

&lt;p&gt;For a field companion, this matters.&lt;/p&gt;

&lt;p&gt;A personal nature journal should feel personal.&lt;/p&gt;




&lt;h1&gt;
  
  
  🛡️ Safety
&lt;/h1&gt;

&lt;p&gt;There is another problem with letting AI create outdoor missions:&lt;/p&gt;

&lt;p&gt;AI can occasionally suggest stupid things.&lt;/p&gt;

&lt;p&gt;😅&lt;/p&gt;

&lt;p&gt;So generated activities have safety constraints.&lt;/p&gt;

&lt;p&gt;TerraLens should never intentionally ask someone to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eat an unknown plant&lt;/li&gt;
&lt;li&gt;eat an unknown mushroom&lt;/li&gt;
&lt;li&gt;handle wildlife&lt;/li&gt;
&lt;li&gt;approach dangerous animals&lt;/li&gt;
&lt;li&gt;trespass&lt;/li&gt;
&lt;li&gt;climb unsafe structures&lt;/li&gt;
&lt;li&gt;enter dangerous water&lt;/li&gt;
&lt;li&gt;cross unsafe roads&lt;/li&gt;
&lt;li&gt;rely on AI identification for medical or food-safety decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The principle is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Observe. Don't disturb.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Curiosity should make exploration better, not reckless.&lt;/p&gt;




&lt;h1&gt;
  
  
  🧪 Judge Mode &amp;amp; AI Lab
&lt;/h1&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%2Fdqtpm0hmvktfvxaxikq6.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%2Fdqtpm0hmvktfvxaxikq6.png" alt="Judge Mode" width="800" height="786"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also realized something while building this:&lt;/p&gt;

&lt;p&gt;A hackathon judge might have only a few minutes.&lt;/p&gt;

&lt;p&gt;Making them discover the architecture manually would be terrible UX.&lt;/p&gt;

&lt;p&gt;So TerraLens includes a dedicated:&lt;/p&gt;

&lt;h1&gt;
  
  
  Judge Mode
&lt;/h1&gt;

&lt;p&gt;It provides a short technical tour covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the idea&lt;/li&gt;
&lt;li&gt;expeditions&lt;/li&gt;
&lt;li&gt;offline behaviour&lt;/li&gt;
&lt;li&gt;Gemma&lt;/li&gt;
&lt;li&gt;Grass Score&lt;/li&gt;
&lt;li&gt;Curiosity&lt;/li&gt;
&lt;li&gt;architecture&lt;/li&gt;
&lt;li&gt;integration status&lt;/li&gt;
&lt;li&gt;privacy&lt;/li&gt;
&lt;li&gt;open innovation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's also an &lt;strong&gt;AI Lab&lt;/strong&gt; for inspecting things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;model state&lt;/li&gt;
&lt;li&gt;evaluation&lt;/li&gt;
&lt;li&gt;offline capabilities&lt;/li&gt;
&lt;li&gt;observability&lt;/li&gt;
&lt;li&gt;architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted the technical work to be visible instead of hiding everything behind the landing page.&lt;/p&gt;




&lt;h1&gt;
  
  
  🏗️ How I Built It
&lt;/h1&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%2F61ue3m487dx5lla46pq2.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%2F61ue3m487dx5lla46pq2.png" alt="Architecture" width="800" height="859"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application is built as a mobile-first &lt;strong&gt;Next.js + TypeScript Progressive Web App&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At a simplified level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                        TERRALENS
                            │
                   ┌────────▼────────┐
                   │   EXPEDITION    │
                   └────────┬────────┘
                            │
             ┌──────────────┼──────────────┐
             ▼              ▼              ▼
          MISSIONS      OBSERVATIONS     JOURNAL
             │              │
             └──────┬───────┘
                    ▼
             CURIOSITY ENGINE
                    │
            ┌───────┴───────┐
            ▼               ▼
       LOCAL RULES         GEMMA
            │               │
            └───────┬───────┘
                    ▼
              PHYSICAL ACTION
                    │
                    ▼
                POCKET MODE
                    │
                    ▼
               GRASS SCORE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When online, additional infrastructure can participate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    DEVICE
                       │
                       ▼
                  SYNC QUEUE
                       │
                       ▼
                   TEMPORAL
                       │
                       ▼
                MASTRA FIELD AGENT
                       │
        ┌──────────────┼───────────────┐
        ▼              ▼               ▼
     MONGODB        TIGER DATA       TABPFN
                       │
            ┌──────────┼──────────┐
            ▼          ▼          ▼
        BACKBOARD   SERPAPI   ELEVENLABS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And throughout the system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SENTRY → observability

TINKER → model adaptation/evaluation

GEMMA → open-weight intelligence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important thing is that the bottom diagram can disappear temporarily...&lt;/p&gt;

&lt;p&gt;and the user can still go outside.&lt;/p&gt;




&lt;h1&gt;
  
  
  ## Why Does Open Innovation Matter?
&lt;/h1&gt;

&lt;p&gt;This is the question at the heart of the challenge.&lt;/p&gt;

&lt;p&gt;For TerraLens, open innovation matters because of &lt;strong&gt;where the application is supposed to work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not inside a perfect office network.&lt;/p&gt;

&lt;p&gt;Outside.&lt;/p&gt;

&lt;p&gt;On a trail.&lt;/p&gt;

&lt;p&gt;In a park.&lt;/p&gt;

&lt;p&gt;In a garden.&lt;/p&gt;

&lt;p&gt;On a village road.&lt;/p&gt;

&lt;p&gt;Somewhere your connection may disappear completely.&lt;/p&gt;

&lt;p&gt;A cloud-only AI architecture is incredibly powerful until the cloud becomes unreachable.&lt;/p&gt;

&lt;p&gt;Open-weight AI gives us another direction.&lt;/p&gt;

&lt;p&gt;We can move intelligence closer to the user.&lt;/p&gt;

&lt;p&gt;We can change the runtime.&lt;/p&gt;

&lt;p&gt;We can swap models.&lt;/p&gt;

&lt;p&gt;We can inspect the behaviour.&lt;/p&gt;

&lt;p&gt;We can fine-tune the model toward a strange objective like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Stop answering so much and make the human investigate.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And we can design toward a future where more of that intelligence runs directly on the device.&lt;/p&gt;

&lt;p&gt;There is also a privacy benefit.&lt;/p&gt;

&lt;p&gt;A photograph doesn't automatically have to become an upload.&lt;/p&gt;

&lt;p&gt;A field journal doesn't have to begin life on somebody else's server.&lt;/p&gt;

&lt;p&gt;A user's exact location doesn't have to be the admission price for exploring nature.&lt;/p&gt;

&lt;p&gt;And if an API disappears?&lt;/p&gt;

&lt;p&gt;The entire idea doesn't have to disappear with it.&lt;/p&gt;

&lt;p&gt;That's why open AI isn't decoration in TerraLens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The environment TerraLens is designed for is exactly where open and local AI becomes most interesting.&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  ## Demo
&lt;/h1&gt;

&lt;p&gt;🌱 &lt;strong&gt;Live application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://terralens.soumwadeepguha.com/" rel="noopener noreferrer"&gt;https://terralens.soumwadeepguha.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the best experience, open TerraLens on a phone.&lt;/p&gt;

&lt;p&gt;Try this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start an expedition.&lt;/li&gt;
&lt;li&gt;Choose a mission.&lt;/li&gt;
&lt;li&gt;Enter Touch Grass Mode.&lt;/li&gt;
&lt;li&gt;Put the phone away.&lt;/li&gt;
&lt;li&gt;Actually complete the mission.&lt;/li&gt;
&lt;li&gt;Come back.&lt;/li&gt;
&lt;li&gt;Capture an observation.&lt;/li&gt;
&lt;li&gt;Continue exploring.&lt;/li&gt;
&lt;li&gt;Finish the expedition.&lt;/li&gt;
&lt;li&gt;Look at your Grass Score.&lt;/li&gt;
&lt;li&gt;Check your Nature / Screen Ratio.&lt;/li&gt;
&lt;li&gt;Browse the journal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And yes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;actually take it outside.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's where TerraLens makes sense.&lt;/p&gt;




&lt;h1&gt;
  
  
  ## Code
&lt;/h1&gt;

&lt;p&gt;TerraLens is open source.&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;Source code&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;The repository includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Next.js application&lt;/li&gt;
&lt;li&gt;PWA/offline infrastructure&lt;/li&gt;
&lt;li&gt;IndexedDB persistence&lt;/li&gt;
&lt;li&gt;expedition and mission engines&lt;/li&gt;
&lt;li&gt;deterministic Grass Score engine&lt;/li&gt;
&lt;li&gt;Curiosity Engine&lt;/li&gt;
&lt;li&gt;Gemma adapter&lt;/li&gt;
&lt;li&gt;Tinker workspace&lt;/li&gt;
&lt;li&gt;Mastra Field Agent&lt;/li&gt;
&lt;li&gt;Temporal worker&lt;/li&gt;
&lt;li&gt;TabPFN prediction service&lt;/li&gt;
&lt;li&gt;MongoDB integration&lt;/li&gt;
&lt;li&gt;Tiger Data retrieval layer&lt;/li&gt;
&lt;li&gt;ElevenLabs voice integration&lt;/li&gt;
&lt;li&gt;Backboard memory&lt;/li&gt;
&lt;li&gt;SerpApi enrichment&lt;/li&gt;
&lt;li&gt;Sentry observability&lt;/li&gt;
&lt;li&gt;unit/integration tests&lt;/li&gt;
&lt;li&gt;Playwright E2E tests&lt;/li&gt;
&lt;li&gt;CI configuration&lt;/li&gt;
&lt;li&gt;deployment configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is available under the project's open-source license.&lt;/p&gt;




&lt;h1&gt;
  
  
  ## My Agent Session
&lt;/h1&gt;

&lt;p&gt;AI-assisted development played an important role in building TerraLens. I used Qoder as my coding agent throughout development—not just to generate code, but to help iterate on the architecture, investigate implementation problems, review different approaches, and turn the original idea into a working product.&lt;/p&gt;

&lt;p&gt;The development process covered everything from the offline-first PWA architecture and IndexedDB persistence to the Curiosity Engine, Gemma integration, Touch Grass Mode, Grass Score, safety rules, synchronization, agent workflows, sponsor integrations, testing, and deployment.&lt;/p&gt;

&lt;p&gt;Rather than starting with a finished specification and asking an agent to generate a landing page, TerraLens evolved through repeated cycles of idea → implementation → testing → review → improvement.&lt;/p&gt;




&lt;h1&gt;
  
  
  ## Prize Categories
&lt;/h1&gt;

&lt;p&gt;Rather than listing technologies just because they're sponsors, these are the categories that correspond to meaningful parts of TerraLens.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏆 Best Use of Gemma — Primary Category
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This is the category TerraLens is most strongly built around.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gemma provides the open-weight intelligence path behind observation understanding and the Curiosity Engine.&lt;/p&gt;

&lt;p&gt;More importantly, Gemma represents the architectural idea behind TerraLens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI that can move closer to the user instead of forcing the user closer to the cloud.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of Tinker
&lt;/h2&gt;

&lt;p&gt;Tinker is used for the Curiosity Adapter experiment: adapting model behaviour away from long generic answers and toward safe, useful physical-world actions.&lt;/p&gt;

&lt;p&gt;The interesting evaluation question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can fine-tuning make an AI measurably better at getting someone to stop interacting with the AI?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of TabPFN
&lt;/h2&gt;

&lt;p&gt;TabPFN powers the structured prediction path for exploration forecasting.&lt;/p&gt;

&lt;p&gt;Rather than asking an LLM to invent probabilities, TerraLens can use structured historical/environmental information to make actual predictions.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of ElevenLabs
&lt;/h2&gt;

&lt;p&gt;ElevenLabs gives Pocket Mode a voice.&lt;/p&gt;

&lt;p&gt;This isn't just narration for decoration.&lt;/p&gt;

&lt;p&gt;Voice directly supports TerraLens's goal of reducing visual screen interaction during an expedition.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of Mastra
&lt;/h2&gt;

&lt;p&gt;Mastra powers the Field Agent architecture that reasons across an expedition rather than treating each observation as an unrelated interaction.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of MongoDB Atlas
&lt;/h2&gt;

&lt;p&gt;MongoDB Atlas provides optional synchronized journal and observation storage while the browser remains capable of supporting the core offline experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of Temporal
&lt;/h2&gt;

&lt;p&gt;Temporal makes the online workflow durable so cloud processing can survive unreliable connectivity and continue when an expedition reconnects.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of Tiger Data
&lt;/h2&gt;

&lt;p&gt;Tiger Data/Postgres + pgvector powers the extended nature-knowledge retrieval layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of Backboard
&lt;/h2&gt;

&lt;p&gt;Backboard provides long-term Field Agent memory so future expeditions can learn from previous exploration behaviour.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of SerpApi
&lt;/h2&gt;

&lt;p&gt;SerpApi adds optional fresh online context while remaining deliberately separate from TerraLens's core identification/intelligence path.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of Sentry Agent Tracing
&lt;/h2&gt;

&lt;p&gt;Sentry provides observability into AI and workflow execution while TerraLens's telemetry rules keep private observation content out of tracing.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏆 Best Use of GitHub Copilot
&lt;/h2&gt;

&lt;p&gt;GitHub and AI-assisted development supported the engineering workflow, while CI validates formatting, types, linting, tests and production builds.&lt;/p&gt;




&lt;h1&gt;
  
  
  🌱 What I Learned
&lt;/h1&gt;

&lt;p&gt;The biggest thing I learned while building TerraLens wasn't about model size.&lt;/p&gt;

&lt;p&gt;It wasn't about vector databases.&lt;/p&gt;

&lt;p&gt;It wasn't about agents.&lt;/p&gt;

&lt;p&gt;It wasn't even about offline AI.&lt;/p&gt;

&lt;p&gt;It was this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sometimes the most helpful thing an AI can do is stop talking.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If I ask about a leaf, maybe I don't need six paragraphs.&lt;/p&gt;

&lt;p&gt;Maybe I need:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Turn it over.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If I hear a bird:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Close your eyes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If I find a flower:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find another one that looks completely different.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If I've been walking while staring at my phone:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Put it away.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI is becoming extremely good at generating more things for us to consume.&lt;/p&gt;

&lt;p&gt;More text.&lt;/p&gt;

&lt;p&gt;More images.&lt;/p&gt;

&lt;p&gt;More video.&lt;/p&gt;

&lt;p&gt;More answers.&lt;/p&gt;

&lt;p&gt;More screen time.&lt;/p&gt;

&lt;p&gt;TerraLens is a small experiment in the opposite direction.&lt;/p&gt;

&lt;p&gt;Using intelligence not to create another digital world...&lt;/p&gt;

&lt;p&gt;but to make the &lt;strong&gt;real one easier to notice.&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  One Last Thing
&lt;/h1&gt;

&lt;p&gt;The funniest possible success metric for TerraLens would be this:&lt;/p&gt;

&lt;p&gt;Someone opens the application.&lt;/p&gt;

&lt;p&gt;Gets a mission.&lt;/p&gt;

&lt;p&gt;Locks their phone.&lt;/p&gt;

&lt;p&gt;Walks away.&lt;/p&gt;

&lt;p&gt;And completely forgets TerraLens exists for the next thirty minutes.&lt;/p&gt;

&lt;p&gt;For most apps, that would be terrible engagement.&lt;/p&gt;

&lt;p&gt;For TerraLens?&lt;/p&gt;

&lt;h1&gt;
  
  
  That's a perfect session. 🌱
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Ask once.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Look closer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listen longer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Walk farther.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Put your phone away.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Go touch grass.
&lt;/h1&gt;




&lt;p&gt;🌱 &lt;strong&gt;Try TerraLens:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://terralens.soumwadeepguha.com/" rel="noopener noreferrer"&gt;https://terralens.soumwadeepguha.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;Source Code:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/soumwadeep/TerraLens" rel="noopener noreferrer"&gt;https://github.com/soumwadeep/TerraLens&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  TerraLens
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AI that sends you outside.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>I Built PingMe — An AI That Turns Your Messy Thoughts Into Tasks</title>
      <dc:creator>Soumwadeep Guha</dc:creator>
      <pubDate>Sun, 04 Oct 2026 05:02:34 +0000</pubDate>
      <link>https://dev.to/soumwadeep/i-built-pingme-an-ai-that-turns-your-messy-thoughts-into-tasks-799</link>
      <guid>https://dev.to/soumwadeep/i-built-pingme-an-ai-that-turns-your-messy-thoughts-into-tasks-799</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;
  
  
  Meet PingMe 👋
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Say it. Forget it. We'll remember.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Have you ever told yourself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I need to call Mom tomorrow morning."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I have to send that presentation tonight, pay the electricity bill by Thursday, and prepare for my interview on Monday."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then... completely forgotten about it?&lt;/p&gt;

&lt;p&gt;I have. My friends have too.&lt;/p&gt;

&lt;p&gt;The funny thing is, we already have calendars, reminder apps, note-taking apps, and to-do lists.&lt;/p&gt;

&lt;p&gt;So why do we still forget things?&lt;/p&gt;

&lt;p&gt;That question became the starting point for &lt;strong&gt;PingMe&lt;/strong&gt;.&lt;/p&gt;




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

&lt;p&gt;I didn't want to build another to-do app.&lt;/p&gt;

&lt;p&gt;There are already hundreds of them.&lt;/p&gt;

&lt;p&gt;The problem I noticed was much simpler:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our thoughts don't arrive as perfectly organized to-do lists.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They arrive like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Tomorrow remind me at 10 to send my resume, I need to buy medicine in the evening, and my interview is Monday at 2."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A normal task app expects you to separate all of that yourself.&lt;/p&gt;

&lt;p&gt;You create one task.&lt;/p&gt;

&lt;p&gt;Choose its date.&lt;/p&gt;

&lt;p&gt;Choose its time.&lt;/p&gt;

&lt;p&gt;Save it.&lt;/p&gt;

&lt;p&gt;Create another task.&lt;/p&gt;

&lt;p&gt;Choose another date.&lt;/p&gt;

&lt;p&gt;Save it.&lt;/p&gt;

&lt;p&gt;Then create an event.&lt;/p&gt;

&lt;p&gt;Then maybe create a reminder.&lt;/p&gt;

&lt;p&gt;That's a surprising amount of work just to make sure you don't forget something.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;PingMe&lt;/strong&gt;, an AI-powered memory companion where you can simply write what's on your mind.&lt;/p&gt;

&lt;p&gt;PingMe figures out the rest.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Brain Dump
&lt;/h3&gt;

&lt;p&gt;The main feature of PingMe is something I call &lt;strong&gt;Brain Dump&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of filling out forms, you just type naturally.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Tomorrow remind me at 10 to send my resume, buy medicine in the evening, and my interview is Monday at 2."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then press:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✨ Sort My Brain&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%2Ff9s99vvtjypg482iyn6g.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%2Ff9s99vvtjypg482iyn6g.png" alt="Write your messy thought here :)" width="800" height="692"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PingMe reads the whole thought and turns it into something useful:&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%2Festtu1tn794hn34t2yx8.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%2Festtu1tn794hn34t2yx8.png" alt="PingMe extracts valuable items from your messy thought :)" width="800" height="698"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tomorrow — 10:00 AM&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
📋 Send resume&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tomorrow — Evening&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
📋 Buy medicine&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monday — 2:00 PM&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
📅 Interview&lt;/p&gt;

&lt;p&gt;You don't need to tell PingMe which part is a task, which part is an event, or manually separate everything.&lt;/p&gt;

&lt;p&gt;The AI handles that.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why I Built It for a Friend
&lt;/h2&gt;

&lt;p&gt;The theme of this challenge is &lt;strong&gt;Build for a Friend&lt;/strong&gt;, and that shaped the entire idea behind PingMe.&lt;/p&gt;

&lt;p&gt;I thought about how people actually remind each other about things.&lt;/p&gt;

&lt;p&gt;A friend doesn't normally say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Please create a medium-priority task with a due date of October 5 at 10:00 AM."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Bro, remind me tomorrow morning to send that email."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;😄&lt;/p&gt;

&lt;p&gt;And somehow we understand exactly what they mean.&lt;/p&gt;

&lt;p&gt;That's the experience I wanted PingMe to have.&lt;/p&gt;

&lt;p&gt;I wanted it to feel less like filling out a productivity form and more like telling a dependable friend:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Hey, don't let me forget this."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's also where the name came from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ping me when I need to remember.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  It's Not Just About Creating Tasks
&lt;/h2&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%2F6mk8h4rz8mwjq56qof9u.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%2F6mk8h4rz8mwjq56qof9u.png" alt="Your All Items" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once PingMe understands something, you remain in control.&lt;/p&gt;

&lt;p&gt;You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✏️ Edit a task&lt;/li&gt;
&lt;li&gt;🗑️ Delete something you don't need&lt;/li&gt;
&lt;li&gt;✅ Mark tasks as completed&lt;/li&gt;
&lt;li&gt;📅 See what's coming up&lt;/li&gt;
&lt;li&gt;🧠 Add more thoughts using Brain Dump&lt;/li&gt;
&lt;li&gt;🎙️ Listen to a spoken summary of your day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I intentionally kept the experience simple.&lt;/p&gt;

&lt;p&gt;I didn't want PingMe to become project-management software.&lt;/p&gt;

&lt;p&gt;No complicated workspaces.&lt;/p&gt;

&lt;p&gt;No teams.&lt;/p&gt;

&lt;p&gt;No boards with 20 different columns.&lt;/p&gt;

&lt;p&gt;No account setup just to remember that you need to buy medicine tomorrow.&lt;/p&gt;

&lt;p&gt;The goal is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Capture the thought → understand it → remember it.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🔊 "Tell Me My Day"
&lt;/h2&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%2Fqwyc6lko0tmngevs417f.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%2Fqwyc6lko0tmngevs417f.png" alt="Tell Me My Day Section" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This became one of my favorite parts of the project.&lt;/p&gt;

&lt;p&gt;Sometimes you don't want to look through another screen in the morning.&lt;/p&gt;

&lt;p&gt;So PingMe can &lt;strong&gt;tell you about your day&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Press &lt;strong&gt;Tell Me My Day&lt;/strong&gt;, and PingMe creates a simple summary of what you have coming up.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You have three things today. Remember to send your resume at 10 AM, buy medicine this evening, and prepare for your upcoming interview."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the voice, I integrated &lt;strong&gt;ElevenLabs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That turns PingMe from something you constantly have to check into something that can actually speak to you like an assistant.&lt;/p&gt;

&lt;p&gt;This integration isn't there just to add another technology to the project.&lt;/p&gt;

&lt;p&gt;It fits the original idea:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would a helpful friend do?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They wouldn't hand you a JSON file. 😅&lt;/p&gt;

&lt;p&gt;They'd probably say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey, you've got these things today. Don't forget."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's what I wanted PingMe to feel like.&lt;/p&gt;


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

&lt;p&gt;The complete application is deployed and working here:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://pingme.soumwadeepguha.com/" rel="noopener noreferrer"&gt;https://pingme.soumwadeepguha.com/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Try giving it something messy rather than writing a perfectly formatted task.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I need to call Mom tomorrow morning, send the presentation tonight and pay the electricity bill before Thursday."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then press:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✨ Sort My Brain&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the best way to experience what PingMe is supposed to do.&lt;/p&gt;


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

&lt;p&gt;The project is open source and the source code is available on GitHub:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/soumwadeep/PingMe" rel="noopener noreferrer"&gt;https://github.com/soumwadeep/PingMe&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The repository also contains information about the architecture, setup, AI integration, and how to run PingMe locally.&lt;/p&gt;


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

&lt;p&gt;I wanted the technical side of PingMe to support one very simple experience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your messy thought
        ↓
     PingMe
        ↓
 Open-source AI
        ↓
Understand meaning
        ↓
Tasks / Events / Reminders
        ↓
     My Day
        ↓
  Don't forget! 🔔
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Underneath that simple experience, several things are happening.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Gemma — The Brain Behind PingMe
&lt;/h3&gt;

&lt;p&gt;The most important part of PingMe is understanding what the user actually means.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;Gemma&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;Gemma is used as the open-weight AI at the core of PingMe's understanding layer.&lt;/p&gt;

&lt;p&gt;Imagine somebody writes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Need to send Shreshtha the deck tonight and remind me tomorrow morning to call Mom."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A computer normally just sees a sentence.&lt;/p&gt;

&lt;p&gt;PingMe needs to understand that there are actually &lt;strong&gt;two separate commitments&lt;/strong&gt; hiding inside it.&lt;/p&gt;

&lt;p&gt;One is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Send Rohan the deck — tonight&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The other is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Call Mom — tomorrow morning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PingMe sends the natural-language thought through its AI extraction layer.&lt;/p&gt;

&lt;p&gt;The model identifies useful information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What needs to be done&lt;/li&gt;
&lt;li&gt;Whether something is a task or event&lt;/li&gt;
&lt;li&gt;When it needs to happen&lt;/li&gt;
&lt;li&gt;Whether a time was mentioned&lt;/li&gt;
&lt;li&gt;How the sentence should be separated into individual commitments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is then converted into structured information that the rest of PingMe can understand.&lt;/p&gt;

&lt;p&gt;One important thing I added here was validation.&lt;/p&gt;

&lt;p&gt;AI output isn't blindly trusted.&lt;/p&gt;

&lt;p&gt;The response is checked before PingMe turns it into something that appears in your day.&lt;/p&gt;

&lt;p&gt;The user also gets the ability to edit or delete commitments afterward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI organizes. The human stays in control.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🗓️ Understanding Human Time
&lt;/h2&gt;

&lt;p&gt;One surprisingly interesting challenge was time.&lt;/p&gt;

&lt;p&gt;Humans rarely speak in database-friendly dates.&lt;/p&gt;

&lt;p&gt;We don't normally say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Create this for 2026-10-05T10:00:00."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Tomorrow morning."&lt;/p&gt;

&lt;p&gt;"Tonight."&lt;/p&gt;

&lt;p&gt;"Next Monday."&lt;/p&gt;

&lt;p&gt;"Before Thursday."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For PingMe to feel natural, it has to understand those phrases in the context of &lt;strong&gt;today&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means the AI receives the relevant date and time context so it can interpret relative phrases correctly instead of guessing blindly.&lt;/p&gt;

&lt;p&gt;It's a small detail, but it makes a huge difference to the experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  💾 Local-First by Design
&lt;/h2&gt;

&lt;p&gt;Something else mattered to me while building PingMe:&lt;/p&gt;

&lt;p&gt;These are personal thoughts.&lt;/p&gt;

&lt;p&gt;A person's reminders can reveal a surprising amount about their life.&lt;/p&gt;

&lt;p&gt;Appointments.&lt;/p&gt;

&lt;p&gt;Family commitments.&lt;/p&gt;

&lt;p&gt;Interviews.&lt;/p&gt;

&lt;p&gt;Bills.&lt;/p&gt;

&lt;p&gt;Work.&lt;/p&gt;

&lt;p&gt;Travel.&lt;/p&gt;

&lt;p&gt;Medication reminders.&lt;/p&gt;

&lt;p&gt;Personal plans.&lt;/p&gt;

&lt;p&gt;So I designed PingMe with a &lt;strong&gt;local-first approach&lt;/strong&gt; for the user's stored commitments.&lt;/p&gt;

&lt;p&gt;The application keeps the user's task data in browser storage rather than requiring an account and sending every saved task to a central database.&lt;/p&gt;

&lt;p&gt;The AI still needs the Brain Dump text when you explicitly ask it to understand and organize that text, but the application doesn't need a giant cloud database containing everyone's personal task history just to function.&lt;/p&gt;

&lt;p&gt;That separation was intentional.&lt;/p&gt;




&lt;h2&gt;
  
  
  ☁️ Render — Where PingMe Lives
&lt;/h2&gt;

&lt;p&gt;I deployed the application using &lt;strong&gt;Render&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Render gives PingMe its production environment and allows the application and its server-side functionality to be available as a real product instead of remaining a localhost hackathon demo.&lt;/p&gt;

&lt;p&gt;The live version is available at:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://pingme.soumwadeepguha.com/" rel="noopener noreferrer"&gt;https://pingme.soumwadeepguha.com/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Having the server side deployed is particularly important because sensitive service credentials shouldn't be placed directly inside frontend code.&lt;/p&gt;

&lt;p&gt;PingMe can keep those integrations behind its server-side endpoints while the user gets a simple web interface.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎙️ ElevenLabs — Giving PingMe a Voice
&lt;/h2&gt;

&lt;p&gt;I used &lt;strong&gt;ElevenLabs&lt;/strong&gt; for the voice experience behind &lt;strong&gt;Tell Me My Day&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;PingMe first understands the user's commitments and builds a natural daily briefing.&lt;/p&gt;

&lt;p&gt;ElevenLabs then turns that briefing into speech.&lt;/p&gt;

&lt;p&gt;This creates a completely different way of interacting with the product.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open app → scan tasks → understand schedule&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;you can simply ask PingMe to tell you about your day.&lt;/p&gt;

&lt;p&gt;That was one of those features where, after getting it working, PingMe started feeling much more like a companion than a task manager.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tech Behind It
&lt;/h2&gt;

&lt;p&gt;For anyone interested in the technical side, PingMe is built with a modern web stack including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Material UI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gemma&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IndexedDB / browser-side persistence&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ElevenLabs&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Render&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But I deliberately tried to hide most of that complexity from the person using PingMe.&lt;/p&gt;

&lt;p&gt;A non-technical user shouldn't need to know what model inference, structured output, IndexedDB, or an API route is.&lt;/p&gt;

&lt;p&gt;They should only need to know:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Write what you're thinking. PingMe will organize it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the technology disappears into the experience, I think it's doing its job.&lt;/p&gt;




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

&lt;p&gt;This part of the challenge was especially interesting to me.&lt;/p&gt;

&lt;p&gt;There are plenty of closed AI APIs that can understand a sentence.&lt;/p&gt;

&lt;p&gt;So why care about open models?&lt;/p&gt;

&lt;p&gt;Because I don't think AI should only exist as a black box that developers rent one request at a time.&lt;/p&gt;

&lt;p&gt;Open-weight models such as &lt;strong&gt;Gemma&lt;/strong&gt; give developers much more freedom to understand, experiment with, customize, optimize, and eventually run intelligence in environments that make sense for their users.&lt;/p&gt;

&lt;p&gt;That matters particularly for a product like PingMe.&lt;/p&gt;

&lt;p&gt;The information we give a memory assistant can be personal.&lt;/p&gt;

&lt;p&gt;Today PingMe uses an AI inference layer to understand Brain Dumps, but an open-model architecture gives this idea somewhere much more interesting to go in the future:&lt;/p&gt;

&lt;h3&gt;
  
  
  Fully local AI.
&lt;/h3&gt;

&lt;p&gt;Imagine downloading PingMe and having the intelligence itself running on your own device.&lt;/p&gt;

&lt;p&gt;No account.&lt;/p&gt;

&lt;p&gt;No sending your personal thoughts to an external AI service.&lt;/p&gt;

&lt;p&gt;No internet connection required for understanding them.&lt;/p&gt;

&lt;p&gt;Just:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You → your device → your AI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open innovation makes that direction possible.&lt;/p&gt;

&lt;p&gt;And that's much more exciting to me than simply replacing one API endpoint with another.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Was Harder Than I Expected?
&lt;/h2&gt;

&lt;p&gt;At first, PingMe sounded simple.&lt;/p&gt;

&lt;p&gt;"Take a sentence and turn it into tasks."&lt;/p&gt;

&lt;p&gt;Then I started thinking about sentences like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"My interview is Monday at 2, remind me Sunday evening to prepare and I also need to send my resume tomorrow."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we're dealing with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an event&lt;/li&gt;
&lt;li&gt;a preparation reminder&lt;/li&gt;
&lt;li&gt;another task&lt;/li&gt;
&lt;li&gt;three different times&lt;/li&gt;
&lt;li&gt;relative dates&lt;/li&gt;
&lt;li&gt;implied relationships between them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And humans can still understand that sentence almost instantly.&lt;/p&gt;

&lt;p&gt;Teaching software to transform that messy human thought into clean, useful information—without making the user learn a special command format—was the interesting part of this project.&lt;/p&gt;

&lt;p&gt;Another challenge was deciding what &lt;strong&gt;not&lt;/strong&gt; to build.&lt;/p&gt;

&lt;p&gt;It's very tempting during a hackathon to keep adding features.&lt;/p&gt;

&lt;p&gt;Calendar.&lt;/p&gt;

&lt;p&gt;Teams.&lt;/p&gt;

&lt;p&gt;Projects.&lt;/p&gt;

&lt;p&gt;Analytics.&lt;/p&gt;

&lt;p&gt;Accounts.&lt;/p&gt;

&lt;p&gt;Collaboration.&lt;/p&gt;

&lt;p&gt;But every time I considered another feature, I came back to one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Does this make "don't let me forget this" easier?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If not, it probably didn't belong in this version.&lt;/p&gt;




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

&lt;p&gt;This project reminded me that AI products don't always need to start with a chatbot.&lt;/p&gt;

&lt;p&gt;Sometimes AI is more useful when it quietly removes a step.&lt;/p&gt;

&lt;p&gt;Without PingMe:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think → remember → open app → create task → choose type → choose date → choose time → save&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With PingMe:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think → say it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the experience I'm trying to build toward.&lt;/p&gt;

&lt;p&gt;I also learned that the most interesting AI interface isn't necessarily a giant chat window.&lt;/p&gt;

&lt;p&gt;The intelligence can sit between &lt;strong&gt;what a human naturally says&lt;/strong&gt; and &lt;strong&gt;what software needs to understand&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is exactly what PingMe does.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;There are several directions I'd love to explore after the challenge.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 More capable local AI
&lt;/h3&gt;

&lt;p&gt;My biggest goal would be moving more of PingMe's intelligence directly onto the user's device.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔔 Better reminders
&lt;/h3&gt;

&lt;p&gt;Smarter reminders based on urgency and context rather than simply displaying a fixed notification.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎙️ Voice-first Brain Dump
&lt;/h3&gt;

&lt;p&gt;Instead of typing anything:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"PingMe, remind me tomorrow morning to..."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and you're done.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔁 Recurring commitments
&lt;/h3&gt;

&lt;p&gt;Things like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Remind me to call my parents every Sunday."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  📅 Calendar integration
&lt;/h3&gt;

&lt;p&gt;Allow confirmed events to optionally appear in the user's existing calendar.&lt;/p&gt;

&lt;h3&gt;
  
  
  📱 Mobile experience
&lt;/h3&gt;

&lt;p&gt;Turn PingMe into an even faster always-available capture experience on phones.&lt;/p&gt;

&lt;p&gt;But I want to keep one principle regardless of how much PingMe grows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It should always be easier than creating the reminder manually.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why PingMe?
&lt;/h2&gt;

&lt;p&gt;I started this challenge thinking about what I could build &lt;strong&gt;for a friend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I ended it thinking about what we actually expect from a good friend.&lt;/p&gt;

&lt;p&gt;A good friend listens.&lt;/p&gt;

&lt;p&gt;A good friend understands what you mean even when you don't phrase everything perfectly.&lt;/p&gt;

&lt;p&gt;And occasionally...&lt;/p&gt;

&lt;p&gt;A good friend says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey, don't forget that thing you told me about."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's PingMe.&lt;/p&gt;

&lt;p&gt;Not another productivity dashboard.&lt;/p&gt;

&lt;p&gt;Not another chatbot.&lt;/p&gt;

&lt;p&gt;Just a small AI companion designed around a very human problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We have too much on our minds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So...&lt;/p&gt;

&lt;h3&gt;
  
  
  Say it.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Forget it.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  We'll remember. 💜
&lt;/h3&gt;




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

&lt;p&gt;I'm submitting PingMe for the partner categories that directly correspond to technologies used in the working project:&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Gemma
&lt;/h3&gt;

&lt;p&gt;Gemma provides the open-weight AI foundation for understanding natural Brain Dumps and transforming them into structured commitments.&lt;/p&gt;

&lt;h3&gt;
  
  
  ☁️ Render
&lt;/h3&gt;

&lt;p&gt;PingMe's production application is deployed using Render and is available through its live domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔊 ElevenLabs
&lt;/h3&gt;

&lt;p&gt;ElevenLabs powers PingMe's spoken &lt;strong&gt;Tell Me My Day&lt;/strong&gt; experience, turning daily briefings into natural voice output.&lt;/p&gt;

&lt;p&gt;Each integration serves an actual part of the product rather than being included solely for the category.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try PingMe 💜
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://pingme.soumwadeepguha.com/" rel="noopener noreferrer"&gt;https://pingme.soumwadeepguha.com/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source Code:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/soumwadeep/PingMe" rel="noopener noreferrer"&gt;https://github.com/soumwadeep/PingMe&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Give it a messy thought.&lt;/p&gt;

&lt;p&gt;Something you'd normally tell a friend not to let you forget.&lt;/p&gt;

&lt;p&gt;Then hit &lt;strong&gt;Sort My Brain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'd love to know whether PingMe understood you. 🙂&lt;/p&gt;

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