Homescreen: how it's built
One calm home screen built from modules, ranked by the moment.
A module registry (40 modules on the main branch as of 2026-09-30, counted from the registry file), a context engine that ranks tiles by the moment and the mode, Postgres behind it, refresh on page load plus a daily and an hourly heal. Accounts are per user.
Architecture
How the home screen renders
Loaders run in parallel when the page loads; cached data is refreshed lazily when it is stale.
- Browser or home app → Sign-in check: open the home screen (request, sync)
- Sign-in check → Home page: signed-in session passes (request, sync)
- Home page → Module registry: run every module's loaders in parallel (request, sync)
- Module registry → Postgres: cached reads; refresh lazily when stale (request, sync)
- Module registry → Weather: forecast, no key (request, sync)
- Module registry → Drive times: drive time to the next event (request, sync)
- Module registry → Calendar: next events (request, sync)
- Module registry → Code and deploys: repository and deployment status (request, sync)
- Home page → Context engine: moment and mode from the clock and the override (request, sync)
- Context engine → Tile placement: score every module (request, sync)
- Tile placement → Browser or home app: hero, Now stack, grid and Quiet (response, sync)
Capture and heal
Phones, a Mac and tools push signed writes in. A daily cron and an hourly job refresh five modules' data.
- Phone shortcut → Signed ingest: a dictated item, signed (request, sync)
- Mac companion → Signed ingest: every six hours, signed (timer, async)
- Coding-session hook → Signed ingest: session events, signed (event, async)
- Tool server → Signed ingest: assistant writes with a bearer token (request, sync)
- Signed ingest → Postgres: store the item (request, sync)
- Daily cron → Background refresh: once a day (cron, async)
- Hourly heal job → Background refresh: every hour, fire and forget (cron, async)
- Background refresh → Postgres: refresh five modules' data (request, sync)
Wiremocks
A mock-up of a screen — Here, a static picture of a screen, drawn to show layout and flow, not the working app. — a static picture, not the real app
One module's own page
A travel module's trip page. The flight-status lookup runs only when this page opens, never on the home screen.
Outbound leg
In air after a delay
- 08:15Gate changed
- 09:05Delayed
- 09:40Departed
- 09:52In air
Return leg
Scheduled, not yet departed
- 16:10Gate changed
Status events the module records
- Departed
- Delayed
- Gate changed
- In air
- Landed
- Cancelled
Refreshed when the trip page opens, not on a timer.
A mock-up of a screen — Here, a static picture of a screen, drawn to show layout and flow, not the working app. — a static picture, not the real app
Capture from the phone
Dictate on the phone, send a signed request, and the item lands in the first column of the tracker board.
1. Phone shortcut
Dictate an item
Add: renew the library card
Send
2. Signed request
signed request → saved as item 42
The server checks the signature, then stores the item.
3. Tracker board
New
- Book the car service
- Renew the library card, item 42
In progress
- Call the plumber
Done
- Pay the water bill
Running cost
| Resource | Figure | Status | Source |
|---|---|---|---|
| Vercel edge requests, plan | One million — Shorthand in prices and limits, as in $1 per 1M tokens. requests per month, shared by about 10 projects | Published price | owner's metered-resource table (Vercel Requests Vercel counts at its edge — Every request Vercel serves (a page, a script, an image) counts as one.) Read on 2026-10-17 |
| Edge requests, whole account, July cycle | 1.2M requests, mostly before the fix (read with three days left); about 10 projects share the count | Measured | edge-requests write-up, lines 4-6 and 262-271 Read on 2026-10-17 |
| Widget refresh | 1 per 180 seconds while visible | Measured | edge-requests write-up, line 212 Read on 2026-10-17 |
| Vercel cron | ~30 runs per month | Derived | see inputs Inputs: 1 × 30 = 30 (one run a day, configured, vercel.json lines 3-7; a 30-day month) Read on 2026-10-17 |
| Hourly heal job | ~730 runs per month | Derived | see inputs Inputs: 24 × 30.4 ≈ 730 (one run an hour, configured, hourly-heal workflow lines 17-19; about 30.4 days a month) Read on 2026-10-17 |
| Hourly heal minutes | — | Unknown | hourly-heal workflow, lines 6-7: it assumes runs are free on public repos; the readme's licence line says private; the host setting is unverified Read on 2026-10-17 |
| Neon compute | $0.106 per Compute unit — The unit a serverless database bills its processing time in; one unit-hour is one unit running for one hour.-hour | Published price | owner's metered-resource table (Neon Postgres) Read on 2026-10-17 |
| Neon storage | $0.35 per Gigabyte — A billion bytes of data; storage is priced per gigabyte per month.-month | Published price | owner's metered-resource table (Neon Postgres) Read on 2026-10-17 |
| Neon usage | ~19 Compute unit — The unit a serverless database bills its processing time in; one unit-hour is one unit running for one hour.-hours per month | Estimate (the project's own) | build log, line 1926 (2026-08-30) Read on 2026-10-17 |
| Neon compute at that usage | ~$2.01 per month | Derived from an estimate | see inputs Inputs: 19 × $0.106 = $2.014 (19 Compute unit — The unit a serverless database bills its processing time in; one unit-hour is one unit running for one hour.-hours, projected; $0.106 per Compute unit — The unit a serverless database bills its processing time in; one unit-hour is one unit running for one hour.-hour, published) Read on 2026-10-17 |
| Flight status calls | 10 requests per minute | Published price | travel spec, line 40; the owner's metered-resource table (FlightAware row) gives the same Read on 2026-10-17 |
| Commute routing | $5 per 1,000 requests | Published price | commute spec, lines 200-204 Read on 2026-10-17 |
| Place search | ~$0.017 per Places autocomplete-session | Published price | env example, lines 120-122 Read on 2026-10-17 |
| Assistant spend cap | $5 per day per user | Set in the project's code | env example, lines 146-147 Read on 2026-10-17 |
Open-Meteo needs no key and is free (architecture doc, line 29); football-data is on its free tier.
Design decisions
- A deterministic, explainable score, no Machine learning — Software that learns its behaviour from examples instead of fixed rules.Each tile is scored at render time from data already loaded, with no new queries. The score line can always answer why a tile sits where it does.
- The engine never reorders the arranged gridIt only picks the Now stack and sinks tiles to Quiet, so the drag-arranged layout and the user's muscle memory survive.
- Modes hide noise, never emergenciesItems from another mode that score 85 or higher bleed through, two rows at most, so a hidden mode cannot bury something urgent.
- A manual override lasts until the end of the blockA cookie that expires when the current time block ends. The reason for that length was not recorded beyond a note calling it recommended.
- Refresh is lazy on page loadStale data refreshes as the page loads, which keeps the flight-lookup bill near zero. A daily cron and an hourly heal came later, because the free plan rejects more frequent cron runs.
Open questions
- Hourly heal minutes: the workflow assumes runs are free on public repos; the readme's licence line says private; the host setting is unverified, so the minutes used are unknown
- Google Maps Platform: the owner's metered-table row is marked verify, so map pricing is not verified beyond the repo's own figures
- Flight status allowance: the travel spec says 500 free calls a month; the owner's row names a monthly dollar cap and no count
- Edge requests after the fix: the 48-hour reading is still open (edge-requests write-up, line 280)
- Neon: no measured Compute unit — The unit a serverless database bills its processing time in; one unit-hour is one unit running for one hour.-hours, only the projection
- Claude: no per-call cost for the voice or assistant calls
- Oura: the owner's verify row names no project