Meal drafts and confidence
The draft an assistant sends to log_meal, ingredient confidence tiers (0.85, 0.60, 0.30) and when a meal needs review.
In ChatGPT and Claude the host model does the vision: it looks at the photo or reads what the person said and sends log_meal a draft. Gutlog matches each item against the person's own foods, the barcode index and the food database, then portions it, computes nutrients and stores it. Gutlog's own analysis of photos from the web app, the CLI and the API produces the same draft, so there is one contract for both paths. The field descriptions below are what the model reads in the tool schema.
Example
{ "title": "Scrambled eggs on toast", "meal_type": "breakfast", "client": "claude", "items": [ { "name": "scrambled eggs", "grams": 120, "confidence": 0.92, "portion_confidence": 0.7, "cooking_method": "pan_fried", "ingredients": [ { "name": "egg", "confidence": 0.97, "visible": true }, { "name": "butter", "confidence": 0.55, "visible": false }, { "name": "milk", "confidence": 0.35, "visible": false } ] }, { "name": "sourdough toast", "portion": { "quantity": 1, "unit": "slice" }, "confidence": 0.85, "ingredients": [ { "name": "wheat flour", "confidence": 0.9, "visible": false }, { "name": "salt", "confidence": 0.75, "visible": false } ] } ]}The meal
* marks a required field. meal_type is one of breakfast | lunch | dinner | snack | drink.
| Field | Type | What to send |
|---|---|---|
| items * | array | One entry per distinct food or drink on the plate or in the message. |
| meal_type | enum | Leave out to infer from the time. |
| eaten_at | string | When it was eaten, ISO 8601 with offset; default now. |
| title | string | A short name for the meal: "Chipotle bowl", "Breakfast". |
| note | string | Anything the person said that is not an item (where, how they felt). |
| client | string | Your client name, e.g. "chatgpt", "claude", "cursor". |
| model | string | Your model name, for calibration. |
Items
One item per distinct food or drink. Send grams when you can estimate the weight from the photo (plate size, utensils, a hand), otherwise a household portion. A readable barcode makes the product's label win over estimates. cooking_method is one of 15 values such as grilled, pan_fried or unknown.
| Field | Type | What to send |
|---|---|---|
| name * | string | The item as it would appear on a menu or label: "grilled chicken breast", "white rice", "oat milk latte". |
| food_id | string | A food id from search_foods or a previous log_meal reply, when you already know the match. |
| barcode | string | Barcode digits if you can read them (UPC/EAN); the product's label then wins over estimates. |
| brand | string | Brand when packaging shows it. |
| grams | number | Your estimate of the edible weight in grams. Prefer this when you can estimate it from the photo (plate size, utensils, hand). |
| portion | object | Instead of grams: "2 slices", "1 cup", "1 medium". |
| servings | number | Number of the product's servings (with a barcode). |
| confidence | number | How sure you are of what this item is, 0–1. |
| portion_confidence | number | How sure you are of the amount, 0–1. |
| cooking_method | enum | |
| ingredients | array | Ingredients with a confidence each, most certain first. Include hidden fats, sugars, onion and garlic when plausible. |
| label_text | string | Any ingredient list or nutrition label text you can read, verbatim. |
Ingredients
Most certain first. Include hidden fats, sugars, onion and garlic when they are plausible, at 0.30 to 0.60: they matter for calories and for gut tracking, and the person is asked rather than assumed.
| Field | Type | What to send |
|---|---|---|
| name * | string | One ingredient as a person would say it: "garlic", "olive oil", "cheddar". |
| confidence * | number | How sure you are it is in this item, 0–1. ≥0.85 you can see or were told it; 0.60–0.85 very likely for this dish; 0.30–0.60 plausible but hidden (cooking fat, butter, sugar, garlic, onion in a sauce): include these, they are asked about. Omit below 0.30. |
| visible | boolean | You can see it in the photo (true) or inferred it from the dish (false). |
| ingredient_id | string | Canonical ingredient id if you know it from a previous response; otherwise leave it out. |
Confidence tiers
| Tier | Confidence | What happens |
|---|---|---|
| confirmed | ≥ 0.85, or read from a label | Included and counted in the meal. |
| likely | 0.6 to 0.85 | Included, counted and pre-selected: one tap or "yes" confirms them all. |
| possible | 0.3 to 0.6 | Suggested, not counted. Asked about, highest confidence first. |
| dropped | under 0.3 | Not stored. Leave these out of the draft. |
An ingredient's status starts as included (confirmed, likely) or suggested (possible), and becomes confirmed or rejected when the person answers.
Always logged; sometimes reviewed
- The meal is always stored: nothing waits for a confirmation.
needs_reviewis set when the meal's confidence is under the person's threshold (default 0.8), when a possible ingredient is one of their known triggers or allergens, or when a portion looks implausible.- The answer carries at most 3
questionsabout possible ingredients. Reply with one line of what was logged, then ask them. - Corrections always win over estimates, and every one is kept with who made it and from where.
{ "meal_id": "6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10", "needs_review": false, "totals_display": { "kcal": 352, "protein_g": 19.8, "carbs_g": 24.1, "fat_g": 19.6 }, "items": [ { "name": "scrambled eggs", "grams": 120, "ingredients": [ { "name": "egg", "tier": "confirmed", "confidence": 0.97, "status": "included" }, { "name": "butter", "tier": "possible", "confidence": 0.55, "status": "suggested" }, { "name": "milk", "tier": "possible", "confidence": 0.35, "status": "suggested" } ] }, { "name": "sourdough toast", "grams": 50, "ingredients": [ { "name": "wheat flour", "tier": "confirmed", "confidence": 0.9, "status": "included" }, { "name": "salt", "tier": "likely", "confidence": 0.75, "status": "included" } ] } ], "questions": [ "Butter in the eggs?", "A splash of milk in the eggs?" ]}Amounts in results are integers in each nutrient's base unit; see nutrients and units. Logging a draft is free and unlimited on every plan.