The Scripting app's type checker doesn't recognize Health/HealthUnit/
HealthUnitPrefix as global types. @ts-nocheck skips type checking
entirely — the APIs exist at runtime.
- Remove all TS type annotations (HealthQuantityType, HealthUnit etc.)
to avoid 'string not assignable' errors — let the app infer types
- HealthMetricPrefix → HealthUnitPrefix (correct enum name per docs)
- HealthUnit.fromString('mmHg') → HealthUnit.millimeterOfMercury()
(confirmed in docs: line 35229)
Scripting app expects TypeScript with import from 'scripting' and Script.exit().
- Renamed health-sync.js → health-sync.tsx
- Added 'import { Script } from "scripting"' and Script.exit() at end
- Added TypeScript type annotations
- Health/HealthUnit/Notification/fetch are global APIs (no import needed)
- fetch() instead of new Request() + req.loadJSON() (Scriptable API)
- Notification.schedule({title, body}) instead of new Notification() + n.schedule()
- allowInsecureRequest: true for HTTP (Scripting app blocks HTTP by default)
- This was the real reason 'nothing happened' — Scriptable API doesn't exist in Scripting app
log_custom_food's schema documents keys like 'protein', 'fat', 'salt' but
sum_nutriments() looks for OFF-style keys ('proteins_100g', 'fat_100g',
'salt_100g'). Nutrients passed with friendly keys were silently dropped
from daily totals. Now translates friendly keys to OFF keys before
storing. Both key styles work.
OFF data is sparse for fresh produce — spinach, oats, most frozen fruit
have no potassium. Added a curated fallback table (114 foods, USDA-sourced)
that injects estimated K/Ca/Mg at log time when OFF has no data.
How it works:
- data/fallback_nutrients.json: 114 foods with mg/100g values
- FallbackTable: case-insensitive exact + substring name matching
- log_food: injects _est keys (potassium_100g_est etc.) when OFF missing
- sum_nutriments: tries OFF value first (grams×1000), then _est (already mg)
Results for today's smoothie + lunch:
- Potassium: 691mg → 2,530mg (47% of 5400mg goal)
- Calcium: 14mg → 304mg (30% of 1000mg goal)
- Magnesium: 61mg → 330mg (73% of 450mg goal)
38 tests passing (7 new: fallback lookup, est fallback, OFF vs est priority)
OFF stores potassium_100g, calcium_100g, magnesium_100g in grams.
Goals are in mg. sum_nutriments now multiplies these by 1000.
Before: potassium showed 0.7mg (was 0.0007g displayed as mg)
After: potassium shows 691.2mg (banana: 0.32g/100g × 216g × 1000)
Added MG_NUTRIENTS const to db.rs. Updated test assertions.
31 tests passing.
- POST /ingest endpoint for Apple Health vitals (src/ingest.rs)
- GET /scriptable/health-sync.js for phone download
- recipes/daily-smoothie.json — Atrdeus's daily smoothie with barcodes
- Scriptable script reads HealthKit and POSTs to /ingest
Closes nutrition-mcp-aav
Old script used deprecated Health.read() with Health.Types.* and .quantity
— every read silently failed in try/catch, so no samples were ever collected.
Rewrote to use Health.queryQuantitySamples() with string type identifiers
and .quantityValue(unit) per current Scripting app docs. Added proper units
(kg, mmHg, count/min, count, percent) for each metric type.
Also adds /scriptable/health-sync.js endpoint to serve the script directly.
- Add vitals table (type, timestamp_utc, value JSON, source) with UNIQUE
(type,timestamp_utc) for idempotent upserts.
- POST /ingest: Bearer-protected HTTP endpoint accepting batched health
samples (weight, blood_pressure, heart_rate, spo2, steps, sleep, ...).
Weight samples are mirrored into weight_log so existing weight tools see them.
- recent_vitals MCP tool: reads back ingested vitals, grouped by type with
min/avg/max/units over a configurable window.
- 6 new tests (31 integration + 2 unit total, all passing).
- Verify live: /ingest POST -> recent_vitals round-trip over MCP protocol.
Parameter-less tools in rmcp generated inputSchema: {} (empty dict
with no type field), which the Hermes MCP client rejects — one bad
tool fails the entire tools/list response.
Fix: added NoParams struct (empty, derives JsonSchema) and changed
get_goals to accept Parameters<NoParams>. schemars generates
{"type": "object", ...} for empty structs, which is valid.
- Search URL: search.openfoodfacts.org/search (not /api/v1/search)
- Search-a-licious returns no nutriments in hits — fetch each via v3 API
- Fall back to nutriments_estimated when no_nutrition_data is set
or nutriments object has <3 keys (common for fresh produce)
- Handle brands as array or string from search API
- systemd user service deployed on Pi5 (port 9432, API key auth)
- Registered with Hermes via mcp_servers config
- Hermes skill at ~/.hermes/skills/productivity/nutrition-tracker/
- Git remote: git.darkmark.co.uk/amerlo/nutrition-mcp
Closes nutrition-mcp-foe, nutrition-mcp-aea