PROJECT / 2026
Dash
A private operating system I built to centralize the different systems of my life.
Dash started because I wanted a finance dashboard across all my bank accounts. Three weeks later I had voice input, task management, calendar sync, health ingestion, semantic memory, agentic review queues and 24/7 background jobs.
Explore Dash ↗This version runs on synthetic data

01 / THE SYSTEM
One state layer for everything
Data inputs to the system flow through server-owned adapters where they are normalized into structured records in Postgres, then they can be surfaced through Home, Tasks, Health, Finance, Review, or queried through Brain. I kept as many calculations, rankings and canonical records deterministic, with AI models being called for fuzzy inputs such as classification, embeddings, or search.
Importantly, the models can interpret data, but not edit the original inputs.
I started out by hosting the system and scheduled jobs in the cloud and eventually started moving the heavier workflows toward a private always-on worker.
Capture
Web capture · Telegram / voice
Calendar
Google Calendar
Health
Apple Health · Strava / Hevy imports
Finance
Plaid · local/private imports
Node server / trust boundary
API routes · authentication · single-user / owner identity · input validation
Server-side secrets · connector credentials · adapters · policy / action gating
Capture / CRM
Captures → classification / extraction → confidence / Review → tasks, people, goals, decisions, links
Health
Ingestion → sample normalization / reconciliation → raw / canonical samples → rollups / daily projections
Calendar
Incremental sync → cached calendar state → contextual read models
Finance · protected
Finance module → reconciliation → deterministic balances, liabilities, utilization, investments
Supabase / Postgres + RLS
Durable structured application stateTasks · captures · people · goals · decisions · links
Health samples / rollups · calendar cache / events
Reviews · notifications · audit / action state
Domain-owned records; distinct reconciliation and access semantics.
Deterministic logic
Finance math · task ranking · queue logic · health rollups · read models · derived state
↓ server-owned outputsAI interpretation
Classification · field / people / fact extraction · review refinement · embeddings · search / Ask synthesis
↑ structured output → policy gate → stateOriginal inputs stay intact.Memory / Brain
Sanitized summaries / memory_chunks → embeddings → pgvector → similarity search → cited Ask
Read models → product surfaces
Home: cross-domain aggregator
Tasks · People · Health · Finance · Review · Brain · Settings
React / TypeScript / Vite UI
Consumes server-owned read models through the Node API.
Uncertain / low confidence
Policy gate → Review
Safe / reversible internal actions
Controlled execution → undo / audit where supported
02 / STRUCTURED STATE
Turning messy inputs into something I could trust
I imagined the system as being able to speak into my phone anytime I wanted and say something like "I need to finish the mechanics problem set Friday" or "Just met Costanza from IBM" and it would automatically go where it belonged.
The model pulled structure out of the sentence—what it was, when it was due, what it related to—then Dash would store the hard deadline, decide the day I should focus on it and its current priority. That meant ordinary code would rank the queue, and if a capture was uncertain, it would route to Review instead of silently committing it.
- capture
- classify
- extract
- confidence
- task state
- rank
- queue


An update isn't always an event
My health data broke the first version of that system because repeated Apple Health exports looked like new records, but they were really just updated snapshots. Because my system was treating every upload as append-only data, there were duplicates everywhere and rollups no longer matched reality. To fix this, I added a decision matrix for what an incoming record meant—event, update, or snapshot—and reconciled it before deriving the daily state.

- snapshot
- append
- upload again
- append
- double count
- snapshot
- reconcile
- canonical samples
- daily rollup
03 / MEMORY + AUTONOMY
Useful AI needs boundaries
The Brain is my attempt at building a vector DB of my life. I embedded sanitized summaries of existing state into pgvector, then kept references back to the original records, which allowed me to create a chat where answers can cite the original input they were using.
- canonical state
- sanitized memory chunks
- embeddings
- pgvector
- similarity search
- cited answer

Adding an agent automation layer created a new problem: being able to do something didn't mean Dash should deploy agents automatically. I solved this by implementing a confidence scale where reversible actions could move on their own, but uncertain or more consequential changes went through Review, with thresholds and undo built into the action flow.
review
safe action
↓
undo / audit

04 / PRODUCTION
The one-minute sync that wrecked the database
I had about twenty calendars to keep fresh and Google's API quotas made a one-minute sync look cheap.
Turns out I was measuring the wrong system.
There was a huge bottleneck downstream, where scheduled functions started overlapping, making Calendar consume roughly 83% of the system's entire scheduled runtime while the database was doing an absurd amount of repeated work: roughly 47.6 million calendar_events updates against only ~4.3K live rows.
- calendars
- ~20
- initial cadence
- 1 min
- runs / 6 hours
- 100
- timeouts
- 99
- scheduled runtime
- ~83%
- event updates
- ~47.6M
- live rows
- ~4.3K
- Google quota looked safe
- poll every minute
- overlapping jobs
- repeated DB writes
- CPU / I/O saturation
- stop + recover + slow down
So I shut the sync down, let Supabase recover, dropped the cadence to every fifteen minutes, and now I know not to size a system against just the API quota.
05 / WHAT I LEARNED
I added integrations faster than I defined to the existing system what they meant
Looking back, this was clearly the recurring mistake. I kept adding APIs because it was easy, but then failed to immediately define to the system whether their data was authoritative, whether a repeated value was an event or a snapshot, how to reconcile conflicts, and what to do if that part of the pipeline failed.
- source identity
- idempotency
- event / update / snapshot
- normalization
- reconciliation
- provenance
- failure state
Planning out integrations involved more than just connecting APIs; it's about deciding how an external fact is allowed to become an internal truth.
This system is retired.
By October I wasn't actively developing Dash anymore, but keeping the live version meant maintaining its database, credentials, scheduled jobs, and private integrations. So I decided to retire the backend and rebuild the frontend as a synthetic archive instead. It looks and behaves like the final Dash UI, but it is no longer connected to my live data or private services.
Explore Dash ↗