From 5beef81d700e85cea1f3202e51ebc6af3736af5f Mon Sep 17 00:00:00 2001 From: Anthony Merlo Date: Thu, 20 Aug 2026 16:53:33 +0100 Subject: [PATCH] docs: README.md, AGENTS.md, CLAUDE.md - README: human-facing with tech stack, 14 nutrient table, 13 tools, env vars, build/run/deploy instructions, Hermes integration - AGENTS/CLAUDE: build commands, architecture, module map, SQLite schema, conventions, tracked nutrients, session protocol Closes nutrition-mcp-yd5, nutrition-mcp-4lv --- .README.md.swp | Bin 0 -> 16384 bytes .beads/interactions.jsonl | 10 ++ AGENTS.md | 202 ++++++++++++++++++-------------------- CLAUDE.md | 162 ++++++++++++++++++------------ README.md | 165 +++++++++++++++++++++++++++++++ 5 files changed, 366 insertions(+), 173 deletions(-) create mode 100644 .README.md.swp create mode 100644 README.md diff --git a/.README.md.swp b/.README.md.swp new file mode 100644 index 0000000000000000000000000000000000000000..6c60a35919b07fa871a953696136189598825b94 GIT binary patch literal 16384 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 v#5UGz^~^o)_eW)Nruz **Architecture in one line:** Issues live in a local Dolt database -> (`.beads/dolt/`); cross-machine sync uses `bd dolt push/pull` (a -> git-compatible protocol), stored under `refs/dolt/data` on your git -> remote — separate from `refs/heads/*` where your code lives. -> `.beads/issues.jsonl` is a passive export, not the wire protocol. -> -> See [SYNC_CONCEPTS.md](https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md) -> for the one-screen overview and anti-patterns (don't treat JSONL as the -> source of truth; don't `bd import` during normal operation; don't -> reach for third-party Dolt hosting before trying the default). - -## Quick Reference +## Build & Test ```bash -bd ready # Find available work -bd show # View issue details -bd update --claim # Claim work atomically -bd close # Complete work -bd dolt push # Push beads data to remote +cargo build --release # Build binary +cargo test # Run unit tests +./target/release/nutrition-mcp # Run server (needs env vars) +``` + +### Smoke Test + +```bash +# Start server +NUTRITION_MCP_BIND=127.0.0.1:9432 NUTRITION_MCP_API_KEY=test \ + NUTRITION_MCP_DB_PATH=/tmp/test.db ./target/release/nutrition-mcp & + +# Health check +curl http://127.0.0.1:9432/health + +# MCP initialize +curl -X POST http://127.0.0.1:9432/mcp \ + -H "Authorization: Bearer test" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json, text/event-stream" \ + -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"0.1"}},"id":1}' +``` + +## Architecture Overview + +MCP server exposing 13 tools for personal nutrition tracking. Streamable HTTP transport with Bearer token auth. + +### Module Map + +``` +src/ +├── main.rs — Entry point: axum server, auth middleware, /health endpoint +├── config.rs — Config struct from env vars (bind, api_key, db_path, user_agent) +├── db.rs — SQLite schema, migrations, DbPool type, TRACKED_NUTRIENTS const, DEFAULT_GOALS_JSON +├── api.rs — OffClient: Search-a-licious + v3 barcode + SQLite cache (FTS5) +└── tools.rs — NutritionServer: 13 MCP tools via #[tool_router] + ServerHandler impl +``` + +### SQLite Schema + +- **products** — OFF cache: code (PK), product_name, brands, nutriments (JSON), serving_quantity, serving_size, image_url +- **products_fts** — FTS5 virtual table on product_name (synced via triggers) +- **entries** — Food log: id, date, meal, product_code, food_name, grams, servings, nutriments (JSON, scaled to portion) +- **daily_goal** — Single row (id=1), goals JSON with 14 nutrient targets +- **weight_log** — id, date, weight_kg + +### Nutrient Storage + +All nutrients stored as JSON blob in `nutriments` TEXT column (verbatim from OFF API). Daily summaries use `json_extract()` or Rust-side parsing to aggregate the 14 tracked nutrients. + +### Portion Scaling + +Nutrients are stored per-100g in OFF data. When logging, `scale_nutriments()` multiplies each value by `grams / 100.0`. For servings, grams = `servings * serving_quantity`. + +### Meal Auto-Detection + +- breakfast: before 11:00 +- lunch: 11:00–15:00 +- dinner: 15:00–21:00 +- snack: after 21:00 + +## Conventions & Patterns + +- **JSON nutriments** — Never hardcode nutrient columns. Store OFF nutriments verbatim as JSON, query at runtime. +- **"no data" vs 0** — Micronutrients (potassium, calcium, magnesium) are sparse in OFF. Summary shows `"no data"` when no entries have the nutrient, not 0. +- **Env vars only** — No config files. All settings via environment variables. +- **API-first** — Always check SQLite cache first, fall back to OFF API, cache results. +- **User-Agent** — Always send custom User-Agent to OFF API (good citizenship). + +## Tracked Nutrients (14) + +``` +energy_kcal → energy-kcal_100g +protein → proteins_100g +carbohydrates → carbohydrates_100g +fat → fat_100g +fiber → fiber_100g +sugars → sugars_100g +saturated_fat → saturated-fat_100g +salt → salt_100g +fructose → fructose_100g (gout) +alcohol → alcohol_100g (gout) +potassium → potassium_100g (hypertension) +calcium → calcium_100g (hypertension) +magnesium → magnesium_100g (hypertension) +cholesterol → cholesterol_100g (hypertension) ``` ## Non-Interactive Shell Commands -**ALWAYS use non-interactive flags** with file operations to avoid hanging on confirmation prompts. +**ALWAYS use non-interactive flags** to avoid hanging on confirmation prompts. -Shell commands like `cp`, `mv`, and `rm` may be aliased to include `-i` (interactive) mode on some systems, causing the agent to hang indefinitely waiting for y/n input. - -**Use these forms instead:** ```bash -# Force overwrite without prompting cp -f source dest # NOT: cp source dest -mv -f source dest # NOT: mv source dest rm -f file # NOT: rm file - -# For recursive operations -rm -rf directory # NOT: rm -r directory -cp -rf source dest # NOT: cp -r source dest ``` -**Other commands that may prompt:** -- `scp` - use `-o BatchMode=yes` for non-interactive -- `ssh` - use `-o BatchMode=yes` to fail instead of prompting -- `apt-get` - use `-y` flag -- `brew` - use `HOMEBREW_NO_AUTO_UPDATE=1` env var - - -## Beads Issue Tracker - -This project uses **bd (beads)** for issue tracking. Run `bd prime` to see full workflow context and commands. - -### Quick Reference - -```bash -bd ready # Find available work -bd show # View issue details -bd update --claim # Claim work -bd close # Complete work -``` - -### Rules - -- Use `bd` for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists -- Run `bd prime` for detailed command reference and session close protocol -- Use `bd remember` for persistent knowledge — do NOT use MEMORY.md files - -**Architecture in one line:** issues live in a local Dolt DB; sync uses `refs/dolt/data` on your git remote; `.beads/issues.jsonl` is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns. - -## Agent Context Profiles - -The managed Beads block is task-tracking guidance, not permission to override repository, user, or orchestrator instructions. - -- **Conservative (default)**: Use `bd` for task tracking. Do not run git commits, git pushes, or Dolt remote sync unless explicitly asked. At handoff, report changed files, validation, and suggested next commands. -- **Minimal**: Keep tool instruction files as pointers to `bd prime`; use the same conservative git policy unless active instructions say otherwise. -- **Team-maintainer**: Only when the repository explicitly opts in, agents may close beads, run quality gates, commit, and push as part of session close. A current "do not commit" or "do not push" instruction still wins. - ## Session Completion -This protocol applies when ending a Beads implementation workflow. It is subordinate to explicit user, repository, and orchestrator instructions. - -1. **File issues for remaining work** - Create beads for anything that needs follow-up -2. **Run quality gates** (if code changed) - Tests, linters, builds -3. **Update issue status** - Close finished work, update in-progress items -4. **Handle git/sync by active profile**: - ```bash - # Conservative/minimal/default: report status and proposed commands; wait for approval. - git status - - # Team-maintainer opt-in only, unless current instructions forbid it: - git pull --rebase - git push - git status - ``` -5. **Hand off** - Summarize changes, validation, issue status, and any blocked sync/commit/push step - -**Critical rules:** -- Explicit user or orchestrator instructions override this Beads block. -- Do not commit or push without clear authority from the active profile or the current user request. -- If a required sync or push is blocked, stop and report the exact command and error. - - - -## Beads Issue Tracker - -Use Beads (`bd`) for durable task tracking in repositories that include it. Use the `beads` skill at `.agents/skills/beads/SKILL.md` (project install) or `~/.agents/skills/beads/SKILL.md` (global install) for Beads workflow guidance, then use the `bd` CLI for issue operations. - -### Quick Reference - -```bash -bd ready # Find available work -bd show # View issue details -bd update --claim # Claim work -bd close # Complete work -bd prime # Refresh Beads context -``` - -### Rules - -- Use `bd` for all task tracking; do not create markdown TODO lists. -- Run `bd prime` when Beads context is missing or stale. Codex 0.129.0+ can load Beads context automatically through native hooks; use `/hooks` to inspect or toggle them. -- Keep persistent project memory in Beads via `bd remember`; do not create ad hoc memory files. - -**Architecture in one line:** issues live in a local Dolt DB; sync uses `refs/dolt/data` on your git remote; `.beads/issues.jsonl` is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns. - +1. **File issues for remaining work** - `bd create` for follow-up items +2. **Run quality gates** - `cargo build --release && cargo test` +3. **Close completed issues** - `bd close ...` +4. **PUSH** - `git add -A && git commit -m "..." && git push` +5. **Verify** - `git status` must show clean working tree \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index db14bd1..2038a0e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,77 +1,111 @@ -# Project Instructions for AI Agents - -This file provides instructions and context for AI coding agents working on this project. - - -## Beads Issue Tracker - -This project uses **bd (beads)** for issue tracking. Run `bd prime` to see full workflow context and commands. - -### Quick Reference - -```bash -bd ready # Find available work -bd show # View issue details -bd update --claim # Claim work -bd close # Complete work -``` - -### Rules - -- Use `bd` for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists -- Run `bd prime` for detailed command reference and session close protocol -- Use `bd remember` for persistent knowledge — do NOT use MEMORY.md files - -**Architecture in one line:** issues live in a local Dolt DB; sync uses `refs/dolt/data` on your git remote; `.beads/issues.jsonl` is a passive export. See https://github.com/gastownhall/beads/blob/main/docs/SYNC_CONCEPTS.md for details and anti-patterns. - -## Agent Context Profiles - -The managed Beads block is task-tracking guidance, not permission to override repository, user, or orchestrator instructions. - -- **Conservative (default)**: Use `bd` for task tracking. Do not run git commits, git pushes, or Dolt remote sync unless explicitly asked. At handoff, report changed files, validation, and suggested next commands. -- **Minimal**: Keep tool instruction files as pointers to `bd prime`; use the same conservative git policy unless active instructions say otherwise. -- **Team-maintainer**: Only when the repository explicitly opts in, agents may close beads, run quality gates, commit, and push as part of session close. A current "do not commit" or "do not push" instruction still wins. - -## Session Completion - -This protocol applies when ending a Beads implementation workflow. It is subordinate to explicit user, repository, and orchestrator instructions. - -1. **File issues for remaining work** - Create beads for anything that needs follow-up -2. **Run quality gates** (if code changed) - Tests, linters, builds -3. **Update issue status** - Close finished work, update in-progress items -4. **Handle git/sync by active profile**: - ```bash - # Conservative/minimal/default: report status and proposed commands; wait for approval. - git status - - # Team-maintainer opt-in only, unless current instructions forbid it: - git pull --rebase - git push - git status - ``` -5. **Hand off** - Summarize changes, validation, issue status, and any blocked sync/commit/push step - -**Critical rules:** -- Explicit user or orchestrator instructions override this Beads block. -- Do not commit or push without clear authority from the active profile or the current user request. -- If a required sync or push is blocked, stop and report the exact command and error. - +# Agent Instructions +This project uses **bd** (beads) for issue tracking. Run `bd prime` for full workflow context. ## Build & Test -_Add your build and test commands here_ +```bash +cargo build --release # Build binary +cargo test # Run unit tests +./target/release/nutrition-mcp # Run server (needs env vars) +``` + +### Smoke Test ```bash -# Example: -# npm install -# npm test +# Start server +NUTRITION_MCP_BIND=127.0.0.1:9432 NUTRITION_MCP_API_KEY=test \ + NUTRITION_MCP_DB_PATH=/tmp/test.db ./target/release/nutrition-mcp & + +# Health check +curl http://127.0.0.1:9432/health + +# MCP initialize +curl -X POST http://127.0.0.1:9432/mcp \ + -H "Authorization: Bearer test" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json, text/event-stream" \ + -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"0.1"}},"id":1}' ``` ## Architecture Overview -_Add a brief overview of your project architecture_ +MCP server exposing 13 tools for personal nutrition tracking. Streamable HTTP transport with Bearer token auth. + +### Module Map + +``` +src/ +├── main.rs — Entry point: axum server, auth middleware, /health endpoint +├── config.rs — Config struct from env vars (bind, api_key, db_path, user_agent) +├── db.rs — SQLite schema, migrations, DbPool type, TRACKED_NUTRIENTS const, DEFAULT_GOALS_JSON +├── api.rs — OffClient: Search-a-licious + v3 barcode + SQLite cache (FTS5) +└── tools.rs — NutritionServer: 13 MCP tools via #[tool_router] + ServerHandler impl +``` + +### SQLite Schema + +- **products** — OFF cache: code (PK), product_name, brands, nutriments (JSON), serving_quantity, serving_size, image_url +- **products_fts** — FTS5 virtual table on product_name (synced via triggers) +- **entries** — Food log: id, date, meal, product_code, food_name, grams, servings, nutriments (JSON, scaled to portion) +- **daily_goal** — Single row (id=1), goals JSON with 14 nutrient targets +- **weight_log** — id, date, weight_kg + +### Nutrient Storage + +All nutrients stored as JSON blob in `nutriments` TEXT column (verbatim from OFF API). Daily summaries use `json_extract()` or Rust-side parsing to aggregate the 14 tracked nutrients. + +### Portion Scaling + +Nutrients are stored per-100g in OFF data. When logging, `scale_nutriments()` multiplies each value by `grams / 100.0`. For servings, grams = `servings * serving_quantity`. + +### Meal Auto-Detection + +- breakfast: before 11:00 +- lunch: 11:00–15:00 +- dinner: 15:00–21:00 +- snack: after 21:00 ## Conventions & Patterns -_Add your project-specific conventions here_ +- **JSON nutriments** — Never hardcode nutrient columns. Store OFF nutriments verbatim as JSON, query at runtime. +- **"no data" vs 0** — Micronutrients (potassium, calcium, magnesium) are sparse in OFF. Summary shows `"no data"` when no entries have the nutrient, not 0. +- **Env vars only** — No config files. All settings via environment variables. +- **API-first** — Always check SQLite cache first, fall back to OFF API, cache results. +- **User-Agent** — Always send custom User-Agent to OFF API (good citizenship). + +## Tracked Nutrients (14) + +``` +energy_kcal → energy-kcal_100g +protein → proteins_100g +carbohydrates → carbohydrates_100g +fat → fat_100g +fiber → fiber_100g +sugars → sugars_100g +saturated_fat → saturated-fat_100g +salt → salt_100g +fructose → fructose_100g (gout) +alcohol → alcohol_100g (gout) +potassium → potassium_100g (hypertension) +calcium → calcium_100g (hypertension) +magnesium → magnesium_100g (hypertension) +cholesterol → cholesterol_100g (hypertension) +``` + +## Non-Interactive Shell Commands + +**ALWAYS use non-interactive flags** to avoid hanging on confirmation prompts. + +```bash +cp -f source dest # NOT: cp source dest +rm -f file # NOT: rm file +``` + +## Session Completion + +1. **File issues for remaining work** - `bd create` for follow-up items +2. **Run quality gates** - `cargo build --release && cargo test` +3. **Close completed issues** - `bd close ...` +4. **PUSH** - `git add -A && git commit -m "..." && git push` +5. **Verify** - `git status` must show clean working tree \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..227e6a1 --- /dev/null +++ b/README.md @@ -0,0 +1,165 @@ +# Nutrition MCP + +Personal calorie and nutrient tracking MCP server. Looks up food via OpenFood Facts, logs meals with portion-scaled nutrients, and tracks daily intake against gout and hypertension-aware goals. + +## Tech Stack + +- [Rust](https://www.rust-lang.org/) — Systems language +- [rmcp](https://github.com/modelcontextprotocol/rust-sdk) — Official Rust MCP SDK (streamable HTTP transport) +- [axum](https://github.com/tokio-rs/axum) 0.8 — Web framework for HTTP transport + auth middleware +- [sqlx](https://github.com/launchbadge/sqlx) 0.8 — Async SQLite +- [reqwest](https://github.com/seanmonstar/reqwest) 0.12 — HTTP client for OpenFood Facts APIs +- [SQLite](https://www.sqlite.org/) with FTS5 — Local database + full-text search + +## Health Context + +This tracker is configured for two specific health conditions: + +- **Gout** — Tracks fructose (15g/day limit) and alcohol (0 limit). Both are known gout triggers. +- **Hypertension** — Tracks salt (6g/day, NHS guideline), potassium (3500mg, helps lower BP), calcium (700mg), magnesium (300mg), and cholesterol (300mg). + +## 14 Tracked Nutrients + +| Nutrient | OFF field | Default goal | Unit | Reason | +|----------|-----------|-------------|------|--------| +| Energy | `energy-kcal_100g` | 2500 | kcal | General | +| Protein | `proteins_100g` | 150 | g | General | +| Carbohydrates | `carbohydrates_100g` | 300 | g | General | +| Fat | `fat_100g` | 70 | g | General | +| Fiber | `fiber_100g` | 30 | g | General | +| Sugars | `sugars_100g` | 90 | g | General | +| Saturated fat | `saturated-fat_100g` | 20 | g | Hypertension | +| Salt | `salt_100g` | 6 | g | Hypertension (key) | +| Fructose | `fructose_100g` | 15 | g | Gout (key) | +| Alcohol | `alcohol_100g` | 0 | % vol | Gout (key) | +| Potassium | `potassium_100g` | 3500 | mg | Hypertension (key) | +| Calcium | `calcium_100g` | 700 | mg | Hypertension | +| Magnesium | `magnesium_100g` | 300 | mg | Hypertension | +| Cholesterol | `cholesterol_100g` | 300 | mg | Hypertension | + +## MCP Tools (13) + +### Food Lookup +- `search_food(query, page_size?)` — Full-text search via OpenFood Facts Search-a-licious +- `get_food_by_barcode(barcode)` — Product lookup by barcode via OFF API v3 + +### Logging +- `log_food(product_code, grams?, servings?, date?, meal?)` — Log OFF product with portion scaling +- `log_custom_food(name, calories, nutriments?, grams, date?, meal?)` — Log homemade/restaurant food +- `delete_entry(id)` — Remove a logged entry + +### Summary & History +- `daily_summary(date?)` — All 14 nutrients vs goals, remaining, entry list +- `history(days?)` — Last N days of totals (default 7) +- `list_entries(date?)` — List entries with IDs for deletion + +### Goals +- `get_goals()` — Current daily nutrient targets +- `set_goals(goals)` — Update goals (partial merge) + +### Weight +- `log_weight(weight_kg, date?)` — Log body weight in kg +- `weight_history(days?)` — Weight trend (default 30 days) + +### Future +- `bulk_import(parquet_url?)` — Stub for offline Parquet import + +## Build + +```bash +cargo build --release +``` + +Binary: `target/release/nutrition-mcp` + +## Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `NUTRITION_MCP_BIND` | `0.0.0.0:9432` | Bind address | +| `NUTRITION_MCP_API_KEY` | (random UUID) | Bearer token for auth | +| `NUTRITION_MCP_DB_PATH` | `~/.local/share/nutrition/nutrition.db` | SQLite database path | +| `NUTRITION_MCP_OFF_USER_AGENT` | `NutritionMCP/0.1.0 (personal use)` | User-Agent for OFF API | + +## Run + +```bash +NUTRITION_MCP_API_KEY=your-secret-key \ +NUTRITION_MCP_BIND=0.0.0.0:9432 \ +./target/release/nutrition-mcp +``` + +### Health Check + +```bash +curl http://localhost:9432/health +# → OK +``` + +### MCP Connect + +```bash +curl -X POST http://localhost:9432/mcp \ + -H "Authorization: Bearer your-secret-key" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json, text/event-stream" \ + -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"0.1"}},"id":1}' +``` + +## Deploy as systemd Service + +```bash +# Create service file +cat > ~/.config/systemd/user/nutrition-mcp.service << 'EOF' +[Unit] +Description=Nutrition MCP Server +After=network.target + +[Service] +ExecStart=%h/workspace/nutrition-mcp/target/release/nutrition-mcp +Environment=NUTRITION_MCP_BIND=0.0.0.0:9432 +Environment=NUTRITION_MCP_API_KEY=your-secret-key +Environment=NUTRITION_MCP_DB_PATH=%h/.local/share/nutrition/nutrition.db +Environment=NUTRITION_MCP_OFF_USER_AGENT=NutritionMCP/0.1.0 (personal use; contact: atradeus@pm.me) +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=default.target +EOF + +# Enable linger (survive logout) +loginctl enable-linger $USER + +# Start +systemctl --user daemon-reload +systemctl --user enable --now nutrition-mcp +``` + +## Connect from Hermes + +```bash +hermes mcp add nutrition --url http://localhost:9432 --header "Authorization: Bearer your-secret-key" +``` + +## Connect from Laptop (LAN) + +```bash +hermes mcp add nutrition --url http://chronos:9432 --header "Authorization: Bearer your-secret-key" +``` + +## Data Sources + +- [OpenFood Facts Search-a-licious](https://search.openfoodfacts.org) — Full-text product search +- [OpenFood Facts API v3](https://world.openfoodfacts.org/api/v3) — Barcode lookups +- [OpenFood Facts Parquet](https://huggingface.co/datasets/openfoodfacts/product-database) — Future offline bulk import (7.82 GB, 4.7M products) + +All food data is cached locally in SQLite with FTS5 for instant repeat lookups. + +## Architecture + +See [AGENTS.md](./AGENTS.md) for full project instructions, conventions, and module map. + +## License + +MIT \ No newline at end of file