← All posts

TONND now sees what you eat. The loop is closed.

Wahed Hemati·
fatsecretnutritionfood-trackingopen-sourcehealth-trackingcalorie-tracking

I logged my dinner in FatSecret last night. This morning I opened TONND and the meal was sitting next to my Hevy workout from yesterday, my Renpho weigh-in, and my Fitbit recovery score. Same screen. Same timeframe.

That sounds boring. It's the whole point.

For months I've been writing about putting health data in one place. Sleep next to HRV next to weight next to workouts. A recovery score you can actually trust because it isn't pulled from a single app's pet metric. The loop I was missing the whole time was the input side. Food.

Nutrition is finally in.

Why nutrition mattered more than I admitted

When I first built TONND, I lumped food in as a Phase 1 thing that would land "eventually." Then Google killed the Fitbit web dashboard and I promised calorie tracking was next. Then I shipped Hevy. Then the MCP server. Then body composition cards. Food kept slipping.

It wasn't laziness. It was the API problem.

If you ate 2,800 calories yesterday, slept five hours, and your HRV dropped from 48 to 27, the three numbers tell you something. One of them on its own is noise. Two of them is a hint. Three of them is a story. That story is what the dashboard exists for, and it had been incomplete the whole time.

The MyFitnessPal problem

The obvious move was MyFitnessPal. Most people I know use it. The interface is fine, the food database is huge, and it has been around forever.

MyFitnessPal doesn't let you read your own food diary through their public API. They have a partner program, and the partner program is closed to small projects. Cronometer is the same. Both are paid B2B integrations that need a business deal, lawyers, and revenue share negotiations. Not a weekend project.

FatSecret was the only path left. Their Platform API is public, they have a real food database, and the food_entries.get endpoint actually works without a partnership signature.

The catch: it uses OAuth 1.0a.

A short detour into 2010

OAuth 1.0a is the protocol everyone replaced with OAuth 2.0 fifteen years ago. It requires HMAC-SHA1 signing of every request, a three-legged dance with a separate request token, and a verifier code the user types back in. It's the kind of thing you read about in a postmortem, not the kind of thing you implement in 2026.

FatSecret has an OAuth 2.0 endpoint, but the client_credentials flow they expose only reads their generic food database. The user's diary requires the legacy three-legged OAuth 1.0a flow. There's no workaround.

So TONND now speaks OAuth 1.0a, signed via oauthlib, with the request token stashed in an in-memory store during the redirect dance. Fernet encryption on the persisted access token and access token secret. The full ceremony, just to read what you had for breakfast.

It works. That's what matters.

What you actually get

Two things show up after you connect FatSecret in the Sources screen.

The first is your per-meal food diary. Every entry has the meal name (free text, whatever you typed when you logged it), the meal slot (Breakfast, Lunch, Dinner, Snack), calories, the four macros (carbs, fat, protein, fiber), plus sugar, saturated fat, mono and poly unsaturated fat, cholesterol, sodium, calcium, iron, potassium, vitamin A, and vitamin C. About 20 fields per row. Stored in a typed food_entries table you can query through the API.

The second is a daily aggregate. One row per day, summing calories, carbs, fat, protein, and fiber. This lives alongside the per-meal entries so you can pull either grain depending on the question you're asking.

The daily aggregates land in the same daily_nutrition table the rest of the dashboard reads from. Food shows up on the same chart strip as steps, sleep, and weight, on the same 7/14/30 day toggle. Nothing special. It just behaves like everything else.

The deletion problem (and why you can't fully solve it)

FatSecret's API is date-scoped. You ask for entries on a given day and get back the current state of that day. No event feed, no "tell me what changed since timestamp X" endpoint. If a user deletes a meal a week later, the only way to learn about it is to refetch that week.

TONND syncs each day with a 2-day window (today and yesterday). Anything deleted inside that window gets soft-deleted in the database, so the aggregates recompute correctly. Anything deleted older than 2 days stays in TONND as if it still existed. It's a known limitation, documented in the sync code, and acceptable for v1 because aggregation only re-runs for the sync window anyway.

If it bothers someone enough, they can trigger a manual backfill. Capped at 30 days.

What Claude can do with this

The MCP server I shipped last month already exposes ten tools that let Claude query your TONND data directly. Nutrition just joined the list.

You can now ask Claude things like "what did I eat on days my HRV was over 50?" or "did my protein intake change in weeks I gained weight?" and it will pull from get_nutrition_daily and get_food_entries, cross reference with get_vitals and get_body_composition, and answer in plain language. No spreadsheets, no copy paste, no separate apps.

This is the part that pulls everything together. As I wrote in the HRV piece, individual day-to-day readings of any health metric are mostly noise. What matters is the pattern over weeks, correlated against what you were actually doing. The "what you were actually doing" now includes the food side.

Where this goes next

The nutrition data is in the database. Daily aggregates are wired into the dashboard storage layer. The MCP server can read it. The API exposes it at /api/v1/nutrition/daily and /api/v1/nutrition/entries.

What isn't built yet: a nutrition card on the dashboard front end. The data is there. The chart isn't. That's the next thing.

After that, weekly training and nutrition plans with KPIs. Not the "drink more water" kind. The kind that says "your protein has been under 130g for three weeks and your strength on heavy compound lifts is flat, the dashboard should probably flag that." Specific. Useful. Boring.

If you want to try it, tonnd.com is the live app. Code is on GitHub. Discord is discord.gg/3qmrFpwzpE if you want to follow along.