Hydration tracking and coaching skill. Use when user wants to track water intake, get reminders to drink water, log body metrics (weight, body fat, muscle %,...
---
name: water-coach
description: "Hydration tracking and coaching skill. Use when user wants to track water intake, get reminders to drink water, log body metrics, or get analytics on hydration habits."
compatibility: "Requires python3, openclaw cron feature, heartbeat feature"
metadata: {"clawdbot":{"emoji":"๐ง"}
author: oristides
---
# ๐ง Water Coach
## First-time Setup
Follow the first setup here [references/setup.md](references/setup.md)
---
## ๐ค How Other Agents Should Interact
### First-time Setup Check
```bash
water setup
```
| is_setup | What to do |
|----------|-------------|
| **false** | Ask: weight OR desired goal. Also ask: "What times do you want water reminders?" (let user configure their schedule). Then use `water set_body_weight 80` or `water set_goal 3000`. Don't assume hardcoded times! |
| **true** | Skip setup. Just log water or show status. |
### โ Don't Ask
- Reminder schedules after first setup (user already configured)
### โ
Do Ask
- "How much water did you drink?"
- Only weight/goal (first time)
---
## CLI Structure
```bash
water_coach.py <namespace> <command> [options]
```
Namespaces: `water` | `body` | `analytics`
---
## Data Format
### CSV Format
```
logged_at,drank_at,date,slot,ml_drank,goal_at_time,message_id
```
| Column | Description |
|--------|-------------|
| logged_at | When user told you (NOW) |
| drank_at | When user actually drank (user can specify past time) |
| date | Derived from drank_at |
| slot | morning/lunch/afternoon/evening/manual |
| ml_drank | Amount in ml |
| goal_at_time | Goal at that moment |
| message_id | Audit trail - link to conversation |
**Key Rules:**
- **drank_at is MANDATORY** - always required
- If user doesn't specify drank_at โ assume drank_at = logged_at
- **Cumulative is calculated at query time** (not stored)
- Use drank_at to determine which day counts
Details at [references/log_format.md](references/log_format.md)
### Audit Trail
Every water log entry captures:
- **message_id**: Links to the conversation message where user requested the log
- **Auto-capture**: CLI automatically gets message_id from session transcript
- **Proof**: Use `water audit <message_id>` to get entry + conversation context
```bash
# Check proof of a water entry
water audit msg_123
# Returns: entry data + surrounding messages for context
```
> โ ๏ธ **Privacy Notice**: The audit feature can read your conversation transcripts, but **only when you explicitly run `water audit <message_id>`**. This is off by default (`audit_auto_capture: false`).
>
> ```bash
> # Edit water_config.json and set:
> "audit_auto_capture": true
> ```
>
> **How it works:**
> - Water log **always** saves the `message_id` (regardless of this setting) โ
> - When you run `water audit <message_id>`:
> - If `false`: Shows entry data only (message_id saved, but no context read)
> - If `true`: Also reads transcript to show conversation context ("User said: I drank 500ml")
>
> **Why disable it?** If you discuss sensitive topics and don't need proof of intake, leave it off.
---
## Daily Commands
```bash
# Water
water status # Current progress (calculated from drank_at)
water log 500 # Log intake (drank_at = now)
water log 500 --drank-at=2026-02-18T18:00:00Z # Log with past time
water log 500 --drank-at=2026-02-18T18:00:00Z --message-id=msg_123
water dynamic # Check if extra notification needed
water threshold # Get expected % for current hour
water set_body_weight 80 # Update weight + logs to body_metrics
water set_body_weight 80 --update-goal # + update goal
water audit <message_id> # Get entry + conversation context
# Body
body log --weight=80 --height=1.75 --body-fat=18
body latest # Get latest metrics
body history 30 # Get history
# Analytics
analytics week # Weekly briefing (Sunday 8pm)
analytics month # Monthly briefing (2nd day 8pm)
```
---
## Rules (MUST FOLLOW)
1. **ALWAYS use CLI** - never calculate manually
2. **LLM interprets first** - "eu tomei 2 copos" โ 500ml โ water log 500
3. **Threshold from CLI** - run `water threshold`, don't hardcode
4. **GOAL is USER'S CHOICE** - weight ร 35 is just a DEFAULT suggestion:
- At setup: Ask weight โ suggest goal โ **CONFIRM with user**
- On weight update: Ask "Want to update your goal to the new suggested amount?"
- User can set any goal (doctor's orders, preference, etc.)
---
## Config Tree
```
water-coach/
โโโ SKILL.md โ You are here
โโโ scripts/
โ โโโ water_coach.py โ Unified CLI
โ โโโ water.py โ Core functions
โโโ data/ โ DO NOT USE - keep skill code separate from user data
โโโ references/
โโโ setup.md
โโโ dynamic.md
โโโ log_format.md
```
### โ ๏ธ IMPORTANT: Data Location
**User data is stored in the AGENT WORKSPACE, NOT in the skill folder!**
| Data | Location |
|------|----------|
| water_log.csv | `<agent-workspace>/memory/data/water_log.csv` |
| water_config.json | `<agent-workspace>/memory/data/water_config.json` |
| body_metrics.csv | `<agent-workspace>/memory/data/body_metrics.csv |
Example path: `/home/oriel/.openclaw/workspace/memory/data/`
**Why?** Keeps user data separate from skill code โ makes backups, migrations, and skill updates easier.
---
## Notifications Schedule
| Type | When | Command |
|------|------|---------|
| User Configured | Per user's schedule | water status |
| Default Suggestion | 9am, 12pm, 3pm, 6pm, 9pm | water status |
| Dynamic | Every ~30 min (heartbeat) | water dynamic |
| Weekly | Sunday 8pm | analytics week |
| Monthly | 2nd day 8pm | analytics month |
### Notification Rules (MUST FOLLOW)
- **USER CONFIGURES THEIR SCHEDULE** โ Agent should ask user: "What times do you want water reminders?" and respect that
- **NO "no log" skip logic** โ Always send notifications when scheduled, don't skip because user hasn't logged water
- **Notifications STIMULATE logging** โ That's the point! Don't assume user will log on their own
---
## Quick Reference
| Task | Command |
|------|---------|
| Check progress | `water_coach.py water status` |
| Log water | `water_coach.py water log 500` |
| Need extra? | `water_coach.py water dynamic` |
| Body metrics | `water_coach.py body log --weight=80` |
| Weekly report | `water_coach.py analytics week` |
| Monthly report | `water_coach.py analytics month` |
## Dynamic Scheduling details
โ [references/dynamic.md](references/dynamic.md)
### โ ๏ธ Bug Fix (Feb 2026)
The `water dynamic` command had a bug where the hourly notification counter wouldn't reset when the hour changed. This is now fixed:
- The script now checks if the current hour differs from `last_extra_hour` and resets the counter accordingly
- This ensures notifications work correctly after hour boundaries (e.g., 4PM)
### โ ๏ธ Bug Fix (Feb 2026) - Analytics
The `analyticsPM โ 5 week` and `analytics month` commands had a bug:
- Was looking for non-existent `cumulative_ml` column in CSV
- Fixed to sum `ml_drank` per day instead
### โ
How to Build Good Weekly/Monthly Reports
**Use these functions (don't reinvent):**
| Report | Script | Function |
|--------|--------|----------|
| Weekly | `water_coach.py analytics week` | `analytics_week()` in `water_coach.py` |
| Monthly | `water_coach.py analytics month` | `analytics_month()` in `water_coach.py` |
These call `get_week_stats()` and `get_month_stats()` in `water.py`.
**When updating analytics functions, follow these rules:**
**1. Include ALL days, even with 0ml**
```python
# In get_week_stats() / get_month_stats()
# Include every day in the range, not just days with data
for i in range(days):
d = (date.today() - timedelta(days=i)).strftime("%Y-%m-%d")
ml = by_date.get(d, {}).get("ml", 0) # Default to 0, not skip
```
**2. Calculate true average**
```python
# Average = total_ml / ALL days (including zeros), not just tracked days
avg_ml = total_ml / days # e.g., 15440ml / 7 days = 2205ml/day
```
**3. Show all days in table format**
```python
| Dia | ML | % | Status |
| Sab 22 | 2250ml | 67.7% | โ ๏ธ |
| Seg 17 | 0ml | 0.0% | โ |
```
This gives users an accurate picture of their habits!
## Tests
```bash
python3 -m pytest skills/water-coach/scripts/test/test_water.py -v
```
## Example
```
User: "eu tomei 2 copos"
Agent: (LLM interprets: 2 copos โ 500ml)
Agent: exec("water_coach.py water log 500")
โ Python logs to CSV
```
Agent Evaluations โ [evaluation/AGENT.md](evaluation/AGENT.md)
don't have the plugin yet? install it then click "run inline in claude" again.