Architecture
Repo layout
Section titled “Repo layout”client/ Expo + React Native client for web, iOS, Android, and Macserver/ Fastify + better-sqlite3 API servershared/ Task/ListDef/FolderDef types and the quick-add parser, used by both sidescustom_components/yarukoto/ Home Assistant integration (installed through HACS)homeassistant-tests/ its tests, run with pytest-homeassistant-custom-componentKeeping the types in shared/ means the client and server can’t drift apart silently — the
server compiles against the same Task shape the UI uses.
How sync works
Section titled “How sync works”The client is the source of truth for what you see; the server is the source of truth for what persists. Every mutation applies to local state immediately and marks the record dirty. A loop pushes dirty records and pulls changes every 5 seconds.
Conflicts resolve last-write-wins per record, compared on updatedAt. Deletes are soft
(deletedAt), so a deletion propagates to other devices instead of the record reappearing on the
next pull. A pull whose cursor predates the retention window is rejected, and the client re-hydrates
fully — otherwise a client offline long enough could miss a hard delete and resurrect the task.
Two timestamps, deliberately. updated_at is stamped by the client that made the edit and is
only ever used for that last-write-wins comparison, because resolving a conflict wants to know when
something was edited. server_updated_at is written by the server on every accepted upsert, and
is the only thing sync cursors compare against.
They have to be separate. Cursors handed out by GET /sync come from the server’s clock, so
filtering on a client-stamped column compares two clocks that are never quite in step: an edit made
on a device running a few seconds behind the server arrives already older than a cursor another
device is holding, and > skips it on every subsequent pull. The record sits on the server, correct
and complete, and simply never reaches the other client until something happens to touch it again.
Sync appears to work “most of the time”, which is the worst way for it to fail.
Design origins
Section titled “Design origins”This started as an HTML/CSS prototype from Claude Design. The original handoff bundle — the design files and the conversation that produced them — has been removed now that the app itself is the reference; it was never used at build time. It remains in the git history if you ever want it back.
