Fitbit Air Coach
Your wearable knows a lot about you. Your resting heart rate, how you slept, whether you actually moved today. But that data sits in a dashboard you never open, next to advice so generic it's useless ("aim for 8 hours!").
I wanted the opposite. No app, no dashboard, just a text thread. You connect your health data once, then text things like "how did I sleep?" and get an answer in your real numbers, compared against your own recent baseline. It runs on Claude.
The interesting engineering problem is trust. An AI talking about your health is exactly where a made-up number is least acceptable. So the whole thing is built around one rule: the model can only speak from data it actually has.
One text, start to finish
A single message runs this pipeline:
The webhook answers instantly and does the real work off to the side, ignoring the bot's own messages and skipping any text it has already seen. Standard hygiene for anything living behind someone else's webhook.
Why it can't make up a number
Every turn, Claude gets a system prompt that's three things bolted together: who it is, a hard set of rules, and a compact snapshot of the day's data and baselines.
Rules:
- Speak only from the provided data or the tools. Never invent numbers; if something is missing, say so.
- Cite real figures and the user's own baseline (e.g. "resting HR 54, a touch above your 51 avg").
- Not a doctor: no diagnoses. If something looks concerning, gently suggest seeing a clinician.But rules alone don't stop a model from confabulating. The real safeguard is where the tools read from.
Claude gets two tools, "get me a day" and "get me a metric's trend," and runs a short tool loop. The trick: both are answered from an in-memory snapshot synced at the start of the turn, so no tool call ever hits the network.
Fast, because there's no round trip mid-conversation. And impossible to hallucinate a number, because there's no number to fetch that wasn't already fetched.
Measured against you, not a textbook
Generic advice is easy. Personal advice needs a baseline. So for each metric I compute the average of your last seven days, not counting today, plus a week-over-week change, and I track how many days actually had data so it won't over-claim on thin evidence.
That's the difference between "your resting heart rate is 54" and "54, a touch above your 51 average this week." The second one actually means something.
Auth you'd trust with health data
Because this reads real health data, the login path is hardened, not hacked together. It's a proper OAuth flow with PKCE, offline access, and read-only scopes. Access tokens refresh about a minute and a half before they expire, and if the provider hands back a rotated refresh token, that gets swapped in. The one secret worth keeping, the refresh token, is stored encrypted with AES-256-GCM. Everything else lives in memory and is fetched fresh each turn.
Onboarding is a single magic link the bot texts back to anyone who isn't connected yet, with a guard so it can't spam you.
Being honest about it
Two things I'm not claiming. First, the low-level fetching and translating of the health data leans on a shared library rather than being written from scratch here. The original work is the AI layer: the grounding, the in-memory tool loop, the personal-baseline analysis, the auth flow, and the iMessage delivery. Second, it's a coach, not a doctor, and it's built to defer anything concerning to a real one.
The thing I'll carry into the next project: for an LLM over sensitive data, "don't hallucinate" isn't a line in a prompt. It's an architecture. The prompt says never invent a number. The system makes it impossible by only ever handing the model data it already has.