# Food Log

> 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.

- Skill: `campbellsmurphy/food-log` (Agent Skill)
- Install (CLI): `npx skillmds@latest add campbellsmurphy/food-log`
- Raw SKILL.md: https://api.skillmd.com/api/skills/campbellsmurphy/food-log/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: campbellsmurphy (https://skillmd.com/u/campbellsmurphy)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/campbellsmurphy/food-log

---


# 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

1. **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.
2. **Meal time comes from the photo timestamp**, not from when you process it.
3. **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.
4. **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.
5. **Rebuild**: `python3 scripts/build.py`. Never hand-edit the generated log.
6. **Add the prose** to `foods.md`: ingredients, allergens, pack size, and every caveat that matters (drained weight, as prepared, best before). Link the photos.
7. **File the photos** to the project's `sources/` as `YYYY-MM-DD-<slug>-<what>.jpg`, and drain them from the inbox.
8. **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.

