A Shared Calendar on the TV

One calendar for my wife and me: on our phones, and on the TV, where a Raspberry Pi shows the day at a glance. It runs on my own Mac, and I built it in two days with Claude Code.

Illustration: a living room in the evening, the TV showing coloured blocks like a weekly planner, a tiny circuit board on the shelf below

I wanted one calendar that my wife and I could both see: on both our phones, and on one screen in the house that shows the day without anyone opening anything.

I had the same rule as for texting my own AI: it lives on my own hardware, and only our own devices can reach it. So I asked Claude Code to build it, and a Raspberry Pi to put it on the TV.

🗓️
The calendar A small web app on the Mac: FastAPI and SQLite, plain JavaScript, installable on a phone like an app
✉️
Invites from email Meeting invites are picked up from Mail on the Mac, read only. Nothing is sent, moved or deleted
🔗
Shared links One private link per person, with exactly what they may see and do
📺
The wall display A Raspberry Pi on the TV shows today and the next three days, full screen, all day

Two Days, Twenty-Two Commits

The first commit was the whole back end: events, repeat rules, sharing, email sync and tests. Then came review. A security reviewer agent read the code in several rounds, and every finding was fixed before the next one. By the end there were 145 tests, and a script that opens every screen at every size, in light and dark, and fails on low contrast, clipped text or a button too small to tap.

Repeat rules took more care than I expected. “Every Tuesday and Thursday until December 15”, “the last Friday of the month”, and the question every calendar has to ask when you change one meeting in a series: this event, this and following, or all events?

Sharing It With My Wife

Sharing works with links, one per person. Each link says what that person can do: see titles and places, or only “Busy”; leave comments; block time of their own. A link can expire, and turning it off works at once. The link is shown one time when it is made, and the server keeps only a hash of it.

My wife uses a link that sees the full details. Time blocked through a shared link shows up on my calendar hatched and labelled with the person’s name, so a plan can be seen before it clashes.

A bug on the Home Screen. A shared link saved to a phone’s Home Screen opened my sign-in page instead of the shared calendar. The app had one manifest for everyone, and it said “start at the front page”. Now each shared link, and the TV’s link, gets its own, so the icon opens the calendar it was saved from.

Invites You Can Trust

Every fifteen minutes the app asks Mail on the Mac for recent messages that look like invites, and reads their calendar parts. The interesting part is not reading them. It is deciding who is allowed to change an event by email, because the “From” line of an email is easy to fake.

So an invite only counts as coming from its sender when the email provider checked it on arrival, and the app reads that check only from the part of the headers the provider itself wrote. A change or a cancellation is accepted only from the person who sent the original invite. Anything it cannot confirm still appears, once, with a yellow “Check this invite” note.

The TV

The wall display: a large clock and the date on the left, today's events on the right with what is on now, and the next three days along the bottom
The wall display, shown here with made-up demo events.

The display is its own page, made for a screen across the room. A large clock and the date. Today, with all-day items first, what is on now and what is next, finished events folded into one line, and “+2 more” when the day is too full. Then the next three days. It refreshes every minute, stays dark, and never needs a touch. On a screen turned on its side it switches to a portrait layout by itself, and a few photos rotate on it between updates.

It opens with its own read-only link, so the TV can show the day but can’t change anything.

The Raspberry Pi

The Pi’s whole job is to open one page and keep it open. That turned out to need a few steps:

  1. 01
    It powers on and signs in by itselfSo after a power cut the TV comes back to the calendar with nobody touching it.
  2. 02
    It waits for the MacA small script checks the Wi-Fi, the private network and the calendar’s health page first, so the screen never opens on an error.
  3. 03
    Chromium opens full screenKiosk mode: no bars, no pop-ups, no “restore pages?”.
  4. 04
    If it ever closes, it comes backThe script starts it again five seconds later.

The display link carries a secret, so it never appears in a script or a log. It lives in a file on the Pi that only its own user can read. To change it, I copy the new link on the Mac and run one command: it sends the clipboard to the Pi over SSH and restarts the screen.

The bug that froze the whole Pi. The whole Pi froze. The system log said the SD card was stuck being busy. Chromium writes to its profile and cache all the time, and the card couldn’t keep up. The fix was to give Chromium a profile and cache that live in memory instead, emptied at every boot. The card now has almost nothing to do.

One small one, too: the Pi’s region is set to the UK, which means a 24-hour clock, so the link asks for a 12-hour clock itself.

Keeping It Private

Only our devices. The app listens only on the Mac itself. Our phones and the Pi reach it through Tailscale, my private network, and it is never published to the open internet.

Links, not passwords, for guests. Shared links are long random tokens, stored only as hashes, with their own limits on how often they can be tried. “Sign out everywhere” ends every session at once.

Nothing loaded from elsewhere. No fonts, scripts or styles from other sites. The page only runs what the Mac itself serves.

My AI Can Use It Too

The calendar has an MCP server, so Claude Code and my AI engine can list events, find free time on a day, add an event or block time, the same way I would. “Find me an hour on Thursday” is now a question, not a search.

The best family calendar is the one you don’t have to open.

What’s Next

A proper sign-in for my wife, instead of a link. Testing invites from real email providers, not only the ones the tests describe. And trying the drag-to-move gesture on a real iPad, which so far has only been tested in a browser.

The calendar, the Pi setup and this article were built with Claude Code.