Skip to content

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.

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

  • OK rating no longer creates phantom Ok option (capitalize bug fixed in normalize_rating)
  • Macros are float not int (so 187.5 cal works)
  • 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_json with 3 retries + linear backoff