Food Log¶
Notion DB tracking food / drink / supplement intake with macros, caffeine, time-of-day, and per-day totals.
Components¶
| Piece | Path |
|---|---|
| Notion DB | id 3510950b-d7a9-81f2-8cac-e6d1c57d230b (alongside Daily Log + Wellness Daily under Life) |
| CLI | forge/scripts/forge_food_log.py |
| Macro lookup | forge/scripts/forge_food_lookup.py (3 backends, retry-wrapped) |
| Inbox bot tools | log_food + food_today registered in forge_telegram_inbox_brain.py (TOOLS spec + TOOL_HANDLERS) |
| Brain DB key | food_log in NOTION_DBS (also added to query_notion allowed list) |
| USDA API key | ~/.forge-secrets/usda.env (free tier, 1000 req/hr) |
Schema (10 properties)¶
Name (title, required), Date (datetime), Meal (select: Breakfast/Lunch/Dinner/Snack/Drink/Supplement), Calories, Protein (g), Carbs (g), Fat (g), Caffeine (mg), Rating (Great/Good/OK/Bad), Tags (multi_select), Notes (rich_text).
Time inference¶
When --time not passed: Breakfast 08:30, Lunch 12:30, Dinner 19:00; Snack/Drink/Supplement/no-meal default to now; backfilled date with no hint defaults to noon. Stored as datetime with America/Chicago tz.
Macro lookup backends¶
| Backend | Best for | Limitation |
|---|---|---|
Sonnet --lookup |
Branded restaurant items, compound foods, real portions | 4 to 14s latency |
USDA --usda |
Raw single ingredients, official lab data | Per 100g basis, no restaurant items, intermittent 400s (auto-retried) |
OpenFoodFacts --source off |
Packaged grocery products by name | Fuzzy search, no restaurant items, intermittent 503s (auto-retried) |
Inbox bot path: brain estimates inline (one pass, no nested call). --lookup/--usda flags are for CLI only.
Inbox bot UX¶
| Text | Result |
|---|---|
| "had eggs and toast for breakfast" | log_food with brain-estimated macros, meal=Breakfast, time=08:30 |
| "Starbucks lemon loaf" | log_food with brain estimate (~490 cal), time=now |
| "took creatine 5g" | log_food meal=Supplement, time=now |
| "what did I eat today" | food_today, returns timeline + totals + caffeine |
Tool spec includes explicit hints (Starbucks lemon loaf ~490 cal, medium banana ~105, 16oz cold brew ~200mg caffeine) so the brain reliably estimates inline.
Provenance¶
CLI --lookup/--usda paths append est: <source> (<confidence>), <lookup notes> to the Notes field, preserving any user-passed notes with | separator. Brain-inline estimation has no provenance marker (indistinguishable from manual entry).
Quota tracking¶
Sonnet CLI --lookup calls record to forge_quota_tracker with invoker="forge_food_log". Brain-inline estimation rolls up under the brain's normal usage.
Notion view calculations (footer sums) gotcha¶
Internal API (forge_notion_api.py cookie auth) CAN write format.table_properties[i].calculation = "sum" and the value persists, but the Notion frontend will NOT render the calc footer until the user clicks the column-footer "Calculate" menu in the UI at least once per column. Tried bare-string, object form, fine-grained path ops, whole-format set, version-bump triggers, subitem_filter_scope injection. None render. The UI click sends a frontend-side operation that triggers render-state separate from the persisted format. So: views can be programmatically created with the right structure, but column calcs require manual one-time clicks per column. Documented as "click recipe" in handoff if creating new analytic views.
Bug history¶
OKrating no longer creates phantomOkoption (capitalize bug fixed innormalize_rating)- Macros are float not int (so
187.5 calworks) - USDA URL must percent-encode parens (
%28FNDDS%29); curl with raw parens 400s, urlencode handles it correctly - Both USDA and OFF flake intermittently — both wrapped in
_http_jsonwith 3 retries + linear backoff