Applied AI· fitness-agent · Coach Aurelius

Personal AI Fitness Coach

The Problem

Modern training data is everywhere and useless. WHOOP knows your overnight recovery, Strava knows what you ran, your lifting notebook is on paper, the weather app is a separate tab, and your training plan lives in your head. None of them talk to each other, and none of them tell you what to do today. The question an athlete wakes up with (given how I slept, how my body recovered, what I ran yesterday, and what’s on the plan, what should this session actually look like?) isn’t answered by any one app.

What I Did

I built a personal AI coach that lives in Discord and answers exactly that. The moment my overnight WHOOP recovery record lands, the bot fuses it with a 7-day physiology trend, recent Strava activity, weather and air quality, and a RAG knowledge base of running, strength, recovery, nutrition, and periodization literature, then prescribes a specific session: pace, HR ceiling, lift template, fueling notes. It isn’t a generic recommendation; it’s a call grounded in the actual state of the athlete that morning.

Lift logging happens conversationally: type “bench 3x10 at 145” and it parses the set, writes it to SQLite, mirrors it to a five-database Notion journal, and flags PRs. The real design challenge was context. A year of history doesn’t fit in a prompt, and re-fetching from WHOOP/Strava every turn was slow and expensive. So I built a layered context system (7 days of detail, 30 days of aggregate, a 1-year baseline, roughly 1K tokens instead of 90K) and gave Claude tools to pull more on demand.

It runs as a systemd service on a small Ubuntu VPS, ingests WHOOP and Strava via webhooks, and redeploys on push to main. With the coaching engine solid, I’m now wrapping its Python brain in a thin FastAPI layer behind Coach Aurelius, a touch-native iOS front end.

Aurelius Today screen: morning recovery score, WHOOP metrics, and the prescribed training session Aurelius Coach chat: the AI reasoning over recovery, recent lifts, and marathon training to answer questions Aurelius Trends screen: 8-week charts for bench estimated 1RM, weekly mileage, HRV, and bodyweight
The coach running in Discord: a logged bench set, a recap of the day's sets pulled from memory, and a coaching call to end the session
The coach running in Discord: conversational logging, session-aware memory, and a real call on when to stop
Data Sources
WHOOP API
Overnight recovery, sleep, HRV, and strain: the primary physiological signal, the trigger for the morning brief and the basis for every prescription.
Strava API
Activity history with pace, heart-rate zones, and distance: the performance side of the ledger, fused with WHOOP for the post-workout debrief.
Open-Meteo
Free, no-key weather and air-quality feed: the environmental layer that shifts an outdoor session’s pace target or routes it indoors.
Stack
Python 3.11 + asyncio
Single-process event loop hosting the Discord client, scheduler, and webhook server: one runtime, no broker, no cron.
discord.py
User-facing surface: morning brief, conversational chat, slash-command tree, and lift logging by free-form message.
Anthropic Claude
Sonnet for the morning brief and post-workout debrief; Haiku for fast conversational chat. Grounded in live physiology + RAG retrieval for every call.
ChromaDB + sentence-transformers
Local RAG store over a curated markdown knowledge base (running, strength, recovery, nutrition, periodization), embedded once and retrieved per query.
Notion API (5 databases)
Background-written training journal: Schedule, Lifts, Lift Sets, Runs, Daily Log. Relational, queryable, visible as a normal Notion page.
SQLite via aiosqlite
Local source of truth for lifts and notes: async, file-based, zero-ops, survives Notion outages.
systemd + GitHub Actions
Runs as a systemd service on a small Ubuntu VPS; zero-downtime redeploy on push to main.
← All work