Metadata-Version: 2.4
Name: hermes-life-os
Version: 1.25.0
Summary: The personal OS that grows with you - mood, sleep, nutrition and habit tracking with pattern detection, built for Ollama/OpenAI/Anthropic/OpenRouter.
Author: Kıvanç
License: MIT License
        
        Copyright (c) 2026 Lethe*
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/Lethe044/hermes-life-os
Project-URL: Repository, https://github.com/Lethe044/hermes-life-os
Project-URL: Issues, https://github.com/Lethe044/hermes-life-os/issues
Keywords: life-os,self-tracking,llm-agent,habit-tracker,mood-tracker,ollama,anthropic,openai
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: openai>=1.0.0
Requires-Dist: rich>=13.0.0
Requires-Dist: pyyaml>=6.0
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.34.0; extra == "anthropic"
Provides-Extra: dashboard
Requires-Dist: matplotlib>=3.7.0; extra == "dashboard"
Provides-Extra: encryption
Requires-Dist: cryptography>=42.0.0; extra == "encryption"
Provides-Extra: voice
Requires-Dist: faster-whisper>=1.0.0; extra == "voice"
Provides-Extra: discord
Requires-Dist: discord.py>=2.3.0; extra == "discord"
Provides-Extra: slack
Requires-Dist: slack_bolt>=1.18.0; extra == "slack"
Provides-Extra: whatsapp
Requires-Dist: flask>=3.0.0; extra == "whatsapp"
Requires-Dist: twilio>=8.0.0; extra == "whatsapp"
Provides-Extra: api
Requires-Dist: flask>=3.0.0; extra == "api"
Provides-Extra: web
Requires-Dist: flask>=3.0.0; extra == "web"
Provides-Extra: all
Requires-Dist: anthropic>=0.34.0; extra == "all"
Requires-Dist: matplotlib>=3.7.0; extra == "all"
Requires-Dist: cryptography>=42.0.0; extra == "all"
Requires-Dist: faster-whisper>=1.0.0; extra == "all"
Requires-Dist: discord.py>=2.3.0; extra == "all"
Requires-Dist: slack_bolt>=1.18.0; extra == "all"
Requires-Dist: flask>=3.0.0; extra == "all"
Requires-Dist: twilio>=8.0.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Dynamic: license-file

# Hermes Life OS 🧠

[![Tests](https://github.com/Lethe044/hermes-life-os/actions/workflows/tests.yml/badge.svg)](https://github.com/Lethe044/hermes-life-os/actions/workflows/tests.yml)
[![PyPI](https://img.shields.io/pypi/v/hermes-life-os)](https://pypi.org/project/hermes-life-os/)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)

**The personal OS that grows with you.**

> Built for the NousResearch "Show us what Hermes Agent can do" hackathon.

Most productivity tools forget you the moment you close them.
Hermes Life OS remembers everything - your mood, your meals, your sleep, your stress,
your wins and your struggles - and gets smarter about you every single day.

## What It Does

Tell it how you feel. Log what you ate. Track your sleep.
Over time it starts connecting dots you haven't: energy crashes after poor sleep,
mood dips on low-hydration days, focus drops when stress spikes.
Every morning it briefs you. Every evening it reflects with you.
Every week it tells you what the data says about your life.

**The longer you use it, the more it knows. The more it knows, the more useful it becomes.**

## Architecture

```mermaid
flowchart TD
    A([👤 You share something]) --> B
    B[🧠 REMEMBER<br/>Mood · Sleep · Meals<br/>Stress · Focus · Habits] --> C
    C[🔍 RECALL<br/>Search memory<br/>for context] --> D
    D[📊 DETECT PATTERNS<br/>Correlations across<br/>all life dimensions] --> E
    E[📋 BRIEF<br/>Personalized insight<br/>based on YOUR data] --> F
    F([🌱 Hermes knows you<br/>a little better today])

    G([⏰ Cron Schedule<br/>07:00 Morning<br/>12:00 Midday<br/>18:00 Evening<br/>23:00 Consolidate<br/>Mon 08:00 Weekly]) --> C

    style A fill:#2980b9,color:#fff
    style F fill:#27ae60,color:#fff
    style G fill:#8e44ad,color:#fff
    style D fill:#e67e22,color:#fff
```

## Hermes Features Used

| Feature | How It's Used |
|---------|--------------|
| **Memory** | Stores every mood, meal, sleep entry, workout, stress log - recalls before every response |
| **Skills** | Life OS playbook defines daily rhythm, pattern detection rules, and briefing format |
| **Cron** | Automated briefings at 07:00, 12:00, 18:00, 23:00, and weekly Monday reviews |
| **Gateway** | Delivers briefings via terminal - extensible to Telegram, email, SMS |
| **Subagents** | Pattern detection runs across all health dimensions in parallel |
| **Atropos RL** | Reward function trains Hermes to be more personal and memory-driven over time |

## Tracking Capabilities

| Category | What Hermes Tracks |
|----------|-------------------|
| 🥗 Nutrition | Meals, calories, protein/carbs/fat, daily totals |
| 😴 Sleep | Duration, quality score, 7-day averages |
| 💧 Hydration | Daily water intake with progress bar |
| 💪 Fitness | Workouts, duration, intensity, weekly count |
| 🧘 Mental | Stress levels, meditation sessions, gratitude logs |
| 🎯 Focus | Deep work sessions, distractions, quality scores |
| ✅ Habits | Streaks, best streaks, completion tracking |
| 🎯 Goals | Progress percentages, milestones, notes |
| 😊 Mood & Energy | Daily scores, trend detection, dip alerts |
| 💰 Spending | Expenses by category, daily/period totals |
| 🤝 Social | Time connecting with others, quality, trend |
| ☕ Substances | Caffeine, alcohol, or anything else - amount, frequency |
| 📚 Reading | Sessions, minutes, pages, titles |
| 💊 Medication | Dose taken/skipped, adherence % by medication |

## Pattern Detection

Hermes automatically detects and surfaces:
- Mood dips lasting 3+ consecutive days
- Sleep deprivation affecting focus and mood
- Energy crashes correlated with nutrition gaps
- Stress spikes and their triggers
- Habit streaks worth celebrating
- Goal stalls that need a nudge
- Hydration gaps on high-stress days

### Correlation Engine

`demo/analytics.py` computes real Pearson correlation coefficients between
tracked metrics (mood, sleep, stress, energy, hydration) using daily-averaged
values from memory. A pair is only surfaced when there's enough data
(4+ overlapping days by default) and the relationship is meaningful
(|r| >= 0.4). Each result reports the direction (positive/negative), strength
(weak/moderate/strong), and the number of days behind it - no external
dependencies required (pure Python stdlib).

**Lagged (predictive) correlations:** same-day correlation can't tell you
whether poor sleep caused today's low mood, or whether being stressed
already caused last night's poor sleep - it just says the two move
together. `compute_lagged_correlations()` shifts one metric forward by
1-2 calendar days (correctly handling gaps from unlogged days) before
correlating, which at least points the arrow of time forward: "a higher
X on one day tends to be followed by a higher/lower Y N days later."
Both same-day and lagged results feed every surface that already shows
insights (chat replies, `detect_patterns`, the static and live
dashboards, the weekly email) automatically, plus a dedicated
`get_correlation_insights` tool for a deeper, on-demand analysis over
a custom day range - just ask "what patterns have you noticed in my
data?" or "what predicts my mood?".

## Reward Function

```mermaid
pie title Life OS Reward Components
    "Briefing Sent - Delivered via send_briefing?" : 30
    "Memory Used - Recalled AND remembered?" : 25
    "Pattern Detected - Called detect_patterns?" : 20
    "Personalization - Referenced real context?" : 15
    "Tool Coverage - Used expected tools?" : 10
```

## Quick Start

Works with four LLM backends - pick whichever you already have. The
provider is auto-detected from whatever key is set (or force one with
`--provider`).

```bash
pip install "hermes-life-os[all]"

# Option A - free, fully local, no API key:
ollama serve
ollama pull llama3.1

# Option B / C / D - pick one:
set ANTHROPIC_API_KEY=sk-ant-...
set OPENAI_API_KEY=sk-...
set OPENROUTER_API_KEY=sk-or-...

hermes-life-os --mode onboard
hermes-life-os --mode morning
hermes-life-os --mode chat

# force a specific backend regardless of which keys are set:
hermes-life-os --mode morning --provider anthropic
```

Prefer running from source instead of installing? Clone the repo and use
`python demo/demo_life_os.py ...` in place of `hermes-life-os ...` above
(same flags, same behavior) - see [Project Structure](#project-structure).

### Or run it with Docker - zero Python setup

```bash
# pull the pre-built image - no clone needed:
docker run --rm -it -e ANTHROPIC_API_KEY=sk-ant-... \
    -v hermes-life-os-data:/root/.hermes \
    ghcr.io/lethe044/hermes-life-os:latest --mode morning
```

Or build it yourself, and get a fully free trial paired with a local
Ollama container (no API key at all):

```bash
git clone https://github.com/Lethe044/hermes-life-os.git
cd hermes-life-os

docker compose up -d ollama
docker compose exec ollama ollama pull llama3.1
docker compose run --rm hermes-life-os --mode onboard
```

## All Demo Modes

| Mode | What Happens |
|------|-------------|
| `onboard` | First-time setup - Hermes learns who you are |
| `morning` | Daily briefing based on all your patterns |
| `checkin` | Midday log - mood, habits, quick nudge |
| `evening` | Evening reflection - wins, struggles, patterns |
| `weekly` | Sunday review - what this week says about you |
| `nutrition` | Log meals and get nutrition insights |
| `sleep` | Log sleep and get sleep analysis |
| `fitness` | Log workouts and track fitness patterns |
| `mental` | Log stress, meditation, and gratitude |
| `focus` | Log deep work sessions and productivity |
| `health` | Full health dashboard - all data in one view |
| `dream` | **Dream journal** - log dreams, detect patterns, sleep/stress correlation |
| `chat` | **Interactive conversation** - type anything |

## Chat Mode

```bash
python demo/demo_life_os.py --mode chat
```

Type naturally. Hermes responds using everything it knows about you.
Type `exit` to leave.

Example conversations:
- "I feel stressed today, any advice?"
- "Log my lunch - grilled chicken and rice, about 600 calories"
- "How has my sleep been this week?"
- "I just ran 5km, log it"
- "What patterns are you seeing in my data?"
- "I logged 4 hours of sleep by mistake, it was actually 7" - Hermes recalls
  the entry and corrects it
- "Delete that last mood entry, I misclicked" - Hermes finds and removes it
  (asks for confirmation first)
- "Set a goal to sleep 7+ hours a night" - Hermes tracks this automatically
  from your actual logged sleep, no manual progress updates needed
- "How am I doing on my goals?" / "How does this week compare to last week?"
- "Has anything been unusual lately?" / "How was I in March?"

## Multi-Profile (shared households)

```bash
python demo/demo_life_os.py --mode morning --profile alex
python demo/dashboard.py --profile alex
```

By default everything lives at `~/.hermes/life-os/` (unchanged, single
person). Passing `--profile <name>` (or setting `LIFE_OS_PROFILE`) fully
isolates that person's data under `~/.hermes/life-os/profiles/<name>/` -
so a household can share one install without mixing anyone's mood/sleep/
habit data. Omitting `--profile` always keeps working exactly as before.

## Multi-User (real accounts for the local API & Slack bot)

```bash
python demo/users.py add alex --profile alex --role owner
python demo/users.py add sam  --profile sam
python demo/users.py list
```

Profiles isolate data; this registry is what turns a profile into a
*person who can log in*. Each user gets their own API key (shown once,
stored only as a salted PBKDF2 hash) that resolves to their own profile
automatically - so a whole household or small team can share one running
`hermes-life-os-api` server or one Slack bot, and everyone only ever
sees their own data:

```bash
curl -H "X-API-Key: <alex's key>" http://127.0.0.1:8765/api/health
# {"status": "ok", "profile": "alex", "user": "alex"}
```

Fully opt-in and non-breaking - a single `LIFE_OS_API_KEY`/`--profile`
keeps working exactly as before if you never touch `users.py`. Full
setup, including linking a user to their Slack account, in
[docs/MULTI_USER.md](docs/MULTI_USER.md).

## Plugin System (add your own tools, no fork required)

```bash
mkdir -p ~/.hermes/life-os/plugins
cp demo/plugins_examples/dice.py ~/.hermes/life-os/plugins/
python demo/demo_life_os.py --mode chat
# "roll a d20 for me"
```

Drop a `.py` file defining a `TOOLS` list and a `dispatch(name, inp)`
function into `~/.hermes/life-os/plugins/`, and Hermes' LLM agent can
call it like any built-in tool - next start, no core code changes. A
broken plugin is skipped and reported, never crashes the app; a plugin
can't shadow a built-in tool name. `python demo/plugins.py` lists
everything currently loaded. Two ready-to-copy examples ship in
`demo/plugins_examples/` (a dependency-free dice/coin-flip tool, and a
profile-aware screen-time tracker showing how to persist your own data).
Full plugin API and a "share it with others" guide in
[docs/PLUGINS.md](docs/PLUGINS.md).

## Encryption at Rest (optional)

```bash
set LIFE_OS_ENCRYPTION_KEY=your-passphrase-here
python demo/demo_life_os.py --mode morning
```

Off by default - nothing changes unless you set this. When set, every
data file (profile, habits, goals, nutrition, sleep, etc.) and every line
of `memory.jsonl` is encrypted at rest with a key derived from your
passphrase (PBKDF2-HMAC-SHA256 + Fernet/AES). Existing plaintext data is
read transparently and gets encrypted the next time it's written - no
separate migration step. **There is no password recovery** - if you lose
the passphrase, that data is unrecoverable by design. Requires
`pip install "hermes-life-os[encryption]"` (or `pip install cryptography`
if running from source).

**Changing your passphrase:** use `hermes-life-os-rekey` rather than
just setting a new `LIFE_OS_ENCRYPTION_KEY` - the latter would leave
your existing files encrypted under the *old* key, unreadable. The
re-key tool decrypts everything with the old key, rotates the salt, and
re-encrypts everything with the new one in one step (it also works to
enable encryption for the first time, or disable it entirely):

```bash
hermes-life-os-backup                                    # back up first
hermes-life-os-rekey --old-key "old pass" --new-key "new pass"
hermes-life-os-rekey --new-key "new pass"                # enable for the first time
hermes-life-os-rekey --disable                           # decrypt everything back to plaintext
```

## Project Structure

```mermaid
graph LR
    A[hermes-life-os] --> B[skills/]
    A --> C[environments/]
    A --> D[demo/]
    A --> E[tests/]
    A --> F[docs/]

    B --> B1[life-os/SKILL.md<br/>Daily rhythm playbook]
    C --> C1[life_os_env.py<br/>Atropos RL environment]
    C --> C2[life_os_config.yaml<br/>Training config]
    D --> D1[demo_life_os.py<br/>CLI / chat / voice orchestration]
    D --> D2[storage.py<br/>Persistence layer]
    D --> D3[patterns.py<br/>Trend detection]
    D --> D4[analytics.py<br/>Pearson correlation engine]
    D --> D5[tools.py<br/>dispatch_tool + TOOLS schema]
    D --> D6[scheduler.py<br/>Cron-style trigger engine]
    D --> D7[notifications.py<br/>console/webhook/Telegram/email]
    D --> D8[run_scheduler.py<br/>Production scheduler entry point]
    D --> D9[plugins.py<br/>Community tool plugin loader]
    D --> D12[life_score.py<br/>Composite 0-100 wellbeing score]
    D --> D13[achievements.py<br/>Streak &amp; milestone badges]
    D --> D14[wrapped.py<br/>Shareable summary card]
    D --> D15[recommendations.py<br/>Rule-based suggestion engine]
    D --> D16[weather.py<br/>Open-Meteo weather correlation]
    D --> D17[life_review.py<br/>Quarterly/yearly retrospective report]
    D --> D18[leaderboard.py<br/>Opt-in household/team leaderboard]
    D --> D19[prompts.py<br/>Deterministic daily reflection prompts]
    D --> D20[moon.py<br/>Local moon phase correlation]
    D --> D21[sleep_debt.py<br/>Sleep debt & bedtime suggestions]
    D --> D22[heatmap.py<br/>GitHub-style SVG contribution heatmap]
    D --> D23[focus_timer.py<br/>Terminal Pomodoro timer]
    D --> D10[users.py<br/>Multi-user registry]
    D --> D11[slack_bot.py<br/>Slack Socket Mode bot]
    E --> E1[test_life_os_env.py]
    E --> E2[test_analytics.py]
    E --> E3[test_storage.py]
    E --> E4[test_tools.py]
    E --> E5[test_scheduler.py]
    E --> E6[test_notifications.py]

    style B1 fill:#27ae60,color:#fff
    style C1 fill:#8e44ad,color:#fff
    style D1 fill:#2980b9,color:#fff
    style D6 fill:#e67e22,color:#fff
    style D7 fill:#e67e22,color:#fff
    style D9 fill:#c0392b,color:#fff
    style D10 fill:#c0392b,color:#fff
    style D11 fill:#c0392b,color:#fff
```

`demo_life_os.py` used to be a single ~1600-line file. It's now a thin
CLI/chat/voice orchestration layer that imports its storage, pattern
detection, and tool-dispatch logic from focused sibling modules -
each independently testable and reusable.

## Scheduling & Notifications

`demo/scheduler.py` implements the "Daily Rhythm" cron table from
`skills/life-os/SKILL.md` (07:00 morning, 12:00 midday, 18:00 evening,
Monday 08:00 weekly, 20:00 proactive nudge check) as a dependency-free
polling loop. The scheduling logic itself (`due_entries`) is pure and
fully unit tested; the actual briefing generation and delivery are
injected as callables, so the core engine has no dependency on the
OpenAI client or network access. The 20:00 nudge check is LLM-free
(see "Proactive Nudges" above) and stays silent when there's nothing
worth flagging.

`demo/notifications.py` delivers briefings through a pluggable channel,
selected via `HERMES_NOTIFY_CHANNEL`: `console` (default), `webhook`,
`telegram`, or `email` (SMTP). All channels are stdlib-only. A failed
remote channel never crashes the scheduler - it's caught, logged, and
the briefing still prints to console.

To run the scheduler in production:

```bash
set ANTHROPIC_API_KEY=sk-ant-...   # or OPENAI_API_KEY / OPENROUTER_API_KEY / a running ollama
set HERMES_NOTIFY_CHANNEL=telegram
set TELEGRAM_BOT_TOKEN=...
set TELEGRAM_CHAT_ID=...
python demo/run_scheduler.py
```

## Voice Mode

```bash
python demo/demo_life_os.py --voice
# or pin a backend/model explicitly:
python demo/demo_life_os.py --voice --provider anthropic --model claude-sonnet-5
```

Speak to Hermes directly. It listens via microphone, processes your input using
everything it knows about you, and responds out loud via system TTS.

No extra API key needed - uses built-in Windows/Linux speech synthesis.

To stop: say or type `exit`

---

## Dashboard

```bash
pip install "hermes-life-os[dashboard]"   # or: pip install matplotlib (running from source)
hermes-life-os-dashboard
hermes-life-os-dashboard --days 60 --compare-days 7 --out my-report.html
```

Turns your logged mood/sleep/stress/energy/hydration data and the
correlations Hermes already detects (e.g. "poor sleep tracks with lower
mood, r=0.62") into a single self-contained HTML report with charts -
opens straight in your browser, no server, nothing leaves your machine.
Needs no LLM/API key at all - it's pure local data analysis. Includes a
retrospective section comparing this week to last week (`--compare-days`
changes the window size), color-coded by whether the change is favorable -
a stress increase shows red, a mood increase shows green.

![Example dashboard trend chart](docs/images/dashboard-example.png)

*Example output from 28 days of sample data - your own chart will reflect
whatever you've actually logged.*

## Live Web Dashboard

```bash
pip install "hermes-life-os[web]"   # or: pip install flask
hermes-life-os-web
# open http://127.0.0.1:8080
```

The interactive, always-current counterpart to the static HTML report
above - same trends/correlations/retrospective/habit data, served as
JSON and rendered client-side with Chart.js, so switching the day-range
re-fetches and re-draws instantly instead of regenerating a file.
Localhost-only by default and read-only (no API key needed, unlike the
Local REST API below) - it only ever reads your own data for your own
browser. See `demo/web_dashboard.py`'s docstring before changing
`--host` beyond `127.0.0.1`.

## Goal Tracking

Goals can track themselves from real data instead of needing manual
progress updates - just tell Hermes what to track:

- "Set a goal to sleep 7+ hours a night" -> auto-tracks against your
  logged sleep, direction "at_least"
- "Set a goal to keep stress under 4" -> direction "at_most"
- "How am I doing on my goals?" -> recomputes and reports current progress

Progress is the average of the linked metric over a rolling window
(7 days by default) relative to the target, clamped to 0-100%. Goals
without a linked metric keep working exactly as before - a plain
percentage you update manually.

## Health Data Import

```bash
pip install hermes-life-os
hermes-life-os-import --apple-health export.xml
hermes-life-os-import --csv my_data.csv
hermes-life-os-import --csv my_data.csv --dry-run   # preview without writing
```

Reduces manual one-entry-at-a-time logging by bulk-importing data you
already have, with real historical dates preserved (not stamped "today"):

- **Apple Health** (`export.xml` from Health app -> profile icon -> Export
  All Health Data): imports Sleep Analysis and Dietary Water records,
  aggregated per day.
- **Generic CSV**: any file with a `date` column (YYYY-MM-DD) plus any
  subset of `sleep_hours, mood, stress, energy, hydration` columns - works
  for a Google Fit CSV export or your own spreadsheet.

Imported entries are tagged so they're distinguishable from entries
logged live through chat.

## Calendar Import (meeting load vs. mood/stress)

```bash
hermes-life-os-calendar --ics calendar.ics
hermes-life-os-calendar --ics calendar.ics --dry-run
```

Correlates meeting-heavy days with mood/stress/sleep - no OAuth or live
API needed, just a standard `.ics` export (Google Calendar: Settings ->
Import & export -> Export; Outlook: File -> Save Calendar; Apple
Calendar: File -> Export). Only timed events count toward meeting hours
(all-day events are skipped); recurring events count once, on their
start date. Once imported, ask Hermes "is my stress linked to
meeting-heavy days?" or check the dashboard's Correlations section.

## Deeper Analysis: Anomalies & Before/After Comparisons

- "Has anything been unusual lately?" -> flags statistical outlier days
  (e.g. "today's stress was far above your normal range")
- "Did starting meditation on March 1st actually help?" -> compares
  metric averages before vs. after a specific date, instead of just a
  fixed weekly window
- "How was I in March?" / "Summarize last month" -> pulls real averages
  and notable entries (gratitude, dreams, notes) for any date range you
  ask about

## Proactive Nudges

The scheduler (see above) includes a daily check (20:00 by default) that
looks for anything worth flagging - an unusual day, a goal falling
behind - using the same deterministic analysis as the tools above, with
no LLM call needed. It stays silent on days with nothing notable, so it
won't spam you.

## Data Export

```bash
hermes-life-os-export --json backup.json --csv summary.csv
```

Your data isn't locked in. `--json` writes a complete backup (every
memory entry plus profile/habits/goals/logs, unmodified). `--csv` writes
a daily summary in the same shape `hermes-life-os-import --csv` expects -
export, edit in a spreadsheet, and re-import elsewhere if you want.

## Telegram Bot

```bash
set TELEGRAM_BOT_TOKEN=...     # from @BotFather
set TELEGRAM_CHAT_ID=...       # your own numeric chat id
hermes-life-os-telegram
```

Talk to Hermes from your phone - no server, no webhook, just long
polling (keep the process running, e.g. in `tmux`/`screen` or as a
background service). Only messages from `TELEGRAM_CHAT_ID` are ever
processed, so your data stays private even if someone finds your bot's
username. See `demo/telegram_bot.py`'s docstring for the exact setup
steps (getting a token and finding your chat id).

**Model reliability note:** this project defines a lot of tools (27+).
Small/CPU-friendly local models (e.g. `llama3.2:3b`) can struggle to use
them reliably - they may log things you didn't ask for, or occasionally
emit a raw tool-call attempt as plain text instead of actually calling
the tool (Hermes detects and filters that specific failure so you never
see raw JSON, but the underlying action still won't happen). `llama3.1`
(8B) is noticeably more reliable via Ollama, at the cost of being slower
on CPU-only machines (several minutes per reply). Any cloud provider
(Anthropic/OpenAI/OpenRouter) is both faster and more reliable if you
have API access.

## Discord Bot

```bash
pip install "hermes-life-os[discord]"   # or: pip install discord.py
set DISCORD_BOT_TOKEN=...      # from the Discord Developer Portal
set DISCORD_USER_ID=...        # your own numeric Discord user id
hermes-life-os-discord
```

The Discord counterpart to the Telegram bot above - same idea (talk to
Hermes, log meals from a photo, send a voice message), different
platform. Uses discord.py's own event-driven client under the hood
(rather than the Telegram bot's hand-rolled long-polling loop), so it
works in a DM or in any server channel the bot can see. Only messages
from `DISCORD_USER_ID` are ever processed - everyone else is silently
ignored. See `demo/discord_bot.py`'s docstring for the exact setup
steps (creating a bot application, enabling the Message Content
intent, and finding your user id). The same vision-model requirement
for photo meal logging applies here - see the Photo Meal Logging
section below.

## WhatsApp Bot

```bash
pip install "hermes-life-os[whatsapp]"   # or: pip install flask twilio
set TWILIO_ACCOUNT_SID=...
set TWILIO_AUTH_TOKEN=...
set WHATSAPP_ALLOWED_NUMBER=whatsapp:+1XXXXXXXXXX   # your own number, E.164
hermes-life-os-whatsapp
```

The third chat platform, via Twilio's WhatsApp API. Unlike the
Telegram bot (polling) and Discord bot (websocket client), this is a
webhook server - Twilio pushes messages to it, so it needs to be
reachable from the internet (`ngrok http 8766` works well for personal
use with Twilio's free WhatsApp Sandbox). Same feature set as the
other two: plain text, photo-based meal logging, and voice-note
transcription. Every incoming request's Twilio signature is verified
before anything is processed, on top of the same single-number
authorization the other bots use. Full setup steps (sandbox join code,
webhook URL) are in `demo/whatsapp_bot.py`'s docstring. The same
vision-model requirement for photo meal logging applies here too - see
the Photo Meal Logging section below.

## Slack Bot

```bash
pip install "hermes-life-os[slack]"   # or: pip install slack_bolt
python demo/users.py add alex --profile alex
python demo/users.py link alex slack U0123ABC   # your Slack member ID
set SLACK_BOT_TOKEN=xoxb-...
set SLACK_APP_TOKEN=xapp-...
hermes-life-os-slack
```

The fourth chat platform, and the first one built multi-user from the
start: DM the bot and it's automatically routed to *your* profile, so a
whole household or team can share one bot process. Uses Socket Mode (a
persistent websocket, via Slack's own `slack_bolt` framework) - same
"no public server, no webhook" philosophy as the Telegram bot, just
using Slack's officially supported connection handling instead of a
hand-rolled polling loop. Works single-user too (`SLACK_ALLOWED_USER_ID`,
same pattern as the Discord/Telegram bots) if you don't need the
multi-user registry. Same photo-based meal logging support as the other
bots. Full setup (creating the Slack app, required scopes, finding your
member ID) in `demo/slack_bot.py`'s docstring and
[docs/MULTI_USER.md](docs/MULTI_USER.md).

## Local REST API

```bash
pip install "hermes-life-os[api]"   # or: pip install flask
set LIFE_OS_API_KEY=some-long-random-string
hermes-life-os-api
```

A lightweight, localhost-only HTTP API for third-party integrations
that don't want to (or can't) go through an LLM at all - Apple
Shortcuts, Android Tasker, a browser extension, a home-screen widget,
an Alfred/Raycast workflow, `curl` in a cron job, etc. Exposes the
same tools the chat agent uses:

```bash
curl -H "X-API-Key: some-long-random-string" http://127.0.0.1:8765/api/tools
curl -H "X-API-Key: some-long-random-string" -X POST \
     -d '{"score": 8}' http://127.0.0.1:8765/api/tools/log_mood
```

Binds to `127.0.0.1` by default and refuses to start without
`LIFE_OS_API_KEY` set - every request needs it as an `X-API-Key`
header. See `demo/local_api.py`'s docstring for the full endpoint list
and the security notes on exposing this beyond your own machine. For a
step-by-step Apple Shortcuts / Android / browser bookmarklet setup, see
[docs/SHORTCUTS.md](docs/SHORTCUTS.md).

## Weather Correlation

```
"does the weather affect my mood?"
"any connection between rain and my energy levels?"
```

`demo/weather.py` fetches historical daily weather (temperature,
precipitation) for a place you name, via Open-Meteo's free, keyless API
(https://open-meteo.com) - no signup, no API key, no cost - and
correlates it against your tracked metrics the same way the core
correlation engine does. This is the only tracker that makes a network
call (every other one is 100% local), and it only ever does so when
explicitly asked, sending nothing but the place name you provide.

## Life Review - the flagship retrospective report

```bash
hermes-life-os-review --days 90              # a quarter -> hermes-life-review.html
hermes-life-os-review --days 365 --out my-year-review.html
```

The "big" report - ties together everything else Hermes tracks into
one self-contained HTML page: your Life Score trend chart, best/toughest
day, a period-over-period retrospective (this quarter vs. the one
before), every correlation detected (same-day and lagged), achievements
earned, and habit streaks. Same "no server, no JS build step" approach
as the dashboard, just built for a much longer lookback window - a
quarter or a year, rather than 30 days. Doesn't include weather
correlation automatically, since that's the one feature that touches
the network - ask for it separately if wanted.

Need something printable or shareable outside a browser? `--format
pdf` renders a two-page PDF version with the same data (Life Score,
retrospective, correlations, achievements, habits) on a light,
print-friendly background:

```bash
hermes-life-os-review --days 90 --format pdf --out my-quarter.pdf
```

`hermes-life-os-wrapped` supports the same trick even more simply -
just name the output file `.pdf` instead of `.png` and it's picked up
automatically:

```bash
hermes-life-os-wrapped --out hermes-wrapped.pdf
```

## Leaderboard - opt-in household/team comparison

```
"join the leaderboard"
"show me the leaderboard"
```

Builds on the multi-user system (see [docs/MULTI_USER.md](docs/MULTI_USER.md)):
a friendly, opt-in ranking across every profile on the install, by
average Life Score, current logging streak, and achievements earned.
**Nobody is included by default** - a profile only appears after
explicitly opting in (`join_leaderboard`, or `python demo/leaderboard.py
join`), and leaving again takes effect immediately. Only those three
numbers are ever shared across profiles - no journal content, no raw
logged entries, and nothing ever leaves the machine.

## Streak Freezes

Habits (`update_habit`) now bank a **streak freeze** every 7 days of an
active streak, up to 3 at once - a small forgiveness mechanic so one
missed day doesn't erase weeks of consistency:

```
"I meditated" (7 days running) -> "Habit 'meditate': streak 7 days (best: 7) - earned a streak freeze! (1 available)"
"I missed meditating today, use a freeze" -> "Habit 'meditate': streak protected with a freeze! Still at 7 days (best: 7). 0 freeze(s) left."
```

No freeze banked and a day's missed? The streak resets to 0, same as
always - freezes are a bonus for consistency, not a way around ever
having an off day.

## On This Day & Daily Prompts

```
"what was I doing on this day last year?"
"give me a reflection prompt"
```

Two small additions aimed at journaling depth, not just numbers:

- **On This Day** (`get_on_this_day`) - a nostalgia lookup: finds
  memory entries logged on today's month/day in previous years, most
  recent first.
- **Daily Prompt** (`get_daily_prompt`, `demo/prompts.py`) - a rotating
  reflection question, deterministic by calendar date (same day always
  returns the same prompt, and it changes daily) - no state to persist,
  no randomness to make testing flaky.

## Contribution Heatmap

```bash
hermes-life-os-heatmap --days 365 --out heatmap.svg
hermes-life-os-heatmap --days 90 --out heatmap.html    # wrapped with stats
```

A GitHub-style calendar heatmap of your logging activity - darker
squares for more active days, same five-level palette as GitHub's own
contribution graph. Pure SVG (no matplotlib needed), so it's fast and
embeddable anywhere that accepts raw SVG or an `<img>` tag. `.html`
output wraps it with active-day/streak stats above the grid.

## Moon Phase Correlation

```
"does the full moon affect my mood?"
```

`demo/moon.py` correlates lunar phase against tracked metrics, purely
via local astronomical calculation - unlike weather.py, this makes
*zero* network calls; the phase is computed on-device from a known
reference new moon date. Offered in the same evidence-based spirit as
every correlation Hermes computes: not because lunar effects on mood
are scientifically established (most rigorous research says they
aren't), but because it's a fun, harmless pattern to check against your
own data - if Hermes finds nothing, that itself is the honest answer.

## Sleep Debt & Suggested Bedtime

```
"how much sleep debt do I have?"
"what time should I go to bed if I'm waking up at 7?"
```

`demo/sleep_debt.py` sums the shortfall between a target sleep duration
(default 8h) and what's actually logged over a recent window - only
days with a logged sleep value count, so gaps in logging are never
mistaken for debt. `get_suggested_bedtime` factors existing debt into
tonight's recommended bedtime, nudged earlier gradually (a quarter of
the debt per night, capped at 1h extra) rather than proposing something
unrealistic in a single night.

## Day-of-Week Insights

```
"what's my best day of the week?"
"is my mood worse on Mondays?"
```

`demo/day_of_week.py` buckets already-logged mood, energy, stress,
sleep, hydration, meeting-hours, and readiness by weekday, then reports
which day averages best and worst for each metric - lower is treated
as "best" for stress specifically, since a calmer day is the good
outcome there. Purely local arithmetic over `daily_averages()`, no new
tracking of its own; a metric needs at least two distinct weekdays
logged before Hermes will call one "best" and another "worst".

## Habit Milestones

```
"how close am I to a milestone on my habits?"
```

`demo/habit_milestones.py` looks at every habit with an active streak
and counts down to its next round-number milestone (7, 14, 30, 50,
100, 150, 200, 365, 500, 1000 days, doubling beyond that). This is a
different lens than the near-milestone nudge already surfaced
opportunistically by `recommendations.py` - `get_habit_milestones`
gives the full countdown list for every active habit on demand, rather
than waiting for one habit to get close enough to be worth a nudge.

## Logging Consistency

```
"how consistent have I been with logging?"
"which trackers have I been neglecting?"
```

`demo/consistency.py` (`get_logging_consistency`) reports the
percentage of recent days that had at least one entry logged, overall
and broken down per tracked metric. A metric that's never been logged
in the window is simply left out of the breakdown rather than shown as
a discouraging 0% - an unused tracker isn't "inconsistent", it's just
unused.

## Time-of-Day Insights

```
"am I happier in the mornings?"
"is my stress worse at night?"
```

`demo/time_of_day.py` (`get_time_of_day_insights`) buckets individual
logged entries into Morning/Afternoon/Evening/Night by the hour they
were logged and reports which time of day is best and worst per
metric - a companion to Day-of-Week Insights that looks at time-of-day
rather than day-of-week, and works entry-by-entry rather than one
daily average, since mood at 8am and mood at 8pm on the same day
should land in different buckets.

## Month-over-Month Comparison

```
"how is this month going compared to last month?"
```

`demo/monthly_summary.py` (`get_monthly_comparison`) compares this
calendar month so far against the same day-count span at the start of
last calendar month - e.g. running it on the 10th compares days 1-10
of each month, not the whole of last month against a partial current
one. Handles month-length edge cases (a 31-day January comparing
against a 28/29-day February) by capping the previous-month span at
that month's own last day. Built on top of the existing
`compare_periods()` averaging/delta logic, just with calendar-month
date ranges instead of rolling day windows.

## Habit Personal Bests

```
"am I close to beating my meditation streak record?"
```

`demo/habit_pb.py` (`get_habit_pb_progress`) compares every habit's
current streak against its own personal-best streak - a new best, a
tie, or how many days remain to tie it. This is a different, often
more motivating lens than the fixed round-number countdown in Habit
Milestones: a habit whose best streak is 12 will never feel "close" to
milestone 14, but "2 days from tying your best" always does.

## Workout Summary

```
"give me a fitness recap"
"how's my workout streak?"
```

`demo/workout_summary.py` (`get_workout_summary`) totals recent
workouts, breaks them down by type, and reports the current
consecutive-day workout streak. The streak always looks at your full
workout history rather than just the requested lookback window, so a
streak that started 40 days ago still shows correctly even when asking
for a 30-day summary.

## Meditation Summary

```
"how's my meditation practice going?"
```

`demo/meditation_summary.py` (`get_meditation_summary`) totals recent
meditation sessions and reports what percentage of days in the window
had at least one session - multiple sessions on the same day count
once toward that consistency figure.

## Gratitude Recap

```
"what have I been grateful for lately?"
```

`demo/gratitude_recap.py` (`get_gratitude_recap`) totals recent
gratitude entries, surfaces the most recurring words across them as a
lightweight signal for recurring themes (not real NLP, just frequency
counting with a small stopword list), and lists the most recent items.

## Meal Summary

```
"give me a nutrition recap"
```

`demo/meal_summary.py` (`get_meal_summary`) totals recent meals,
reports average calories per meal and per logged day, breaks meals
down by meal time (breakfast/lunch/dinner/snack), and lists the most
frequently logged foods (case-insensitively, so "Salad" and "salad"
count together).

## Goal Deadlines

```
"update_goal('finish the report', deadline='2026-03-01')"
"what goal deadlines am I about to miss?"
```

`update_goal` now accepts an optional `deadline` (`YYYY-MM-DD`).
`demo/goal_deadlines.py` (`get_goal_deadlines`) lists every
deadline-bearing goal sorted by urgency, with overdue goals surfaced
first and how many days overdue they are - so a goal with a deadline
never silently falls off the radar the way a plain progress percentage
can.

## Focus Timer

```bash
hermes-life-os-focus 25 --task "writing"
hermes-life-os-focus 25 --task "deep work" --break 5
```

A terminal Pomodoro-style countdown that logs itself on completion, via
the exact same `log_focus_session` path a chat-based request uses - so
this isn't a separate timer app you also have to remember to log
afterward. Ctrl+C during the countdown stops it early and does **not**
log a session (an abandoned session isn't a completed one).

## Markdown / Obsidian / Notion Export

```bash
hermes-life-os-export --markdown ./obsidian-vault/hermes
hermes-life-os-export --markdown ./notes --days 90
```

Adds a third export format alongside JSON and CSV: one file per day
(`YYYY-MM-DD.md`) with YAML frontmatter for that day's numeric metrics
and a bulleted list of everything logged - filename convention matches
Obsidian's Daily Notes plugin exactly, and Notion's markdown importer
reads YAML frontmatter as page properties, so the same export folder
drops into either tool with no conversion step.

## Semantic Memory Search

`recall` searches by exact keyword; ask Hermes something like "have I
felt this way before?" or "find entries about feeling overwhelmed" (even
if you never used that exact word) and it can fall back to
`semantic_recall` - a local, free embedding search via Ollama (`ollama
pull nomic-embed-text` first) or OpenAI:

```bash
set EMBEDDING_PROVIDER=ollama   # or openai; auto-detects from OPENAI_API_KEY otherwise
```

Embeddings are cached per entry and only recomputed when that entry's
text actually changes.

## Oura Ring Import

```bash
set OURA_PERSONAL_ACCESS_TOKEN=...   # https://cloud.ouraring.com/personal-access-tokens
hermes-life-os-oura --days 30
```

No OAuth flow - just a personal access token from Oura's own dashboard.
Imports real sleep duration (merges directly with manually logged and
Apple-Health-imported sleep) and your daily readiness score (a new
tracked metric - ask "is my readiness linked to sleep or stress?").

## Weekly Email Summary

```bash
set HERMES_SMTP_HOST=smtp.gmail.com
set HERMES_SMTP_PORT=587
set HERMES_SMTP_USER=you@gmail.com
set HERMES_SMTP_PASSWORD=...          # an app password, not your real password
set HERMES_SMTP_TO=you@gmail.com      # optional, defaults to HERMES_SMTP_USER

hermes-life-os-weekly-email
hermes-life-os-weekly-email --days 30 --compare-days 7
```

Emails the same self-contained report `hermes-life-os-dashboard`
generates - trend charts, correlations, retrospective, habit streaks -
straight to your inbox. Not wired into the scheduler by default (not
everyone has SMTP configured); schedule it yourself with your OS's own
task scheduler if you want it automatic weekly:

```
Linux/macOS (cron):        0 8 * * 1  hermes-life-os-weekly-email
Windows (Task Scheduler):  weekly trigger, action = same command
```

## Voice Notes (Telegram)

```bash
pip install "hermes-life-os[voice]"   # or: pip install faster-whisper
```

Send the Telegram bot a voice note instead of typing - it's downloaded
and transcribed locally (a free Whisper model via `faster-whisper`, no
cloud API, no per-minute cost) before being processed exactly like a
typed message. The reply is prefixed with what Hermes heard, so you can
catch a bad transcription. `WHISPER_MODEL` (default `base`) controls
speed vs. accuracy - `tiny` is fastest, `small`/`medium` are more
accurate but slower on CPU-only machines. Without `faster-whisper`
installed, voice notes get a clear "couldn't process" reply instead of
silently failing.

## Photo Meal Logging (Telegram, Discord, WhatsApp &amp; Slack)

Send any of the four bots a photo of your meal (with an optional
caption) and a vision-capable LLM identifies what's in it and logs it
- no separate step needed. OpenAI's and Anthropic's default models
already support vision. On Ollama, pull a vision-capable model
yourself (`ollama pull llava`) and point Hermes at it explicitly
(`set HERMES_MODEL=llava` or `--model llava`) - Ollama's default
text-only models (like `llama3.1`) will simply ignore the image.

## Automatic Backups

Hermes takes a timestamped local backup of your data every day at
20:30 (right after the evening nudge check), keeping the 7 most recent
by default and pruning older ones. Backups live alongside your other
data (`<profile dir>/backups/`) and are plain JSON - the same format
`hermes-life-os-export --json` produces. Run it manually anytime:

```bash
hermes-life-os-backup            # keep the default 7
hermes-life-os-backup --keep 14  # keep the 14 most recent
```

## Spending, Social & Substance Tracking

```
"spent 12 on lunch"
"hung out with my best friend for an hour, really good talk"
"had 2 cups of coffee this morning"
```

Three more trackers alongside nutrition/sleep/fitness/mental, added
because a "life OS" that only tracks the body misses a lot of what
actually moves the needle day to day:

- **Spending** - logs expenses by category, and (like every other
  metric) feeds the correlation engine, so "do I spend more on stressed
  days?" is an answerable question, not a guess.
- **Social connection** - time spent with other people and how
  connecting/fulfilling it felt (1-10) - loneliness and social
  wellbeing are as real a signal as sleep or stress, just rarely
  tracked anywhere.
- **Substances** - caffeine, alcohol, or anything else worth watching,
  with amount and unit left free-form. Caffeine specifically feeds the
  correlation engine (e.g. against sleep quality); other substances are
  logged and summarized even if not yet wired into correlations.

Ask for a summary anytime: "how's my spending been this month?",
"how much have I been socializing lately?", "how much caffeine have I
had this week?".

## Life Score & Achievements

```
"what's my life score today?"
"show me my achievements"
```

**Life Score** blends whatever you've logged that day - mood, sleep,
hydration, stress (inverted), energy, focus - into a single 0-100
number with a plain-language label (Thriving / Doing well / Steady /
Rough day / Tough day). Not a medical measure, just a transparent,
at-a-glance way to answer "how am I doing overall" without mentally
combining five numbers yourself - `demo/life_score.py`'s `components`
field always shows exactly which metrics fed the score, so it's never
a black box, and a day with only one thing logged still scores fairly
(missing metrics are excluded, not treated as zero).

**Achievements** (`demo/achievements.py`) are streak and milestone
badges - a 7/30/100-day streak on any habit, a 7/30/100-day *overall*
logging streak, and count-based badges ("first workout logged", "50
mood check-ins"). Entirely read-only and recomputed fresh every time -
there's no separate achievements database to drift out of sync with
your actual logs, so editing or deleting an entry updates progress
immediately.

## Wrapped - a shareable summary card

```bash
hermes-life-os-wrapped                              # last 30 days -> hermes-wrapped.png
hermes-life-os-wrapped --days 365 --out my-year.png --title "My 2026"
hermes-life-os-wrapped --days 7                      # a "your week" card
```

A single shareable PNG card - your average Life Score, entries logged,
days active, average mood/sleep, your best day, and badges earned - in
the spirit of Spotify Wrapped or GitHub's yearly contribution recap.
Entirely local: reads only from data already on disk, makes no LLM or
network calls, and the image never leaves your machine unless you
choose to share it. Needs matplotlib (already a core dependency, same
as the dashboard).

## Reading & Medication Tracking

```
"read 25 pages of Atomic Habits for 20 minutes"
"took my vitamin D"
"skipped my omega-3 today"
```

- **Reading/learning** (`log_reading`, `get_reading_summary`) - session
  count, total minutes, total pages over a window. Reading minutes also
  feed the correlation engine.
- **Medication/supplement adherence** (`log_medication`,
  `get_medication_adherence`) - log a dose as taken or skipped, get an
  adherence percentage per medication over a recent window. Simple by
  design: no dosage/scheduling logic, no interaction warnings - just an
  honest log of what was actually taken.

## Recommendations

```
"what should I focus on today?"
"any suggestions based on my data?"
```

`demo/recommendations.py` turns patterns already visible in your own
data into concrete, actionable nudges - entirely local, rule-based, no
LLM or network call involved, so every suggestion can be traced back to
the exact numbers behind it:

- **Threshold nudges** - e.g. average sleep under 6.5h or stress over
  7/10 recently.
- **Correlation-derived insights** - reuses the same correlation engine
  behind `get_correlation_insights`, just phrased as a suggestion.
- **Near-milestone streaks** - "2 days from a 30-day streak on
  'meditate' - keep it going!"

Not medical or therapeutic advice - a reflection of your own patterns,
phrased as a nudge, nothing more.

## What's New

**v1.25.0 - Workout, Meditation, Gratitude, and Meal Summaries**
- New **Workout Summary** (`demo/workout_summary.py`,
  `get_workout_summary`): totals, breakdown by workout type, and a
  consecutive-day workout streak computed over full history rather
  than just the requested window.
- New **Meditation Summary** (`demo/meditation_summary.py`,
  `get_meditation_summary`): totals and a consistency percentage
  (days with at least one session logged).
- New **Gratitude Recap** (`demo/gratitude_recap.py`,
  `get_gratitude_recap`): totals, recurring-word frequency across
  logged items, and the most recent entries.
- New **Meal Summary** (`demo/meal_summary.py`, `get_meal_summary`):
  totals, average calories per meal/day, breakdown by meal time, and
  the most frequently logged foods.
- 43 new tests - suite grew from 1005 to 1048.

**v1.24.0 - Logging Consistency, Time-of-Day Insights, Month-over-Month, Habit PBs**
- New **Logging Consistency** (`demo/consistency.py`,
  `get_logging_consistency`): percentage of recent days with at least
  one entry logged, overall and per tracked metric - unused trackers
  are omitted rather than shown as a discouraging 0%.
- New **Time-of-Day Insights** (`demo/time_of_day.py`,
  `get_time_of_day_insights`): buckets individual logged entries into
  Morning/Afternoon/Evening/Night by hour and reports the best/worst
  time of day per metric - a companion to Day-of-Week Insights that
  works entry-by-entry instead of on daily averages.
- New **Month-over-Month Comparison** (`demo/monthly_summary.py`,
  `get_monthly_comparison`): compares this calendar month so far
  against the same day-count span at the start of last calendar month,
  reusing `compare_periods()`'s averaging/delta math with calendar
  month boundaries instead of rolling day windows; correctly caps a
  longer current month's span against a shorter previous month (e.g.
  comparing a 31-day January against February).
- New **Habit Personal Bests** (`demo/habit_pb.py`,
  `get_habit_pb_progress`): compares every habit's current streak
  against its own personal best - new best, tied, or days remaining to
  tie it - a complement to the fixed-milestone countdown in Habit
  Milestones.
- Also promotes `analytics._extract_metric` to a public `extract_metric`
  (backward-compatible, original kept) so `time_of_day.py` could reuse
  the exact same per-entry metric extraction rather than duplicating
  the per-type rules.
- 54 new tests - suite grew from 951 to 1005.

**v1.23.0 - Day-of-Week Insights, Habit Milestones, Goal Deadlines**
- New **Day-of-Week Insights** (`demo/day_of_week.py`,
  `get_day_of_week_insights`): buckets logged mood/energy/stress/sleep/
  hydration/meeting-hours/readiness by weekday and reports which day
  is best and worst for each metric, purely from data already logged -
  no new tracking, no network call.
- New **Habit Milestones** (`demo/habit_milestones.py`,
  `get_habit_milestones`): counts down every active habit streak to
  its next round-number milestone (7, 14, 30, 50, 100, 150, 200, 365,
  500, 1000 days) in one on-demand list, complementing the existing
  opportunistic near-milestone nudge in `recommendations.py`.
- New **Goal Deadlines** (`demo/goal_deadlines.py`,
  `get_goal_deadlines`): `update_goal` now accepts an optional
  `deadline` (`YYYY-MM-DD`); `get_goal_deadlines` lists every
  deadline-bearing goal sorted by urgency, overdue ones called out
  first with how many days overdue.
- 42 new tests - suite grew from 909 to 951.

**v1.22.0 - Heatmap, Moon Correlation, Sleep Debt, Focus Timer, Markdown Export**
- New **Contribution Heatmap** (`demo/heatmap.py`, `hermes-life-os-heatmap`):
  a GitHub-style SVG calendar heatmap of logging activity - pure SVG,
  no matplotlib, embeddable anywhere.
- New **Moon Phase Correlation** (`demo/moon.py`, `get_moon_correlation`):
  correlates lunar phase against tracked metrics via pure local
  astronomical calculation - zero network calls, unlike weather.py.
- New **Sleep Debt Calculator** (`demo/sleep_debt.py`, `get_sleep_debt`,
  `get_suggested_bedtime`): cumulative shortfall against a target sleep
  duration, plus a bedtime suggestion that pays down debt gradually.
- New **Focus Timer** (`demo/focus_timer.py`, `hermes-life-os-focus`):
  a terminal Pomodoro-style countdown that logs itself on completion
  via the same path a chat-based focus session uses.
- New **Markdown/Obsidian/Notion Export** (`data_export.py --markdown`):
  one daily note per day with YAML frontmatter, matching Obsidian's
  Daily Notes convention and readable by Notion's markdown importer.
- Also promotes `achievements._consecutive_day_streak` to a public
  `consecutive_day_streak` (backward-compatible alias kept) so
  heatmap.py could reuse the exact same streak logic rather than
  duplicating it.
- 75 new tests - suite grew from 834 to 909.

**v1.21.0 - PDF Export, Streak Freezes, On This Day, Daily Prompts**
- **PDF export** for the two biggest reports: `hermes-life-os-review
  --format pdf` renders a two-page, print-friendly PDF version of the
  Life Review (Life Score, retrospective, correlations, achievements,
  habits); `hermes-life-os-wrapped --out card.pdf` picks up PDF
  automatically from the file extension - no new flags needed.
- **Streak freezes**: habits now bank one streak freeze every 7 days of
  an active streak (capped at 3) - `update_habit` with
  `completed=false, use_freeze=true` spends one to protect a streak
  through a missed day instead of resetting it to 0.
- New **On This Day** (`get_on_this_day`): a nostalgia lookup - finds
  memory entries logged on today's month/day in previous years.
- New **Daily Prompt** (`get_daily_prompt`, `demo/prompts.py`): a
  rotating reflection question, deterministic by calendar date - same
  day always returns the same prompt, changes daily, no state to
  persist.
- Also fixes a real Python variable-scoping bug found during testing:
  a local `from storage import get_all_memory` inside one `dispatch_tool`
  branch was shadowing the module-level import for the *entire*
  function, breaking two unrelated tools (`get_correlation_insights`'s
  semantic-recall path and `compare_periods`) whenever `get_on_this_day`
  had been added to the same file. Caught by the full test suite before
  release, not after.
- 62 new tests - suite grew from 806 to 834.

**v1.20.0 - Life Review Report, Household Leaderboard**
- New **Life Review** (`demo/life_review.py`, `hermes-life-os-review`):
  the flagship retrospective report - Life Score trend chart,
  best/toughest day, a period-over-period comparison, every correlation
  detected, achievements earned, and habit streaks, all in one
  self-contained HTML page built for a quarter- or year-long lookback
  window. Reuses the same chart-rendering approach as the dashboard for
  visual consistency.
- New **Leaderboard** (`demo/leaderboard.py`, `join_leaderboard` /
  `leave_leaderboard` / `get_leaderboard` tools): an opt-in, cross-profile
  ranking by average Life Score, logging streak, and achievements
  earned, built on top of the multi-user system. Nobody is included by
  default; opting out takes effect immediately; only those three
  numbers are ever shared across profiles.
- 33 new tests - suite grew from 768 to 805.

**v1.19.0 - Weather Correlation, Quick-Logging Guide**
- New **Weather Correlation** (`demo/weather.py`, `get_weather_correlation`
  tool): fetches historical daily weather via Open-Meteo's free, keyless
  API and correlates temperature/precipitation against tracked metrics
  using the same Pearson approach as the core correlation engine. The
  only tracker that makes a network call - entirely on-demand, sends
  nothing but the place name.
- New [docs/SHORTCUTS.md](docs/SHORTCUTS.md): a step-by-step guide for
  building one-tap Apple Shortcuts, Android (Tasker/HTTP Shortcuts), and
  browser-bookmarklet quick-loggers on top of the existing local REST
  API - no new app, no subscription.
- 20 new tests (all HTTP calls mocked - no real network access
  required to run the suite) - suite grew from 748 to 768.

**v1.18.0 - Reading & Medication Tracking, Recommendations**
- New trackers: **reading/learning** (`log_reading`,
  `get_reading_summary` - sessions, minutes, pages; reading minutes
  feed the correlation engine) and **medication/supplement adherence**
  (`log_medication`, `get_medication_adherence` - taken/skipped dose
  logging with an adherence % per medication).
- New **Recommendations** (`demo/recommendations.py`,
  `get_recommendations` tool): a fully local, rule-based suggestion
  engine combining threshold nudges (low sleep, high stress),
  correlation-derived insights (reusing the existing correlation
  engine), and near-milestone habit streaks into concrete, traceable
  suggestions - no LLM or network call involved.
- 26 new tests - suite grew from 722 to 748.

**v1.17.0 - Spending/Social/Substance Tracking, Life Score, Achievements, Wrapped**
- New trackers alongside nutrition/sleep/fitness/mental: **spending**
  (`log_expense`, `get_spending_summary`), **social connection**
  (`log_social_interaction`, `get_social_summary`), and **substances**
  (`log_substance`, `get_substance_summary` - caffeine, alcohol, or
  anything else). Spending and caffeine feed the correlation engine
  like every other metric.
- New **Life Score** (`demo/life_score.py`, `get_life_score` tool): a
  single 0-100 composite blending whatever's logged that day (mood,
  sleep, hydration, stress, energy, focus) into one at-a-glance
  wellbeing number, with a transparent `components` breakdown - never a
  black box, and never penalized for partial data.
- New **Achievements** (`demo/achievements.py`, `get_achievements`
  tool): streak badges (7/30/100 days, per-habit and overall) and
  count-based milestone badges. Fully read-only and recomputed fresh
  every call - no separate achievements state to fall out of sync with
  your actual logs.
- New **Wrapped** (`demo/wrapped.py`, `hermes-life-os-wrapped`): a
  single shareable PNG summary card (average Life Score, entries
  logged, best day, badges earned) in the spirit of Spotify Wrapped -
  entirely local, no network calls.
- 81 new tests - suite grew from 641 to 722.

**v1.16.0 - Plugin System, Multi-User Accounts, Slack Bot**
- New plugin system (`demo/plugins.py`): drop a `.py` file into
  `~/.hermes/life-os/plugins/` defining `TOOLS` + `dispatch()` and
  Hermes' LLM agent can call it like any built-in tool - no fork, no
  core code changes. A broken plugin is skipped and reported, never
  crashes startup; plugins can't shadow built-in tool names. Ships with
  two ready-to-copy examples (`demo/plugins_examples/`) and a full
  guide at [docs/PLUGINS.md](docs/PLUGINS.md). Also fixes a
  long-standing dead-code bug where `dispatch_tool`'s final "Unknown
  tool" fallback could never actually be reached.
- New multi-user registry (`demo/users.py`): named users, each with
  their own salted-hash API key that resolves to their own profile
  automatically. `hermes-life-os-api` and the new Slack bot are both
  multi-user aware - one running server/bot can now serve a whole
  household or team, each person only ever seeing their own data. Fully
  opt-in; a single `LIFE_OS_API_KEY`/`--profile` keeps working exactly
  as before. See [docs/MULTI_USER.md](docs/MULTI_USER.md).
- New Slack bot (`demo/slack_bot.py`, `hermes-life-os-slack`): the
  fourth chat platform, via Slack's Socket Mode (no public server/
  webhook needed, same as the Telegram bot). Supports both single-user
  (`SLACK_ALLOWED_USER_ID`) and multi-user (linked via `users.py`)
  modes, plus the same photo-based meal logging as the other bots.
- 74 new tests - suite grew from 567 to 641.

**v1.15.0 - Local REST API, Live Web Dashboard, WhatsApp Bot, Predictive Correlations**
- New `hermes-life-os-api` local REST API (`demo/local_api.py`, Flask):
  `GET /api/tools`, `POST /api/tools/<name>`, `GET /api/memory/recent`,
  `GET /api/memory/search` - lets a Shortcut, browser extension, or any
  other client call Hermes' tools over HTTP. Binds to localhost by
  default and requires `LIFE_OS_API_KEY` on every request; refuses to
  start without it.
- New live web dashboard (`demo/web_dashboard.py`,
  `hermes-life-os-web`) - the same charts/correlations/retrospective as
  the static PNG report, but as an always-current local web page that
  refreshes without regenerating a file.
- New WhatsApp bot (`demo/whatsapp_bot.py`, `hermes-life-os-whatsapp`),
  via Twilio's WhatsApp API - the third chat platform alongside
  Telegram and Discord, with the same text/photo-meal-logging feature
  set. Unlike the polling/websocket-based bots, this is a webhook
  server, so every incoming request's Twilio signature is verified
  before processing.
- New lagged/predictive correlations (`compute_lagged_correlations()`
  in `demo/analytics.py`): shifts one metric 1-2 days forward before
  correlating, so results can say "a higher X on one day tends to be
  followed by a higher/lower Y N days later" instead of only reporting
  same-day co-movement. Feeds every existing insight surface (chat,
  `detect_patterns`, both dashboards, the weekly email) plus a new
  dedicated `get_correlation_insights` tool for on-demand deep dives.

**v1.14.0 - Automatic Backups, Photo Meal Logging, Discord Bot, Encryption Re-key**
- Automatic daily local backups of all data, kept on a rolling window,
  restorable via `hermes-life-os-backup`.
- Photo-based meal logging: send the Telegram or Discord bot a photo of
  a meal (with an optional caption) and a vision-capable LLM identifies
  and logs it - no separate step needed.
- New Discord bot (`demo/discord_bot.py`, `hermes-life-os-discord`) -
  the second chat platform alongside Telegram, using discord.py's
  event-driven client rather than a hand-rolled polling loop, so it
  works in a DM or any server channel the bot can see.
- New `hermes-life-os-rekey` tool: safely rotates
  `LIFE_OS_ENCRYPTION_KEY` (decrypts with the old key, rotates the
  salt, re-encrypts with the new one in one step) - also works to
  enable or fully disable encryption after the fact, which simply
  setting a new key directly could not do safely.

**v1.13.0 - Weekly Email Summary, Voice Notes**
- New `hermes-life-os-weekly-email` CLI: emails the same self-contained
  dashboard report (charts, correlations, retrospective, habits) that
  `hermes-life-os-dashboard` generates. Reuses the existing SMTP
  settings (`HERMES_SMTP_*`); new `notifications.send_html_email()`
  sends HTML with a plain-text fallback. Not wired into the scheduler
  by default - schedule it yourself with cron/Task Scheduler if wanted.
- Telegram bot now accepts voice notes: downloaded and transcribed
  locally via a free Whisper model (`faster-whisper`, no cloud API,
  `WHISPER_MODEL` env var to pick model size), then processed exactly
  like a typed message. The reply is prefixed with what Hermes heard,
  and a missing/failed transcription gets a clear message instead of
  silently failing.
- 36 new tests - suite grew from 355 to 391.

**v1.12.0 - Telegram Bot, Semantic Memory Search, Oura Ring Import**
- New `hermes-life-os-telegram` CLI: talk to Hermes from your phone via
  long-polling (no server/webhook needed). Restricted to a single
  `TELEGRAM_CHAT_ID` for privacy. Replies use `run_life_os()`'s new
  `reply_text` field - the model's actual natural-language answer,
  extracted directly rather than parsed from rendered terminal output
  (avoids garbled box-drawing characters and empty-panel replies).
  Long messages auto-split across Telegram's 4096-char limit; failed
  polls back off exponentially (5s -> 5min) instead of hammering the
  API if the token is briefly rate-limited or wrong.
- Hardening: if a weak/small model emits a raw failed tool-call attempt
  as plain text (e.g. `{"name":"recall","parameters":{...}}`) instead of
  actually calling the tool, that's now detected and never relayed to
  the user as if it were a real answer - seen with small local models
  (e.g. `llama3.2:3b`) via Ollama, which can also make unreliable tool
  choices in general; `llama3.1` (8B) or a cloud provider is
  recommended for more consistent behavior.
- New `semantic_recall` chat tool + `semantic_search.py`: meaning-based
  memory search via local (Ollama) or OpenAI embeddings, with a
  per-entry cache that only recomputes when an entry's text actually
  changes. Falls back gracefully with a clear message if no embedding
  provider is reachable.
- New `hermes-life-os-oura` CLI: imports real sleep duration (merges
  directly into the existing "sleep" metric alongside manual logs and
  Apple Health imports) and daily readiness score (`readiness`, a new
  fully tracked metric) from an Oura Ring, via Personal Access Token -
  no OAuth flow needed.
- 83 new tests - suite grew from 272 to 355.

**v1.11.0 - Anomaly Detection, Calendar Import, Proactive Nudges, Data Export, History Queries**
- `check_anomalies` tool + `analytics.detect_anomalies()`: flags statistical
  outlier days (z-score based) in mood/energy/stress/sleep/hydration.
- `compare_before_after` tool + `analytics.compare_before_after()`: compares
  metric averages before vs. after a specific changepoint date (e.g. "did
  starting meditation on March 1st actually help?").
- New `hermes-life-os-calendar` CLI: imports meeting hours per day from a
  standard `.ics` calendar export (Google Calendar/Outlook/Apple Calendar,
  no OAuth needed). `meeting_hours` is now a fully tracked metric -
  participates in correlations, goal-linking, retrospectives, and anomaly
  detection automatically.
- Proactive nudges: the scheduler's new 20:00 `nudge_check` entry
  deterministically (no LLM call) surfaces anomalies and lagging
  metric-linked goals, staying silent when nothing stands out.
- New `hermes-life-os-export` CLI: `--json` for a complete backup, `--csv`
  for a daily summary in the same shape `hermes-life-os-import --csv`
  expects (export, edit, re-import).
- `get_period_summary` tool + `storage.get_memory_by_date_range()`: natural-
  language history queries like "how was I in March?" - the LLM resolves
  the phrase to concrete dates, Hermes returns real averages and notable
  entries for that period.
- 52 new tests - suite grew from 220 to 272.

**v1.10.0 - Goal-Metric Linkage, Retrospective Comparison, Health Data Import**
- Goals can now auto-track from real logged data instead of manual progress
  updates - `update_goal` accepts `metric`/`target`/`direction`/`window_days`;
  new `check_goal_progress` tool recomputes and reports current progress.
- New `compare_periods` tool and a Dashboard "Retrospective" section compare
  this period to the one before it (week-over-week by default,
  `--compare-days` to change the window), color-coded by whether the change
  is favorable per metric.
- New `hermes-life-os-import` CLI: bulk-imports Apple Health `export.xml`
  (Sleep Analysis, Dietary Water) or a generic CSV
  (date + sleep_hours/mood/stress/energy/hydration columns), preserving real
  historical dates instead of stamping everything "today".
- `write_memory()` now only stamps "now" when no timestamp was already
  provided - unchanged for all real-time logging (which never supplies one),
  enables historical-dated bulk import.
- 45 new tests (goal-metric linkage, retrospective comparison, health
  import) - suite grew from 175 to 220.

**v1.9.0 - Multi-Profile, Encryption at Rest, Correcting/Deleting Entries**
- `--profile <name>` (or `LIFE_OS_PROFILE`) isolates all data per person
  under `~/.hermes/life-os/profiles/<name>/` - for shared households.
  Omitting it keeps the original single-profile layout unchanged.
- `LIFE_OS_ENCRYPTION_KEY` - optional encryption at rest (PBKDF2-HMAC-SHA256
  + Fernet/AES) for every data file and every memory.jsonl line. Off by
  default; existing plaintext data reads transparently and gets encrypted
  on next write, no separate migration needed.
- Every memory entry now has a stable id. New `correct_entry` / `delete_entry`
  tools let you fix a mistake or remove a bad log entry through normal
  conversation ("that sleep entry was wrong, it was actually 7 hours" /
  "delete that last entry") instead of it being stuck in an append-only log.
- 39 new tests (12 profiles, 10 encryption, 12 memory edit/delete at the
  storage layer, 5 for the correct_entry/delete_entry chat tools) - suite
  grew from 136 to 175 tests.

**v1.8.0 - PyPI Package, GHCR Image, Contributor Docs**
- `pip install hermes-life-os` - real PyPI packaging via `pyproject.toml`,
  with CLI commands `hermes-life-os`, `hermes-life-os-dashboard`,
  `hermes-life-os-scheduler`. Source layout (`demo/`) unchanged, so
  existing `python demo/demo_life_os.py` usage still works exactly the
  same. Auto-published to PyPI on every GitHub Release.
- `ghcr.io/lethe044/hermes-life-os` - pre-built Docker image, auto-published
  on every push to `main` and every release. No `git clone` needed to try it.
- Example dashboard chart embedded in the README (see the
  [Dashboard](#dashboard) section).
- `CONTRIBUTING.md` and GitHub issue templates (bug report / feature
  request) for contributors.

**v1.7.0 - CI, Docker & Dashboard**
- GitHub Actions workflow runs the full test suite on every push/PR
  across Python 3.10/3.11/3.12, with a status badge in this README
- `Dockerfile` + `docker-compose.yml` for a zero-install trial - pairs
  with a local Ollama container for a completely free, no-API-key run
- New `demo/dashboard.py`: generates a self-contained HTML report with
  charts of your mood/sleep/stress/energy/hydration trends and the
  correlations Hermes detects - pure local data analysis, no LLM call
- 7 new tests for the dashboard - suite grew from 129 to 136 tests

**v1.6.0 - Multi-Provider LLM Support**
- New `demo/llm_providers.py`: provider-agnostic client layer supporting
  Ollama (free, fully local, no API key), OpenAI, Anthropic, and
  OpenRouter, with auto-detection from whichever key is set
- `--provider` flag / `LIFE_OS_PROVIDER` env var to force a specific backend
- Friendly troubleshooting output on connection/auth failures instead of
  raw tracebacks
- 16 new unit tests (`test_llm_providers.py`) covering provider resolution
  and the Anthropic <-> OpenAI message/tool format adapter - total suite
  grew from 113 to 129 tests, all passing

**v1.5.0 - Modular Architecture, Scheduler & Notifications**
- Split the ~1600-line `demo_life_os.py` monolith into focused, independently
  testable modules: `storage.py`, `patterns.py`, `tools.py` (demo_life_os.py
  is now the CLI/chat/voice orchestration layer only)
- New `demo/scheduler.py`: dependency-free cron-style engine implementing
  the Daily Rhythm table (07:00 morning, 12:00 midday, 18:00 evening,
  Monday 08:00 weekly), with pure, fully unit-tested scheduling logic
- New `demo/notifications.py`: pluggable delivery via console, webhook,
  Telegram, or email (SMTP) - stdlib only, never crashes on missing config
- New `demo/run_scheduler.py`: production entry point wiring the scheduler
  to real briefing generation and delivery
- 77 new unit tests (`test_storage.py`, `test_tools.py`, `test_scheduler.py`,
  `test_notifications.py`) - total suite grew from 36 to 113 tests, all passing

**v1.4.0 - Real Correlation Engine**
- New `demo/analytics.py` module: pure-stdlib Pearson correlation analysis
  across mood, sleep, stress, energy, and hydration
- `detect_patterns()` now computes actual daily-aggregated correlations
  (r-value, day count, direction, strength) instead of a static placeholder
  message ("correlation analysis active")
- Correlation insights are surfaced automatically in `detect_patterns`
  tool output, feeding into morning/evening/weekly briefings
- 14 new unit tests covering the correlation engine (`tests/test_analytics.py`)

**v1.3.0 - Dream Journal**
- Dream logging mode with symbol, emotion, tone and vividness tracking
- Sleep/mood/stress/dream correlation detection
- Recurring symbol pattern detection across 30 days
- Morning briefing includes dream analysis

**v1.2.0 - Voice & Performance**
- Voice mode - speak to Hermes, hear responses via system TTS
- Concurrent tool execution - read-only tools run in parallel threads
- Microphone input via SpeechRecognition

**v1.1.0 - Health & Wellness Expansion**
- Nutrition, sleep, hydration, fitness, mental, focus tracking
- Full health dashboard and weekly health report
- Interactive chat mode

**v1.0.0 - Initial Release**
- 12 demo modes covering every life dimension
- Pattern detection across mood, sleep, nutrition, stress, focus
- Memory-driven briefings, Atropos RL environment

---

## Running Tests

```bash
python -m pytest tests/ -v
python -c "from environments.life_os_env import smoke_test; smoke_test()"
```

## Why This Is Different

Every other agent in this hackathon does something **for** you.
Hermes Life OS becomes something **with** you.

It tracks nutrition, sleep, fitness, stress, focus, hydration, habits, and goals -
and connects them all. Bad Monday? It checks if you slept poorly Sunday.
Energy crash at 3pm? It looks at what you ate for lunch.
Mood dip this week? It finds the pattern you missed.

That is not a tool. That is a presence that accumulates.
