Food log
Adapt before use. This skill assumes a small plain-text food project: a data/foods.csv of label transcriptions, a data/intake.csv of servings, a scripts/build.py that regenerates a markdown log, and a sources/ folder for label photos. Set PROJECT to wherever yours lives and point the inbox at wherever photos arrive. The composition-database lookup below is the Australian AFCD; substitute USDA FoodData Central, McCance and Widdowson, or your national equivalent.
PROJECT=~/vault/01-projects/food-tracking # adapt
INBOX=~/vault/00-inbox # adapt
Read the project's own architecture.md before making any structural decision. It records which composition database is in use and why, the label-first resolution rule, and what is deliberately not built.
Stage: monitoring only. Macronutrients first, micronutrients second. Do not generate targets. Reference percentages in the generated log are published population references, not targets the user has set. Observations are wanted; prescriptions are not.
The standing rule
A food photo in the inbox is food the user ate, unless they say otherwise. Log it. Do not ask them to confirm that they ate their own lunch.
Ask only when the amount is genuinely ambiguous and the answer changes the numbers materially: a multi-serve pack where it is unclear how much they had, an undrained tin, a "prepared" panel made up differently. One question, with the options costed, not a checklist.
Procedure
- Read every photo. Panel, front of pack, scale.
sips -Z 1400 a copy first; full-resolution phone photos are wasteful to read whole. For a small panel, crop at full resolution with sips -c <h> <w> --cropOffset <y> <x> rather than squinting at a downscale. Phone photos carry EXIF orientation, so a crop's coordinates are in the stored (usually landscape) frame, not the frame you saw.
- Meal time comes from the photo timestamp, not from when you process it.
- New food? Add one row to
data/foods.csv:
- Transcribe the label exactly as printed, in the basis it is printed in (
per_100g or per_100ml plus density_g_per_ml). Do not convert to be tidy; the stored numbers have to be checkable against the photo.
- Find a micronutrient proxy in the composition database and record its key in
afcd_ref (rename that column for your database).
- A weak proxy is worse than none. If the closest match is a different kind of food (homemade versus a powdered packet mix), leave the reference blank and say so in
notes. The build reports coverage honestly; a plausible-looking wrong number does not get caught.
- Record
serve_g and serve_label from the pack.
- Append to
data/intake.csv: datetime,food_id,amount,unit,notes. Prefer g. Put anything that makes the panel not describe what they ate (undrained, made differently, part of the pack) in notes.
- Quote any field containing a comma. The build fails loudly on ragged rows, but do not make it.
- Rebuild:
python3 scripts/build.py. Never hand-edit the generated log.
- Add the prose to
foods.md: ingredients, allergens, pack size, and every caveat that matters (drained weight, as prepared, best before). Link the photos.
- File the photos to the project's
sources/ as YYYY-MM-DD-<slug>-<what>.jpg, and drain them from the inbox.
- Log one line to wherever the project records activity.
Honesty rules, non-negotiable
- Unknown is never zero. A nutrient with no label value and no proxy stays blank and prints as
?.
- Never invent a figure for a pack size, net weight or percentage that is not legible in the photo. Say what is missing and what photo would fix it.
- State the assumptions that carry error. Density conversions, "about 2 serves per tin", anything estimated. They belong in
notes and in the report.
Gotchas found in the field
- Labelled scoops lie. Two 30 g scoops of whey isolate weighed 67 g. Always prefer the scale.
- Australian labels carry almost no micronutrients: energy, protein, fat, saturated fat, carbohydrate, sugars, sodium, and sometimes calcium. Everything else has to come from the composition database, which is why the proxy matters. Other jurisdictions differ; US labels carry more, and their own rounding rules.
- National composition databases have no branded products. Do not go looking for one.
- A file store can go read-only while writes still work. On macOS, iCloud occasionally returns
EDEADLK on read from one process while another writes happily. If reads start failing, copy the file out through Finder with osascript, or read from a git mirror of the tree.
1---2name: food-log3description: Log food the user has eaten into a food-tracking project: read the nutrition panel and scale photos they dropped in the inbox, add the food to data/foods.csv with a composition-database micronutrient proxy, append the serving to data/intake.csv, rebuild the generated log, and file the photos. Use whenever a food or nutrition-label photo appears in the inbox, or when the user says they ate something, asks what was in a meal, or asks about their intake. NOT for recipes they are keeping.4---56# Food log78**Adapt before use.** This skill assumes a small plain-text food project: a `data/foods.csv` of label transcriptions, a `data/intake.csv` of servings, a `scripts/build.py` that regenerates a markdown log, and a `sources/` folder for label photos. Set `PROJECT` to wherever yours lives and point the inbox at wherever photos arrive. The composition-database lookup below is the Australian AFCD; substitute USDA FoodData Central, McCance and Widdowson, or your national equivalent.910```11PROJECT=~/vault/01-projects/food-tracking # adapt12INBOX=~/vault/00-inbox # adapt13```1415Read the project's own `architecture.md` before making any structural decision. It records which composition database is in use and why, the label-first resolution rule, and what is deliberately not built.1617**Stage: monitoring only.** Macronutrients first, micronutrients second. **Do not generate targets.** Reference percentages in the generated log are published population references, not targets the user has set. Observations are wanted; prescriptions are not.1819## The standing rule2021**A food photo in the inbox is food the user ate, unless they say otherwise.** Log it. Do not ask them to confirm that they ate their own lunch.2223Ask only when the amount is genuinely ambiguous and the answer changes the numbers materially: a multi-serve pack where it is unclear how much they had, an undrained tin, a "prepared" panel made up differently. One question, with the options costed, not a checklist.2425## Procedure26271. **Read every photo.** Panel, front of pack, scale. `sips -Z 1400` a copy first; full-resolution phone photos are wasteful to read whole. For a small panel, crop at full resolution with `sips -c <h> <w> --cropOffset <y> <x>` rather than squinting at a downscale. Phone photos carry EXIF orientation, so a crop's coordinates are in the **stored** (usually landscape) frame, not the frame you saw.282. **Meal time comes from the photo timestamp**, not from when you process it.293. **New food?** Add one row to `data/foods.csv`:30 - Transcribe the label **exactly as printed**, in the basis it is printed in (`per_100g` or `per_100ml` plus `density_g_per_ml`). Do not convert to be tidy; the stored numbers have to be checkable against the photo.31 - Find a micronutrient proxy in the composition database and record its key in `afcd_ref` (rename that column for your database).32 - **A weak proxy is worse than none.** If the closest match is a different kind of food (homemade versus a powdered packet mix), leave the reference blank and say so in `notes`. The build reports coverage honestly; a plausible-looking wrong number does not get caught.33 - Record `serve_g` and `serve_label` from the pack.344. **Append to `data/intake.csv`**: `datetime,food_id,amount,unit,notes`. Prefer `g`. Put anything that makes the panel not describe what they ate (undrained, made differently, part of the pack) in `notes`.35 - **Quote any field containing a comma.** The build fails loudly on ragged rows, but do not make it.365. **Rebuild**: `python3 scripts/build.py`. Never hand-edit the generated log.376. **Add the prose** to `foods.md`: ingredients, allergens, pack size, and every caveat that matters (drained weight, as prepared, best before). Link the photos.387. **File the photos** to the project's `sources/` as `YYYY-MM-DD-<slug>-<what>.jpg`, and drain them from the inbox.398. **Log** one line to wherever the project records activity.4041## Honesty rules, non-negotiable4243- **Unknown is never zero.** A nutrient with no label value and no proxy stays blank and prints as `?`.44- **Never invent a figure** for a pack size, net weight or percentage that is not legible in the photo. Say what is missing and what photo would fix it.45- **State the assumptions that carry error.** Density conversions, "about 2 serves per tin", anything estimated. They belong in `notes` and in the report.4647## Gotchas found in the field4849- **Labelled scoops lie.** Two 30 g scoops of whey isolate weighed 67 g. Always prefer the scale.50- **Australian labels carry almost no micronutrients**: energy, protein, fat, saturated fat, carbohydrate, sugars, sodium, and sometimes calcium. Everything else has to come from the composition database, which is why the proxy matters. Other jurisdictions differ; US labels carry more, and their own rounding rules.51- **National composition databases have no branded products.** Do not go looking for one.52- **A file store can go read-only while writes still work.** On macOS, iCloud occasionally returns `EDEADLK` on read from one process while another writes happily. If reads start failing, copy the file out through Finder with `osascript`, or read from a git mirror of the tree.