Skip to content

Repository files navigation

AI Fitness Trainer

Personal AI fitness coach that runs as a Telegram bot, powered by Claude Code (Max subscription). It integrates with Intervals.icu for training data, Google Calendar for scheduling, and web search for fitness research.

Built for triathletes (swim/bike/run) and weight lifters.

Features

  • Data-driven coaching — queries your Intervals.icu data (activities, training load, wellness, power curves) before giving advice
  • Calendar-aware — checks Google Calendar to schedule workouts around your life
  • Morning briefing — configurable daily cron that sends your training plan, checks wellness, and asks how you're feeling
  • Self-improving — give feedback ("I'm vegetarian", "I have a knee injury") and the coach remembers it permanently by editing its own instructions
  • Conversation memory — sessions persist across container restarts via SQLite
  • Single-user — whitelist-based access, responds only to your Telegram account

Architecture

Telegram --> Go bot (go-telegram/bot) --> claude -p subprocess --> Anthropic API
                                               |
                             +-----------------+-----------------+
                             |                 |                 |
                       intervals-mcp      gcal-mcp          WebSearch
                       (Go binary)       (Go binary)             |
                             |                 |                Web
                       Intervals.icu    Google Calendar

All components run inside a single Docker container. Claude Code CLI authenticates via OAuth token (Max subscription — no API key billing).

Prerequisites

Setup

1. Get your Claude Code OAuth token

This token lets Claude Code run headless inside Docker using your Max subscription.

# Install Claude Code if you haven't already
curl -fsSL https://downloads.claude.ai/claude-code-releases/bootstrap.sh | bash

# Generate a long-lived OAuth token for headless use
claude setup-token

Copy the token (sk-ant-oat01-...) for use in the .env file.

2. Create a Telegram bot

  1. Open Telegram and message @BotFather
  2. Send /newbot and follow the prompts (pick a name and a username ending in bot)
  3. Copy the bot token (format: 123456789:AAH...)

Then get your numeric user ID:

  1. Message @userinfobot on Telegram
  2. It replies with your numeric ID (e.g. 7064223637)

3. Get Intervals.icu credentials

  1. Log in to intervals.icu
  2. Go to Settings (gear icon)
  3. Scroll to the bottom — Developer Settings section
  4. Copy your API Key
  5. Your Athlete ID is shown there too (starts with i, e.g. i518868). It's also visible in the URL when you view your profile.

The bot uses intervals-mcp, a Go-based MCP server that exposes 144 tools for the full Intervals.icu API. It's built from source during docker build.

4. Google Calendar setup (optional)

See docs/google-calendar-setup.md for the full guide, including multi-account support (e.g. personal + work calendars).

Quick version:

  1. Create a Google Cloud project and enable the Google Calendar API
  2. Create OAuth credentials (Desktop app) and save to ./config/gcp-oauth.keys.json
  3. Run the auth flow:
    GOOGLE_OAUTH_CREDENTIALS=./config/gcp-oauth.keys.json \
    GOOGLE_CALENDAR_MCP_TOKEN_PATH=./config/gcal-tokens.json \
      go run ./cmd/gcal-mcp/ auth
  4. For multiple accounts, pass a nickname: ... auth personal, ... auth work

5. Configure environment

cp .env.example .env

Edit .env with your values:

# Required
TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
ALLOWED_TELEGRAM_USER_IDS=7064223637
CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...
INTERVALS_API_KEY=your-api-key
INTERVALS_ATHLETE_ID=i12345
TZ=Europe/Lisbon

# Optional
CLAUDE_MODEL=sonnet          # sonnet/opus/haiku
CLAUDE_TIMEOUT=120           # seconds
BRIEFING_HOUR=7              # morning briefing time (0-23)
BRIEFING_MINUTE=0            # (0-59)
LOG_LEVEL=INFO

6. Build and run

docker compose build
docker compose up -d

Check the logs:

docker compose logs -f

Usage

Command Description
/start Welcome message
/new Reset conversation (start fresh session)
Any text Chat with your AI coach

Example messages

  • "What were my last 3 activities?"
  • "How's my training load looking this week?"
  • "I have a half marathon in 8 weeks, help me plan"
  • "What should I eat before a long ride?"
  • "Remember that I'm vegetarian" (self-improving — saved permanently)

Morning briefing

The bot sends a daily check-in at the configured time (default 07:00). It:

  1. Checks your Intervals.icu training plan for the day
  2. Reviews recent wellness data (sleep, HRV, soreness)
  3. Looks at your training load and fatigue
  4. Recommends what to do
  5. Asks how you're feeling

Customizing the coach

Edit CLAUDE.md to change the coach's personality, knowledge areas, or behavior. Changes take effect on the next message — no rebuild needed.

The coach also edits its own CLAUDE.md when you give it feedback (e.g. dietary preferences, injury history, race goals). Check the "Athlete Profile" and "Learned Preferences" sections at the bottom of the file to see what it's learned.

Project structure

ai_fitness_trainer/
├── cmd/
│   ├── bot/main.go           # Telegram bot entrypoint
│   └── gcal-mcp/main.go      # Google Calendar MCP server + auth CLI
├── internal/
│   ├── config/               # Environment variable loading
│   ├── store/                # SQLite session/KV/activity persistence
│   ├── claude/               # Claude CLI subprocess wrapper (stream-json)
│   ├── telegram/             # Bot handlers + message splitting
│   └── scheduler/            # Morning briefing cron + activity check
├── .env.example              # Template for secrets
├── .mcp.json                 # MCP server config (intervals-icu + google calendar)
├── CLAUDE.md                 # Coach personality + self-improving memory
├── Dockerfile                # Multi-stage: Go build + Claude CLI
├── docker-compose.yml
└── go.mod

Troubleshooting

Bot doesn't respond: Check docker compose logs -f for errors. Common issues:

  • Invalid CLAUDE_CODE_OAUTH_TOKEN — regenerate with claude setup-token
  • Wrong ALLOWED_TELEGRAM_USER_IDS — must be numeric, not username

Session errors after restart: The bot auto-recovers by starting a fresh session if --resume fails.

OAuth token expired: Re-run claude setup-token on your host, update .env, and docker compose restart.

Morning briefing not sending: Check that TZ is set correctly and the container clock matches. Verify with docker compose exec bot date.

About

Personal AI fitness coach on Telegram — powered by Claude Code, Intervals.icu, and Google Calendar. Self-improving, with daily training briefings

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages