Analytics
Most of the analysis happens before you ask for it. Background workers compute correlations, records, summaries and statistical models on a schedule, and the coach reads the result.
That ordering is deliberate. Deriving statistics inside a conversation means deriving them from whatever slice of data happened to be in context, which produces answers that are confidently wrong — a "personal best" that is only the best of the last thirty days. Computing ahead of time against the full history removes that class of error entirely.
The correlation engine
Runs across every module at once — habits, nutrition, wearables, bloodwork, genetics — on the deterministic tier of the background pipeline, every couple of hours. See when things run.
Known physiology is tested against your data. Rather than asserting that sleep drives recovery, the engine checks whether it does for you, and labels the result confirmed, contradicted, or confounded. A contradiction is often the more useful finding.
Statistical controls are applied. Partial correlation controlling for time trend and sleep, so a relationship that is really just "both improved over six months" does not present as causal. Autocorrelation-adjusted significance, because consecutive days are not independent samples. Multiple-testing correction, because testing forty metrics against each other will produce spurious hits by construction.
Results are stored as a graph. Edges carry the coefficient, the partial coefficient, lag, p-value, sample size, tier and provenance. Depth-2 traversal assembles mechanistic chains — sleep to recovery to next-day strain capacity — instead of asserting them.
Every edge is graded robust, probable, hypothesis or confounded, and that grade is the first thing to read — a coefficient without its tier is not a finding. The verdict on a relationship the engine expected to find is a separate vocabulary from the tier on one it discovered; confidence tier and prior status explain which is which and why filtering the graph for confirmed returns nothing.
Behaviour-to-marker links. Daily behaviours are tested against bloodwork markers over a biologically plausible exposure window, so a marker that responds over eight weeks is not correlated against yesterday's meals.
You can also ask for a pair nobody precomputed. On-demand analysis applies the same guards, and the result is always labelled a hypothesis regardless of how strong the coefficient looks — a single fished pair has no multiple-testing protection.
Precomputed models
The insights engine maintains a set of statistical models, queryable in the app and via get_insights over MCP:
| Model | What it answers |
|---|---|
| Readiness score | How prepared you are today, as a single score plus the contributors that moved it |
| Recovery formula | Which of your behaviours actually move your recovery, and by how much |
| Lead-lag relationships | Which metric moves first when two move together |
| Goal ETA | Projected arrival with Monte Carlo confidence bands |
| Streak survival | The probability a streak of a given length continues |
| Training load | Accumulated load against capacity |
| HRV baseline | Your personal baseline and deviation from it |
| Momentum | Whether you are building or slipping right now |
| Dose-response | Whether more of a behaviour keeps helping, or plateaus |
| Changepoints | Dates where a metric's regime actually shifted |
| Behavioural archetypes | Recurring patterns in how you operate |
Your recovery formula
Worth describing on its own, because it is the model most likely to be quoted back at you and the one with the most ways to be wrong.
It is a regression of today's recovery on last night's sleep and yesterday's behaviour, reported as recovery points per unit — "sleep duration: +6 recovery points per extra hour" — alongside the R² and the number of days it was fitted on. Prior-day strain and sleep duration are always in the model. Exercise, vitamins and eating quality join it conditionally.
Two guards decide what gets stated, and both exist because the model was confidently wrong without them.
A behaviour has to be logged often enough to model. An optional behaviour earns a slot only if it is actually recorded on at least 30% of the days being modelled. The reason: a habit you log a seventh of the time, with every unlogged day treated as "didn't do it", produces a coefficient that measures whether you were engaged enough to fill in the row rather than whether the habit did anything. That is not a subtle bias — it is how "prior-day vitamins: −9.9 recovery points" reached the coach as a finding. Below the floor the term is dropped rather than hedged, because there is nothing there to hedge.
A term the correlation engine calls confounded is labelled as such. Each surviving term is matched back to its edge in the correlation graph, and a confounded edge makes the coefficient read [confounded — not a direct effect] wherever the formula is stated. The coefficient is real and stays in the model; what it is not is a lever you can pull. A term the engine has no edge for is left plain rather than guessed at — the label is only ever added, never inferred.
R² is in-sample fit. It describes how well the model explains the history it was built from, which is not the same as how well it predicts tomorrow.
Facts and records
An all-time fact index per metric: first and last recorded day, minimum, maximum, lifetime total where a total is meaningful, current and best streak, and 30- and 90-day rolling averages.
Coverage is derived from the metric registry rather than hand-maintained, which is what stops it from silently omitting a group of metrics — an earlier hand-written version omitted every WHOOP column, and the coach reported bests that were nowhere near the true maxima.
Direction is declared per metric, because it is not inferable. Lower is better for resting heart rate and mile time. Higher is better for HRV. Weight is deliberately neither, because whether up or down is better depends on your goal, not on the metric.
Summaries
Narrative rollups written by the summarization pipeline: weekly, monthly, quarterly and yearly reviews, lab and methylation interpretations, mission analysis, personal records, and a cross-module correlation narrative.
These are embedded alongside individual days, so a question about a period retrieves the period rather than reassembling it from ninety rows.
Charts
Trends, distributions and comparisons over any tracked metric, rendered in the app. Bloodwork markers get sparklines against their reference ranges.
When things run
The pipeline is split in two by cost, which is the thing to understand if you are reasoning about how fresh a number is.
| Worker | Schedule | Does |
|---|---|---|
| Derived tier | Every 2 hours | Correlations, the insights models, personal records, period summaries, the all-time fact index, labs, methylation and supplement pipelines |
| Generative tier | 01:00, 05:00, 10:00, 14:00, 17:00, 21:00 UTC | The steps that call a reasoning model: meal enrichment, the narrative journey, mission analysis, and the belief check against your learnings |
| WHOOP sync | Hourly, per your own clock | Pulls at 05:00–09:00 then every two hours to 23:00, in your timezone |
| Embeddings | 06:00 UTC | Batch-embeds anything flagged during the day |
| Learning maintenance | 04:00 UTC | Decay, expiry, consolidation |
Why the split. Correlations and insights are seconds of arithmetic; mission analysis alone is allowed ten minutes of reasoning-model time. Running them in one loop meant the cheap work inherited the expensive cadence — a correlation refreshed only as often as the prose did — and one slow account could exhaust the budget before the rest of the queue was reached. Separating them lets the arithmetic run several times a day.
WHOOP sync is on your clock, not UTC. The cron fires hourly and each account is pulled when its own local time reaches one of the scheduled hours, so everyone gets the same schedule in their own day wherever they live. It is hourly through the morning because that is when WHOOP scores the night's sleep and the day's recovery, then every two hours to follow strain as it accumulates. The overnight stretch is skipped: nothing new is scored while you are asleep.
Days are also embedded inline as you save them; the cron pass is a fallback for anything that failed or was written while the embedding service was unavailable.
Data quality
Analysis is only run on values that can carry it. WHOOP recovery from the calibration period and sleep stages from a night with a significant sensor gap are suppressed for analysis while remaining visible in the ledger exactly as reported. See quality gating.
Related
- Concepts — tiers, provenance, the feature store
- MCP tool reference — querying all of this directly
- Mission Statement — goal progress and causality