The idea: one button that classifies everything for you.
Take the last N weeks (6 by default, user-settable), collect every uncategorised event title, and ask an on-device model — "here is the event name, here are the available categories, where would you file it?" — then present the answers as suggestions the user accepts in one tap.
This is the difference between "sort 40 activities" and "check 40 suggestions", which is the difference between a tool for its author and a tool for someone else.
Where it plugs in
The v2 sorter (app/categorize.tsx) is already shaped for this. Suggestion carries title → categoryId plus the weight used to sort rows, and ResolutionSource already reserves 'model'. Swapping the built-in keyword table for a model changes where categoryId comes from and nothing else — same list, same rows, same accept-all, same undo, same button.
Platform APIs
| Platform |
API |
Notes |
| iOS 26+ |
Foundation Models (LanguageModelSession, guided generation) |
On-device, free, no entitlement. Apple Intelligence devices only. |
| Android |
ML Kit GenAI / Gemini Nano via AICore |
Pixel 9+ and comparable; capability must be queried, never assumed. |
Neither is exposed by an Expo module today, so each needs a small native module. Guided generation matters — constraining output to the category enum removes parsing entirely, which is what makes this reliable enough to run unattended over hundreds of titles.
Rules that have to hold
- Batch, don't stream. One session, all titles, one pass. Per-title round trips over a few hundred titles is minutes of wall clock and a flat battery.
- Send titles, nothing else. No dates, attendees, notes or locations. The privacy claim is that the calendar never leaves the device; an on-device model doesn't weaken it, but only if the prompt stays minimal — so that the claim survives the day someone proposes a cloud fallback. There is no cloud fallback.
- Suggestions, never writes. The wand fills the pickers. The user accepts.
- Degrade in silence. No capable model → the keyword table, no message, no nag. Most devices won't have one for years.
- Cache by normalised title. The same title must never be classified twice.
Full design: docs/CATEGORISATION.md §4.
The idea: one button that classifies everything for you.
Take the last N weeks (6 by default, user-settable), collect every uncategorised event title, and ask an on-device model — "here is the event name, here are the available categories, where would you file it?" — then present the answers as suggestions the user accepts in one tap.
This is the difference between "sort 40 activities" and "check 40 suggestions", which is the difference between a tool for its author and a tool for someone else.
Where it plugs in
The v2 sorter (
app/categorize.tsx) is already shaped for this.Suggestioncarriestitle→categoryIdplus the weight used to sort rows, andResolutionSourcealready reserves'model'. Swapping the built-in keyword table for a model changes wherecategoryIdcomes from and nothing else — same list, same rows, same accept-all, same undo, same button.Platform APIs
LanguageModelSession, guided generation)Neither is exposed by an Expo module today, so each needs a small native module. Guided generation matters — constraining output to the category enum removes parsing entirely, which is what makes this reliable enough to run unattended over hundreds of titles.
Rules that have to hold
Full design:
docs/CATEGORISATION.md§4.