Health Dashboard Part 6: Closing the Loop with Body Composition

Overview

The final section of Part 5 listed what was still missing:

Weight trend. MFP measurements (body weight over time) would complete the picture — you’d see nutrition, training load, and what the scale is doing in one place.

That gap is closed. Withings body composition — weight, fat%, muscle mass, fat-free mass, bone mass, hydration — is now present across the dashboard, and most importantly wired into the Nutrition × Exercise tab’s AI coach evaluation.


The data source

The Withings scale produces a richer reading than a standard weight scale. A single step-on generates six body composition values: weight, fat ratio, fat mass, fat-free mass, muscle mass, bone mass, and hydration. These come back from the API as typed measurement records — integer values with a unit exponent — merged per day into one clean dict.

The dashboard imports WithingsClient directly, the same pattern as StravaClient and MFPClient. It gets the SQLite cache for free: 24-hour TTL for measurements (scale data doesn’t update mid-day), 15-minute TTL for today’s activity data.


Where it appears

Today & Yesterday — a compact card below calorie balance shows the most recent scale reading: weight, fat%, muscle. No trend here since you’re looking at a single day, but you always know when the last reading was taken.

Last 7 Days — a full body comp card sits in the weekly summary block, above the per-day breakdown. If there are two or more readings in the 7-day window, each field shows a delta vs the oldest reading:

Weight     74.60 kg   (+0.15 kg)
Body Fat   16.6%      (−1.0%)
Muscle     59.38 kg   (+0.87 kg)
Fat-Free   62.22 kg   (+0.55 kg)

Last 30 Days — same full card, covering the full 30-day window. This is where meaningful trends appear: a full month of training and nutrition data has enough resolution to see if fat% is moving.


The Nutrition × Exercise tab

This is where body composition matters most. The tab already had nutrition averages and calorie balance. What it was missing was the outcome: is the combination of food and training actually doing what you intend?

Body composition now anchors the top of the tab — before the 15-day and 30-day sections — as a standalone snapshot:

⚖️ Body Composition

Most recent reading: 2026-05-29. Trend deltas vs earliest reading in window (2026-05-01).

Weight     74.60 kg   (−0.60 kg)
Body Fat   16.6%      (−1.0%)
Muscle     59.38 kg   (+0.87 kg)
Fat-Free   62.22 kg   (+0.67 kg)
Fat Mass   12.38 kg   (−1.50 kg)
Bone Mass   2.82 kg   (−0.01 kg)
Hydration  41.52 kg   (+0.44 kg)

That snapshot is followed by the 15-day and 30-day correlation sections, each with their workout-vs-rest-day nutrition comparison and energy balance cards.


The AI coach evaluation

The correlation evaluation was already analyzing prior-day carbs vs next-day pace, protein vs recovery, and calorie balance sustainability. It now has a fifth dimension: body composition.

The evaluation context passed to claude -p includes the most recent scale reading and the trend deltas for the period:

### Body composition (most recent reading: 2026-05-29)
- weight 74.6 kg | body fat 16.6% | muscle 59.4 kg | fat-free mass 62.2 kg
- Change over period: weight −0.6 kg | body fat −1.0% | muscle +0.9 kg

The coach prompt adds a fifth instruction: assess whether the calorie balance and macros are consistent with the body composition trend the scale is showing — call out if the data supports or contradicts the athlete’s likely goals.

This closes the loop that the previous version couldn’t close. A typical evaluation might now read:

The 30-day calorie deficit averaging 380 kcal/day is consistent with the 0.6 kg weight loss. More interesting: fat mass dropped 1.5 kg while muscle increased 0.9 kg — a body recomposition pattern, which aligns with the protein intake averaging 142g/day (1.9g/kg bodyweight). The deficit isn’t aggressive enough to risk lean mass loss at this protein level. The only gap is the two weeks in early May where protein dropped below 110g/day — those weeks show slower pace and higher HR, but the scale data doesn’t show any muscle loss, suggesting the window was short enough not to affect composition.

That kind of analysis — crossing nutrition, training performance, and body composition in the same paragraph — wasn’t possible before.


How evaluation generation picks it up

The generate_evals.py script runs at dashboard startup via ./start. It already fetches Strava and MFP data to build the correlation context. It now also fetches Withings measurements for the period and passes them into build_correlation_context():

withings_month = get_withings_measurements(MONTH_START, TODAY)

_generate_corr("15d", "Last 15 Days", all_month, nutrition_month,
               FIFTEEN_START, withings_month, force)
_generate_corr("30d", "Last 30 Days", all_month, nutrition_month,
               MONTH_START,   withings_month, force)

The Withings call is cached at 24 hours, so it adds no meaningful latency to startup.


What the dashboard looks like now

Five tabs, three data sources, AI evaluations at two layers:

Tab Strava MFP Withings
Today & Yesterday compact card
Last 7 Days full card + trend
Last 30 Days full card + trend
🏃 Running
🔗 Nutrition × Exercise snapshot + in AI eval

The running tab doesn’t include body composition because the relationship there is indirect — body comp is an outcome of the nutrition-training combination, not a run-level metric. It belongs in the correlation view.


What’s still open

Workout type differentiation. The Nutrition × Exercise tab treats all activities the same. A strength session has a different relationship with protein and calories than a 15K run. Separating by sport type would sharpen the correlation analysis.

Longer windows. Thirty days is still the ceiling on data fetching. Body composition changes slowly — a 60 or 90-day window would be more useful for spotting genuine trends vs week-to-week noise.

Withings sleep data. The MCP server already exposes get_sleep_summary. Sleep quality affects both training performance and body composition. It’s the next obvious addition to the correlation tab.

The core loop — did what I ate and how I trained this month show up on the scale — is fully answerable now. The dashboard runs locally, requires no cloud infrastructure beyond the original Strava, MFP, and Withings accounts, and generates coaching evaluations via the Claude CLI already running in the terminal.

Part 4 covers the evaluation architecture in detail. The Withings MCP that powers the body composition data is described in the companion post.