<?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: Seth S</title>
    <description>The latest articles on DEV Community by Seth S (@seth_s_292e9e8e75b62dac52).</description>
    <link>https://dev.to/seth_s_292e9e8e75b62dac52</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%2F3129751%2F6ed24708-99ec-4864-987d-d16393142b64.png</url>
      <title>DEV Community: Seth S</title>
      <link>https://dev.to/seth_s_292e9e8e75b62dac52</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/seth_s_292e9e8e75b62dac52"/>
    <language>en</language>
    <item>
      <title>Reads everything. Remembers nothing: an email watch API built on open-weights AI</title>
      <dc:creator>Seth S</dc:creator>
      <pubDate>Tue, 13 Oct 2026 01:30:46 +0000</pubDate>
      <link>https://dev.to/seth_s_292e9e8e75b62dac52/reads-everything-remembers-nothing-an-email-watch-api-built-on-open-weights-ai-3loe</link>
      <guid>https://dev.to/seth_s_292e9e8e75b62dac52/reads-everything-remembers-nothing-an-email-watch-api-built-on-open-weights-ai-3loe</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;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;WatchFox is an email-watching API.&lt;/strong&gt; You tell it which mailbox to watch and what to catch (an enquiry, an invoice, a support ticket, a purchase order, a job application, a claim, or a type you define), and when a matching email arrives it calls your server with a &lt;strong&gt;signed webhook&lt;/strong&gt;. Your app never has to read an inbox or write a classifier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who pays:&lt;/strong&gt; SaaS builders and operations teams that need to react to inbound email: sales enquiries and RFQs that must reach the right person in minutes, invoices heading into accounts payable, support requests, purchase orders, claims. Their customers connect a mailbox through a hosted page that carries the SaaS's own name, logo and colour, so the SaaS can offer "connect your mailbox" in an afternoon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem it solves:&lt;/strong&gt; every team that wants this ends up writing the same fragile pile: IMAP polling, regex rules, an LLM prompt per email, and a privacy question nobody can answer ("where did our customers' emails go?"). WatchFox replaces that with one API call, and answers the privacy question in the strongest way possible: &lt;strong&gt;it never stores email content.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's live and taking subscriptions: Kit (free, 50 runs a month), Tracker ($29) and Alpha ($149).&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live site:&lt;/strong&gt; &lt;a href="https://watchfox.run" rel="noopener noreferrer"&gt;https://watchfox.run&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs written for humans and for coding agents:&lt;/strong&gt; &lt;a href="https://watchfox.run/#/docs" rel="noopener noreferrer"&gt;https://watchfox.run/#/docs&lt;/a&gt;, plus &lt;a href="https://watchfox.run/llms-full.txt" rel="noopener noreferrer"&gt;https://watchfox.run/llms-full.txt&lt;/a&gt; (the whole API in one plain-text file an agent can read)&lt;/li&gt;
&lt;/ul&gt;

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


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sethsazure" rel="noopener noreferrer"&gt;
        sethsazure
      &lt;/a&gt; / &lt;a href="https://github.com/sethsazure/watchfox-open" rel="noopener noreferrer"&gt;
        watchfox-open
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      WatchFox: an email-watching API. Signed webhooks, open-weights decision model (Laya typed-decisions), zero email retention.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;WatchFox&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;An email-watching API.&lt;/strong&gt; Tell it which mailbox to watch and what to catch (an enquiry, an invoice, a support ticket, a purchase order
a job application, a claim, or a type you define). When a matching email arrives, WatchFox calls your server with a &lt;strong&gt;signed webhook&lt;/strong&gt;
Your app never has to read an inbox or train a classifier.&lt;/p&gt;

&lt;p&gt;Live service: &lt;strong&gt;&lt;a href="https://watchfox.run" rel="nofollow noopener noreferrer"&gt;https://watchfox.run&lt;/a&gt;&lt;/strong&gt; (free plan, 50 runs a month; the "try it" box on the home page runs the real checker without signing up).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open-weights decision model, self-hosted.&lt;/strong&gt; Emails are judged by &lt;a href="https://huggingface.co/convaiinnovations/laya-typed-decisions" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;convaiinnovations/laya-typed-decisions&lt;/code&gt;&lt;/a&gt;
a small (421M parameter) encoder that answers typed, calibrated questions, served by the open-source
&lt;a href="https://github.com/NandhaKishorM/laya" rel="noopener noreferrer"&gt;&lt;code&gt;laya-serve&lt;/code&gt;&lt;/a&gt;. It is not a chat model: no tokens, no per-email API bill, no invented answers, and a
score you can put a threshold on. On a single 12 GB consumer GPU it makes roughly 400 decisions per second when requests…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sethsazure/watchfox-open" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
About 6,400 lines of Python (FastAPI), 3,500 lines of React, &lt;strong&gt;74 automated tests that run on both SQLite and PostgreSQL&lt;/strong&gt;, and a GitHub Actions pipeline that tests, builds and deploys to Azure on every push.
&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The open-source AI: an open-weights "decision" model, self-hosted.&lt;/strong&gt;&lt;br&gt;
WatchFox doesn't ask a chat LLM "is this an invoice?" on every email. It uses &lt;strong&gt;Laya &lt;code&gt;typed-decisions&lt;/code&gt;&lt;/strong&gt; (open weights on Hugging Face), a 421M-parameter ModernBERT-large encoder that answers &lt;em&gt;typed, calibrated questions&lt;/em&gt; about a piece of text: yes/no probabilities, choices and ordinal scores. It runs on &lt;strong&gt;&lt;code&gt;laya-serve&lt;/code&gt;&lt;/strong&gt; (open source) on &lt;strong&gt;In my own server rack&lt;/strong&gt;, and the production app reaches it over a private network.&lt;/p&gt;

&lt;p&gt;Why that choice, in numbers: one non-generative forward pass, about 3 GB of VRAM, and **roughly 400 decisions per second when requests are batched. No tokens, no per-email API bill, no hallucinated answers, and a score I can put a threshold on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problems I had to solve (the interesting part):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A model that wasn't built for my job.&lt;/strong&gt; The base model answers questions; it doesn't know what a "good" question is for &lt;em&gt;my&lt;/em&gt; customers. I built a &lt;strong&gt;tuner&lt;/strong&gt;: for each type you create, it tries several wordings of the question, scores them on your labelled examples &lt;em&gt;and&lt;/em&gt; on a built-in set of look-alikes, picks the wording that separates them best, sets the threshold, and adds exclusions for the look-alikes it still gets wrong. Press "wrong catch" on a real email and it re-tunes from that mistake. It's measured, not magic, and the UI says so.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;"Never keep the email" is easy to promise and hard to build.&lt;/strong&gt; WatchFox keeps only the subject, sender, a 300-character snippet, attachment names and scores, for 90 days. When a customer needs the whole &lt;code&gt;.eml&lt;/code&gt; or an attachment, WatchFox reads it &lt;strong&gt;from the mailbox at that moment&lt;/strong&gt;, streams it through, and forgets it. The full text only ever exists in memory while a webhook is being delivered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Putting a private GPU behind a public web app.&lt;/strong&gt; Azure App Service containers have no network device that talent recognizes, so the node never signed in. Fix: userspace networking plus the &lt;code&gt;TAILNET&lt;/code&gt; flag, and a SOCKS proxy that carries &lt;em&gt;only&lt;/em&gt; the model calls, so nothing a user supplies (a webhook URL, a mail-server host) can ever reach the private network. If the GPU is unreachable, a paced fallback queue takes over, and the status page says which path is serving.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Every limit is the same in the dashboard and the API.&lt;/strong&gt; A test hits each limit with an API key, because that's where limits usually leak.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Built for AI agents as customers.&lt;/strong&gt; &lt;code&gt;llms.txt&lt;/code&gt;, &lt;code&gt;llms-full.txt&lt;/code&gt; and an OpenAPI file are generated from the live API, and a test fails if anyone adds a public endpoint without a description. A coding agent can integrate WatchFox from one file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Proven under load.&lt;/strong&gt; On a local PostgreSQL run with the model stubbed: 100 accounts, 5,000 emails, &lt;strong&gt;every webhook delivered in about 31 seconds with zero errors&lt;/strong&gt;, while 50 clients hammered the read API (median 0.3 s).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; FastAPI, React + Vite, PostgreSQL, Azure App Service (containers), GitHub Actions with Azure OIDC (no stored cloud password).&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Three things a closed API would have made impossible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The privacy promise.&lt;/strong&gt; "We never keep your email" means nothing if the text goes to someone else's LLM first. With open weights on my own GPU, an email's text goes from the mailbox to my model over a private network and nowhere else. I can tell customers exactly where it went.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The economics of a side hustle.&lt;/strong&gt; A per-token API bill scales with every email. A 421M-parameter open model on a GPU costs the same at 10 emails or 10 million.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stability.&lt;/strong&gt; While preparing this launch I found that a closed model my tooling relied on was blocked for my Azure subscription in my region, and its successor wasn't offered there. I had to change the assistant's model mid-build. The open weights I run don't get retired out from under me: I choose when to change them, and I can re-tune and re-test on my own data.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I built WatchFox in a long pairing session with Claude Code: design, the tuner, the security audit, the load test, the Azure and GitHub pipeline, and even the playbook I'm now using to migrate my next app the same way.&lt;/p&gt;

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

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

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