Inbox Sloth:在本機運行、替你讀取收件匣的 Gemma
Inbox Sloth: a local Gemma that reads your inbox so you don’t have to
Inbox Sloth 使用本機運行的 Gemma 讀取電郵,提取待辦事項和期限,並追蹤後續電郵對原有事項的更改。針對 18 封合成電郵的測試中,加入程式碼檢查後,找出事項、日期及類別均達 12/12;這是開發集分數,不能證明能推廣至其他電郵。現時只支援英文及匯入的電郵,尚未支援 Gmail 同步。
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
My professor emails on Monday: assignment due Friday. On Tuesday: "correction, because of the holiday it's now Thursday."
An email summariser gives me two accurate summaries and zero help. I still have to notice they're about the same assignment, remember which one wins, and move the date in my head.
Inbox Sloth does that part for me. It reads a mailbox with Gemma running on my own laptop, turns emails into commitments (what, by when, which email said so), and notices when a later email changes an earlier one:
Submit Probability Assignment 3: Thu 22 Oct, 11:59 PM. Changed (was Fri 23 Oct).
Evidence: "Please submit Probability Assignment 3 by Thursday 22 October, 11:59 PM instead."
I open one page and see what to do first, what's due this week, what clashes, and which dates moved and are worth double-checking.
- Reads email, extracts commitments: assignments, meetings, exams, replies, with deadlines resolved to real dates.
- Tracks them across emails: a correction updates the original task and keeps the history; an older email can never overwrite a newer one.
- Plans your day and week: ranked by urgency first, then by what you said matters (a student's exam, a freelancer's client reply). Every ranking shows its reasons, so you can disagree with it.
- Flags trouble: overlapping events, overloaded days, moved dates.
- Shows its evidence: every task links to the sentence it came from, highlighted in the original email.
- Admits what it ignored: informational emails (a mess menu, an instruction tweak) create no task and appear under "Ignored by the sloth" with the reason, so nothing disappears silently.
Demo
Run it yourself in a few minutes (the demo command runs the real model on 18 sample emails and scores it against ground truth):
ollama pull gemma3:1b
cd backend && pip install -r requirements.txt
python -m pytest -q # 132 tests, no Ollama needed
python -m app.cli demo # real model run, scored against ground truth
uvicorn app.main:app # http://localhost:8000
Code
https://github.com/newton-lebniz/inbox-sloth
How I Built It
Stack: gemma3:1b via Ollama (JSON-schema constrained output, temperature 0), FastAPI, SQLite, plain HTML/JS, pytest. It runs on a CPU-only laptop with 16 GB RAM.
The key design decision: the model is a noisy witness. The model reads; code decides.
email -> Gemma (local, JSON-schema output) -> checks in plain code -> commitment tracker -> plan
- Dates are never computed by the model. It copies the words ("Thursday 5 PM"); a deterministic resolver turns them into a date relative to when the email was sent.
- A date has to be in the email. If the model's date words don't appear there, they're replaced by the email's own date (flagged "Date unsure") or dropped.
- A task needs a cue: an action, deadline, meeting or exam word, in a sentence that isn't about the past or a cancellation.
- Evidence is chosen by code, not trusted from the model's quote.
- Kind and title are normalised from the subject: a quiz is an exam, and a meeting is named after the meeting.
- Safety net: if the model returns nothing for an email, rules may propose one task, subject to the same checks, and the UI marks it "found by rules".
Valid model answers are cached by (model, prompt, email), so re-analysing all 18 emails after a code change takes about a second instead of three minutes. That is what made fast iteration possible on a CPU.
The part I almost didn't write
On Day 1, my evaluator said: 10 of 12 commitments found, 6 of 12 dates right.
Then I read the rows. It was comparing "Pay semester fee" with "Submit data structures exam". My matcher accepted the best title match even when the best was bad, so the score looked better than the output. After fixing the evaluator and re-scoring the same real output:
| Day 1 (real gemma3:1b run) | reported | actual |
|---|---|---|
| Commitments found | 10/12 | 6/12 |
| Dates correct | 6/12 | 5/12 |
| False positives | 2 | 6 |
What the real run showed: for 4 of the 14 actionable emails, including the deadline correction, no commitment came out. It invented tasks for informational emails ("Khichdi and papad dinner" from a mess-menu notice). It rewrote dates, and a quiz became "Attend class".
So the interesting problem wasn't prompting. It was building something that stays correct when the model doesn't. With the checks above, same prompt:
| Day 1 (re-scored) | After the code checks (real Gemma run) | |
|---|---|---|
| Found | 6/12 | 12/12 |
| Dates correct | 5/12 | 12/12 |
| Kinds correct | 5/12 | 12/12 |
An ablation (on recorded Gemma answers) shows where it comes from: without the rule safety net, 10/12 found and 9/12 dates; without the cue check, the false positives come back.
Honest caveats
- I wrote the rules after seeing these 18 emails, so this is a development-set score, not a claim that it generalises.
- I then wrote 12 differently-worded emails and ran them through the rules alone (all handled), and tried adversarial ones. That found two real flaws ("Thanks for attending the workshop on Monday" became a future task; an email's own subject could act as evidence for a title copied from it). Both are fixed and tested. But I wrote the rules and the tests, so treat this as a smoke test, not proof.
- All emails are synthetic. No real mailbox was used.
- A 1B model misses things; the rule fallback proposes at most one task per email. A cancellation is ignored rather than applied to an existing task. English only, no Gmail sync yet (imported messages only).
Why Does Open Innovation Matter?
Email is the most private text most people have: grades, client names, medical appointments, offers. I didn't want to ship that to a third-party API just to find out when my lab report is due.
- Local inference: after mail is fetched, analysis never leaves the machine.
- Free after setup: no per-email bill, so running it over a whole mailbox is a non-event.
-
Swappable: one environment variable (
SLOTH_MODEL=gemma3:4b) changes the model. That mattered, because a 1B model made mistakes and the architecture had to survive them. - Inspectable and reproducible: open weights at temperature 0 let me cache answers and replay them, so I could compare Day 1 and Day 2 on identical model output. A hosted model that changes under you can't give you that.
The Lazy Payoff
The saving is the part I used to do by hand: noticing that Tuesday's email overrides Monday's, and re-checking my own list. The honest limit: I haven't run it on a real mailbox for a week, only on 18 synthetic emails, so I can't claim hours saved. What I can show is that on those emails it found every commitment and applied the date correction, and that for every task it shows the sentence it came from, so checking it takes seconds.
What I learned: (1) a metric you wrote in ten minutes is a hypothesis, and mine flattered me until I read the rows; (2) let the model read and let code decide; (3) make every judgment visible. The evidence sentence, the ranking reasons and the ignored list made the tool trustworthy and also debuggable.
Prize Categories
Best Use of Gemma
來源:DEV Community · dev.to



