Nutrition intake

Handle nutrition intake capture and canonical nutrition logging for Coach Luca. Use when an athlete sends a meal photo, snack photo, drink, supplement, food label, text-only food log, follow-up timing correction, or any nutrition item that must be stored before analysis or reply. Use for intake detection, media copy, consumed-versus-received date resolution, canonical daily-log writes under <code translate="no" v-pre>## Nutrition</code>, summary-table and totals updates, completion checks, repair passes for item-level nutrition entries, and deciding whether minimal staging or routing ledgers still need updates.

Handle nutrition intake persistence and canonical nutrition logging before specialist analysis or athlete-facing reply.

Keep this skill focused on intake detection, persistence, canonical logging, repair passes, and completion gates. Do not use it as the source of truth for specialist evidence handling or athlete-facing nutrition wording.

Workflow overview

  1. Detect whether the inbound message is a new nutrition item, follow-up timing context, a batch context update, a return-media request, or a summary request.
  2. Persist the intake item into canonical workspace locations.
  3. Ensure the correct athlete-day daily log exists and write the nutrition item into ## Nutrition.
  4. Rebuild the derived ### Summary table and totals row when the logged intake changes.
  5. If the item requires specialist review, the script output feeds directly into the nutrition specialist workflow. Do not hand off to nutrition-analysis - it is disabled.
  6. If the item requires an athlete-facing reply, explicitly read and apply nutrition-reply after persistence and any required specialist coordination are complete.
  7. Do not treat the workflow as complete until that final nutrition reply has either been sent under nutrition-reply or deliberately withheld because the case is operator-only, test-only, or otherwise not meant for athlete delivery.

Read these references when needed

  • Read references/workflow.md for the end-to-end intake workflow, branch logic, daily-log write sequence, and repair rules.
  • Read references/persistence.md for canonical paths, heading standards, timestamp handling, media copy rules, and completion gates.
  • Read references/logging-entry-template.md for the single source of truth on the required nutrition-item template.
  • Read references/logging-summary-table.md for how to rebuild the summary table and totals row.
  • Read references/migration-map.md when migrating or auditing older nutrition instructions that still live outside this skill.

Script execution gate (hard - no exceptions)

Every live athlete nutrition intake item must be processed through scripts/process_nutrition_intake.py. This is not optional and not a default. It is the only permitted path for writing a new nutrition item into the canonical daily log.

NO_REPLY is never a substitute for this gate. In athlete-channel workflows, NO_REPLY means only that no visible progress text should be sent to the athlete. It does not mean the nutrition item is complete, skipped, or acknowledged. A live nutrition item is complete only when the processor has created the daily-log entry and raw archive, or when a concrete blocker is logged for operator repair.

Duplicate/source-message idempotency gate (hard - before script execution)

Before running scripts/process_nutrition_intake.py for any live nutrition item or retry, perform a same-day duplicate preflight against the canonical athlete-day log. This gate applies even when the script execution gate applies.

Hard stop before every processor invocation: if scripts/process_nutrition_intake.py is already running for the same date, heading minute, received/local timestamp, source text, or media item, do not start another processor command. Wait for the active command to finish or inspect its result, then continue from that result. Starting a second same-source processor while the first is running is a duplicate-creation workflow failure.

  1. Read or search athlete/logs/daily/YYYY-MM-DD.md for the inbound item's exact Received, exact Local, heading minute, and normalized athlete text or photo description.
  2. If the same source message, same media file, or same normalized food text is already logged under any ### HH:MM or ### HH:MM (n) heading, do not run a fresh insert.
  3. If the prior entry is incomplete, stale, or needs revised estimates, run the script only as a replacement using --replace-heading <existing-heading> and --target-heading <intended-heading>. Do not allow the logger to create a new suffixed heading for the same source item.
  4. If a suffixed heading such as HH:MM (2) already exists for the same source item and the same raw archive folder, treat it as a repair case: keep the raw-artifact-aligned entry, remove stale duplicate blocks and summary rows, recalculate totals, and add an internal system correction row. Do not send an athlete-facing correction unless the operator explicitly asks.
  5. If the inbound message mixes a non-nutrition request with a nutrition item, split the classification, but process the nutrition item only once. The request text may be preserved in the quoted message, but it must not justify a second nutrition-item insert for the same food.

The hard failure mode to avoid is a second fresh run for the same source message or same minute, including a second attempt launched while the first command is still running, that creates HH:MM (2) while reusing athlete/data/nutrition-analysis/raw/YYYY-MM-DD/HHMM/. That produces stale daily-log blocks pointing at overwritten raw artifacts.

  • Do not manually write a nutrition item entry into the daily log.
  • Do not hand-build the #### Macro comparison, #### Service notes, or #### Aggregate estimate blocks.
  • Do not skip the script because the item looks simple, is text-only, or has no photo.
  • Do not write a plain entry first and plan to add analysis later. That is a workflow failure.

The script handles media copy, canonical daily-log write, raw archive creation, normalized JSON, comparison markdown, and summary rebuild in one pass. If the script exits with a non-zero code, stop and report the error before proceeding. Do not fall back to a manual write.

The completion gate for any nutrition item write is: a raw archive directory exists at athlete/data/nutrition-analysis/raw/YYYY-MM-DD/<heading-time>/ and the daily log entry contains #### Macro comparison, #### Service notes, and #### Aggregate estimate. If those are absent, the item is not complete.

Photo-backed intake guard (hard)

If the inbound nutrition item contains any photo, image, media, attachment, [image telegram:file/...] marker, or channel metadata indicating a photo was sent, invoke scripts/process_nutrition_intake.py with --expect-image and either --source-image <incoming media path> or --image <already-canonical media path>.

  • --source-image is preferred for newly received media because the wrapper copies it into athlete/logs/media/YYYY-MM-DD/ and passes that canonical path to the logger.
  • If --expect-image fails because no local image path is available, stop. Do not process the item as text-only and do not claim the photo was logged.
  • The completion gate for photo-backed items additionally requires a Markdown image immediately under the ### HH:MM entry and script output containing image or canonical_image.
  • If OpenClaw history shows only text and no media marker for an item the athlete/operator says included a photo, log this as a gateway/media-ingestion failure and ask for resend or recover the file from channel tooling before repairing the daily log.

Core rules

  • Treat every inbound nutrition item as a persistence task first.
  • Do not send an athlete-facing nutrition reply before the required persistence work exists in the canonical files.
  • Use the canonical athlete-day log at athlete/logs/daily/YYYY-MM-DD.md.
  • Perform all nutrition-item writes through scripts/process_nutrition_intake.py as stated in the script execution gate above.
  • Keep staging and routing ledgers minimal if they are still used at all.
  • The nutrition-analysis skill is disabled. Do not reference or invoke it. Multi-service comparison is handled by scripts/process_nutrition_intake.py directly.
  • Use nutrition-reply for athlete-facing wording and blocked reply content.
  • When a nutrition item is expected to produce an outbound athlete message, do not draft that message from general memory, from prior chat wording, or from another skill. Read and apply nutrition-reply at the reply step.
  • Treat any nutrition reply that was not composed under nutrition-reply as a workflow failure that should be corrected before send.
  • Do not send the athlete any intermediate progress reply while persistence, estimation, routing, or coordination is still in progress.
  • Disallowed athlete-facing progress chatter includes messages such as I'm logging this, I'm adding this, I'm updating this, I'm adding this to today's nutrition log first, then I'll send, or any equivalent internal-status wording.
  • Hard stop: if the candidate outbound text is a processing update instead of the final athlete-useful reply, do not send it. Send nothing.
  • Under this skill, the athlete channel stays silent until the final athlete-useful nutrition reply is ready, unless a real follow-up question is strictly required to complete the item.
  • Channel isolation rule: this skill never calls a send or delivery tool directly. All athlete delivery is delegated to athlete-comms. The sequence is: complete persistence, compose candidate body, pass to athlete-comms with the candidate. athlete-comms validates and delivers.
  • Athlete-comms audit rows are not a substitute for athlete-comms. Do not call scripts/athlete_comms_audit.py, manually write an athlete-comms: system row, or mark a nutrition reply as APPROVE, REWRITE, BLOCK, delivered, or not delivered from the nutrition-intake/main session. Only the actual athlete-comms agent may write that verdict row after it has reviewed the final candidate and either attempted delivery or explicitly blocked delivery.
  • For every successful athlete-originated nutrition item that needs a reply, spawn the configured athlete-comms agent with the final candidate body. If there is no actual athlete-comms session result, the nutrition workflow is incomplete. Do not infer an athlete-comms verdict from a valid-looking draft, and do not end the workflow after writing only an audit row.
  • If athlete-comms returns APPROVE or REWRITE with Delivered: no, treat that as an unresolved delivery failure, not completion. Retry through the configured reviewed send path when allowed by the handoff rules, or log the concrete blocker and surface it to the operator. A row with Channel: none, Account: none, and Target: none is valid only when athlete-comms recorded the actual transport blocker.

Chronological ordering rule (hard)

This rule applies every time a ### HH:MM block is written into ## Nutrition. It is not optional and does not require reading the references first.

Before writing any new ### HH:MM block:

  1. Read the current ## Nutrition section and identify all existing ### HH:MM headings and their positions in the file.
  2. Determine the correct chronological position for the new block among the existing ### HH:MM blocks:
    • New item is later than all existing blocks: insert it after the last existing ### HH:MM block's content. Do not insert it after a named subsection heading such as ### Watch, ### Observations, or ### Carry-forward.
    • New item is earlier than all existing blocks: insert it before the first existing ### HH:MM block.
    • New item falls between two existing blocks: insert it after the earlier block and before the later block.
  3. When no ### HH:MM blocks exist yet, place the new block after the last named subsection.
  4. After writing, re-read the ## Nutrition section and confirm every ### HH:MM block is in ascending time order. If they are not, reorder before proceeding.

Hard failure mode to avoid: never anchor a new block's insert position to a named subsection heading (e.g. ### Watch, ### Carry-forward) when ### HH:MM blocks already follow it. That inserts the new block before those existing time blocks regardless of its own time.

Tilde escaping rule (hard)

All ~ tilde characters must be escaped as \~.

This rule fires at write time. Do not write unescaped tildes into any content then rely on a later repair pass to fix them. Scan the content before writing and escape any ~ that is not already \~.

Exception: inside plain ~~~ fenced blocks (athlete message quotes), use plain ~ without escaping.

Boundaries

This skill owns:

  • intake detection
  • media copy into workspace storage
  • consumed-date versus received-date resolution
  • choosing the correct athlete-day file for nutrition items
  • ensuring the ## Nutrition section structure exists
  • writing or repairing nutrition item entries in the athlete daily log
  • inserting markdown media into nutrition entries
  • rebuilding the ### Summary table and totals row
  • heading and timestamp application guidance for the write
  • completion gates for intake handling

This skill does not own:

  • detailed specialist evidence hierarchy
  • detailed service-selection or comparison logic beyond recognizing that a specialist handoff is needed
  • athlete-facing nutrition reply wording
  • cross-domain coaching synthesis after persistence is complete