A longitudinal tracker for my indoor Kratky garden. Each phone-call check-in becomes a dated snapshot file — old snapshots are never edited, so the record builds up over time instead of getting overwritten. Posts on my site embed a snapshot via <iframe>.
/— timeline of all snapshots + the latest one inline/s/:date— one snapshot, with "what changed since last time" once there's history/embed/:date— chrome-less view for embedding in a blog post/api/snapshots,/api/s/:date— JSON/source— this code
The personal-site renders an iframe code-fence. In a blog post:
```iframe height=560
https://charlies-farm-log.val.run/embed/2026-06-14
```
Older posts embed the default deployment URL
(https://dcm31--6ac4f166685411f1858c1607ee4eb77e.web.val.run/embed/<date>).
That URL still resolves — adding the custom domain didn't disable it — so existing
embeds keep working. New posts should use the charlies-farm-log.val.run form.
When I get back on the phone and describe the garden, the AI:
- adds
data/<YYYY-MM-DD>.json(a new file — never edits the old ones), and - adds that date to
SNAPSHOT_DATESindata/loader.ts.
Plant keys are stable across snapshots, so the same plant can be followed over
time and diff() can show what changed. Snapshot schema:
{ "date": "2026-06-14", "title": "Pre-trip inventory", "note": "…", "plants": [ { "key": "tiny-tim-40l", "name": "\"Tiny Tim\" dwarf tomato", "type": "Fruit", "vessel": "The prize pot", "volL": 40, "status": "About to flower", "flags": ["star"] } ] }
flags: "star" (highlight) and "attention" (needs care — shown with ⚠). volL may be null.
main.tsx— Hono server + all viewsdata/loader.ts— reads snapshot files, sorts newest-first, computes diffsdata/<date>.json— one snapshot per file
Crons/reminders, photos, succession scheduling, and any multi-user/login stuff — this is just for me, kept deliberately small.