Engineering note · May 2026
Most "smart" calorie trackers aren't smart at all. They calculate a TDEE once at signup using a 1919 formula, tell you to eat 500 kcal under it, and never look at your data again. If the number was wrong — or if your body adapts, as every body does — you find out by stalling for six weeks.
Healthify doesn't do that. The engine watches four signals every day and re-tunes your plan on a weekly cadence backed by a 28-day smoother. This piece walks through every formula, the safety clamps that keep it sane, and an 8-week worked example. No marketing fluff — every number below is the same number the app is computing right now.
On this page
| # | Pillar | Cadence | What it adapts |
|---|---|---|---|
| 1 | Weekly TDEE recalibration (EWMA + OLS slope smoother) | Once per ISO week | Your daily calorie target |
| 2 | Real-time daily adjust | Every HealthKit sync | Today's calorie ceiling |
| 3 | Body State macro tilt | Every morning | Today's protein / carbs / fat split |
| 4 | Deficit classification | Continuous | The recommendation card you see |
The pillars stack. Pillar 1 sets your weekly anchor. Pillar 2 nudges that anchor up or down based on how active today actually was. Pillar 3 shuffles macros around the new calorie number based on your recovery and exertion signals. Pillar 4 reads where the day landed and tells you whether to add a meal, hold, or back off.
The textbook formula for energy balance is dead simple:
ΔWeight (kg) = (Intake − TDEE) × days / 7700
7700 kcal ≈ 1 kg of fat. Rearranged, if we know your actual weight trend and your actual logged intake, we can solve for TDEE directly:
TDEE = avgIntake − (slope_kg_per_day × 7700)
That's the whole game. The hard part is that both inputs are noisy:
A naïve "first weight minus last weight over two weeks" estimate is unusable. It will swing your calorie target by ±400 kcal week-to-week and you'll never trust it.
A two-stage smoother modelled on the MacroFactor whitepaper (services/expenditureSmoother.ts):
0.25 × today + 0.75 × yesterday's smoothed value. Filters single-day water swings without lagging real fat-mass change by more than a few days.Chart 1. 28 days of weigh-ins with realistic ±0.6 kg daily noise. The raw line wanders up to 1.5 kg over a single day; the EWMA captures the underlying 0.65 kg/week downward trend that the OLS fit then reads cleanly.
We call this the "Kalman-style" path internally because it carries forward a state estimate the way a Kalman filter does, but the math is simpler — an EWMA on the weight series feeding an OLS slope — not a true Kalman update. We refuse to trust this path until all three gates are met:
Without these, two dense weeks of daily weigh-ins would silently flip the model on and you'd
get a confident-looking number built on a fundamentally short history. Until the gates pass
we use a deliberately conservative "fallback" path: a simple 14-day weight delta + 7-day
intake average. The fallback is honest about its limits — it ships with a low
confidence label and a "Based on N days" footer chip in the UI.
Even with a clean TDEE estimate, we never just slam the user's calorie target. The proposal goes through three safety layers:
After the proposal, the calorie target is recomputed into a fresh protein / carbs / fat split using the same heuristics as initial onboarding, so the macros stay internally consistent with the new ceiling. The user always sees the proposal first and taps Accept or Dismiss. We never silently rewrite goals.
Pillar 1 sets your weekly anchor. Pillar 2 acknowledges a fact every serious lifter knows: a 12k-step day and a 3k-step day are not the same day. The TDEE smoother averages those out across the week, but you still want today's plan to reflect today's reality.
Formula (computeAdaptiveCalorieTarget):
rawDelta = todayActiveCalories − baselineActiveCalories clampedDelta = clamp(rawDelta, −500, +500) nominalDelta = round(clampedDelta / 25) × 25 adjustedTarget = max(1200, baseTarget + nominalDelta)
baselineActiveCalories defaults to 400 kcal — roughly the active-energy
output of a moderately-active office worker walking 7-8k steps. The calorie target rounds to
the nearest 25 kcal so the number doesn't flicker minute-to-minute as HealthKit pushes step
deltas. The ±500 cap prevents a single CrossFit class from suggesting you eat 800
extra kcal. The 1200 floor is non-negotiable.
Chart 2. Two weeks of Pillar 2 in action. Each dot is the day's adjusted calorie target after Pillar 2 reads the morning's active-energy total from HealthKit. Big lift days punch up; recovery days trim back. The band hard-clips at ±500 kcal from the weekly anchor.
Worked example. Base target 2000 kcal, baseline active 400 kcal:
You "earn" the calories you actually burned, but the cap keeps the math honest about energy compensation (your body downregulates basal output on big training days, so a true 1:1 refeed is overkill).
Same calorie ceiling, very different macro split — depending on how recovered, exerted,
and stressed your body looks today. Five modes, chosen from sleep duration / efficiency, HRV,
resting heart rate, wrist temperature delta, steps, active calories, and exercise minutes
(services/bodyStateService.ts):
| Mode | Trigger | Cal Δ | Carb × | Fat × | Why |
|---|---|---|---|---|---|
| Perform | recovery ≥ 78 AND exertion ≥ 58 | +125 to +225 | 1.14 – 1.22 | 0.94 | Body is ready to use fuel — push carbs around training |
| Recover | recovery < 58 OR stress ≥ 76 (low-exertion side) | −50 to −100 | 0.78 – 0.86 | 1.10 | Steady carbs, more fat for satiety, protect protein |
| Stabilize | high exertion + low recovery | 0 | 0.86 – 0.94 | 1.06 | No deficit today — sodium, moderate carbs |
| Cut Smart | recovery ≥ 72 AND exertion < 45 | −175 | 0.90 | 1.02 | Lighter activity day with good recovery — gentle deficit |
| Baseline | nothing else fires | 0 | 1.00 | 1.00 | Use your standard plan |
Hard caps: calorie delta ±300 kcal, carb multiplier 0.65–1.35, fat multiplier 0.8–1.2, calorie floor 1200, protein floor 40 g, carb floor 30 g, fat floor 25 g. Every macro is also rounded to the nearest 5 g so the targets read cleanly in the UI.
The mode is recomputed every morning. If you wake up under-slept after two great days, your plan will quietly shift from Perform into Recover and your protein will hold while carbs trim — without you needing to remember to do anything.
Pillars 1-3 set what you should eat. Pillar 4 reads what you actually are eating,
computes burned − eaten, and drops the day into one of eight buckets
(classifyDeficit):
| Bucket | Range (kcal under burn) | Tone | Recommendation theme |
|---|---|---|---|
| Extreme deficit | ≥ 1000 | danger | Add 400–600 kcal, protect muscle/hormones |
| Aggressive deficit | 700 – 1000 | warn | Add 200–400 kcal, protein-forward |
| Optimal deficit | 300 – 700 | good | Hold — fat-loss sweet spot |
| Mild deficit | 50 – 300 | good | Slow loss territory |
| Maintenance | ±50 | neutral | At maintenance |
| Mild surplus | 50 – 300 | neutral | Lean-gain territory |
| Moderate surplus | 300 – 700 | warn | Bulking — protein ≥ 1.6 g/kg |
| Large surplus | ≥ 700 | danger | Plan a lighter day tomorrow |
Two gates before a classification is even produced: burn must be > 500 kcal (basal alone is
~1200) and intake must be > 0. Without both, the card returns no_data and
tells you to log a meal or sync HealthKit. We refuse to make up numbers.
Alex is 86 kg, 32, male, office job, walks ~7k steps/day, lifts 3×/week. Goal: lose ~20 kg over six months without losing strength. Mifflin-St Jeor with PAL 1.4 estimates his TDEE at 2500 kcal. We seed his target at 2000 kcal/day (500 kcal deficit, ~0.45 kg/week expected loss).
| Wk | Avg weight (kg) | Avg intake | Engine action | Why |
|---|---|---|---|---|
| 1 | 86.1 | 2120 | No change | Smoother gates not met yet |
| 2 | 85.9 | 2080 | No change | Fallback sees −0.10 kg/wk, within target band |
| 3 | 85.7 | 2050 | No change (still fallback) | Trend on track; not enough span for the EWMA+OLS smoother |
| 4 | 85.6 | 2010 | 2000 → 1750 | Smoother activates: smoothedTDEE 2400, slope −0.10 kg/wk — too slow; raw delta −440 kcal, clamped to −250 |
| 5 | 85.0 | 1750 | No change | Slope −0.55 kg/wk, on target (in −0.86 to −0.35 band) |
| 6 | 84.4 | 1750 | No change | Slope −0.60 kg/wk, on target |
| 7 | 83.5 | 1700 | 1750 → 1850 | Slope −0.95 kg/wk exceeds 1% safety ceiling (0.86 kg) — too fast; +100 kcal (no clamp needed) |
| 8 | 83.0 | 1860 | No change | Slope −0.55 kg/wk, locked in |
Chart 3. Alex's calorie target across 8 weeks. The smoother sat out the first three weeks (gates not met), proposed a 250 kcal cut in week 4 (the raw math wanted −440, the safety clamp held it to −250), and pulled the cut back +100 kcal in week 7 when the trend overshot the safety ceiling. Net: 3.1 kg lost in 8 weeks at the conservative end of his target band.
Chart 4. Alex's expenditure estimate over the same 8 weeks. The static formula sat at 2500 kcal the whole time. The data-driven smoother started there too (it falls back to fallback math while the gates are unmet), then in week 4 it had enough weigh-ins and intake days to compute a true slope — and immediately corrected the estimate down to ~2400 kcal, which is what triggered the −250 kcal target cut in Chart 3. Without the smoother, that 100 kcal of "phantom expenditure" would have kept Alex stuck at −0.10 kg/week for another month.
Net result: 3.1 kg down in 8 weeks (0.39 kg/week — exactly the conservative end of his target band), zero stalls, zero crashes. The engine caught the "I'm not actually losing" plateau in week 4 and the "I'm losing too fast" risk in week 7 — both the kind of signal a static TDEE app would never see.
Day 35 of his cut is also a perfect Pillar 2/3 case study. Alex's HealthKit shows:
Final macros for that day: 2275 kcal, 175 g protein, 280 g carbs, 65 g fat. A static-TDEE app would have told him to eat 1500 kcal — and his 4 PM training session would have suffered.
| Capability | Static MSJ apps | MacroFactor | Healthify |
|---|---|---|---|
| Adapts calorie target to real outcomes | × | ✓ (weekly Bayesian) | ✓ (weekly EWMA + OLS slope, gates 12/10/21) |
| Real-time daily adjust from HealthKit | × | partial | ✓ (rounded to 25, ±500 cap) |
| Macro split adapts to recovery / exertion | × | × | ✓ (5 Body State modes) |
| Safety clamp on weekly delta | × | ✓ (~200 kcal) | ✓ (±250 kcal) |
| Calorie floor | × | ✓ | ✓ (1200/1500 by goal) |
| Honest "low confidence" labelling | × | partial | ✓ (low/medium/high + N-days chip) |
| Protein floor surfaced as nudge | × | × | ✓ (15% under for 7d → coaching card) |
| Open formulas (no black-box) | n/a | partial | ✓ (this article + the source) |
We are not pretending to be the only adaptive nutrition app. MacroFactor got there first and the smoother model in this app is built on the public foundations of theirs. The differentiators are the daily-adjust layer (Pillar 2), the recovery-aware macro split (Pillar 3), the explicit confidence labelling, and the fact that we're putting the formulas on a public page anyone can read.
A few things this engine deliberately does not do, because the science doesn't support them or because they create false confidence:
The adaptive engine ships in every Healthify Meals account — free tier included. Log meals for ten days, sync HealthKit, drop a few weight readings, and the engine will start showing you a "Based on N days · model" chip on your Energy Balance card with the exact window backing your number.
Open Healthify →