Chronicle

Thirty seconds a day becomes a searchable life.

Thirty seconds a day — one voice note or one photo — transcribed, embedded, and turned into a timeline you can ask questions of rather than scroll.

30s
the entire daily ask
768
dimensions per memory
3
runtimes in one product

A Flutter PWA with a Python agent behind it

The client is Flutter compiled to web and installable as a PWA. Capture goes to Supabase Storage, Groq whisper-large-v3 transcribes it, and Jina produces 768-dimension embeddings that land in Postgres with pgvector. Supabase Edge Functions handle the per-request work; a Python service on Vercel runs the AI agent and an MCP server over the same data, so the timeline is queryable by a model as well as by the app. Firebase Cloud Messaging handles the daily nudge, because a journal nobody is reminded about is a journal nobody keeps.

Decisions

One capture a day, deliberately

The constraint is the product. An app that accepts unlimited entries becomes a backlog; an app that asks for thirty seconds gets used. Everything else — search, the weekly narrative, the timeline — is built on the assumption that entries are small, regular and never edited.

Three runtimes, chosen not inherited

Dart for the client, TypeScript for Edge Functions, Python for the agent and MCP server. More surface than a single-language stack, justified by each doing what it is genuinely best at — and it is the reason the project reads as an integration problem rather than an app.

MCP as a first-class interface

Exposing the timeline over the Model Context Protocol means the data is not locked behind the app’s own UI. A journal you can only read through one client is a smaller thing than one a model can reason over on your behalf.

Two failures that only showed up in production

Groq decommissioned llama-3.3-70b-versatile on 2026-08-16. It failed at runtime rather than at build, so the chat agent and the weekly narrative simply went quiet while everything still deployed green. Separately, pubspec.lock was not committed — CI resolved fresh packages on every run, a newer supabase_flutter deprecated anonKey, and every Dependabot PR went red at once. Both have the same shape: the thing that broke was outside the repository, and the repository had no way to notice.

Built with

  • Flutter Web PWA
  • Supabase · pgvector
  • Groq whisper-large-v3
  • Jina embeddings
  • Vercel Python · MCP
  • FCM