# Pierre MCP Server - Development Environment
# Copy this to .envrc for local development settings
#
# Setup:
# cp .envrc.example .envrc
# # Edit values below
# direnv allow # or: source .envrc
#
# ============================================================================
# ENVIRONMENT VARIABLE CATEGORIES
# ============================================================================
#
# Category | Variables | Required By
# ------------------|----------------------------------------------|------------------
# 1. CRITICAL | DATABASE_URL, PIERRE_MASTER_ENCRYPTION_KEY | All server scripts
# 2. Provider OAuth | PIERRE_*_CLIENT_ID/SECRET | Based on PIERRE_DEFAULT_PROVIDER
# 3. Server Config | HTTP_PORT, RUST_LOG, JWT_EXPIRY_HOURS | Defaults provided
# 4. Database Pool | POSTGRES_*, SQLX_* | PostgreSQL only
# 5. Features | PIERRE_*_ALGORITHM, FITNESS_*, CACHE_*, etc. | All optional
# 6. Development | OAUTH_DEFAULT_*, ADMIN_EMAIL/PASSWORD | Dev/test scripts
# 7. Frontend | VITE_BACKEND_URL | start-frontend.sh
# 8. Mobile | EXPO_PUBLIC_API_URL | Mobile app
#
# Scripts will FAIL FAST if:
# - .envrc is missing
# - CRITICAL variables (DATABASE_URL, PIERRE_MASTER_ENCRYPTION_KEY) are unset
#
# Generate encryption key: openssl rand -base64 32
#
# Full documentation: book/src/environment.md
#
# ============================================================================
# PROVIDER CONFIGURATION - Pluggable Provider Architecture (Phase 1)
# ============================================================================
# Default Provider
# Set which provider to use as default: "strava", "garmin", "synthetic"
# - "synthetic": Development without OAuth (default if not set)
# - "strava": Real OAuth testing with Strava
# - "garmin": Real OAuth testing with Garmin
export PIERRE_DEFAULT_PROVIDER=strava
# ----------------------------------------------------------------------------
# Strava Provider Configuration
# ----------------------------------------------------------------------------
# OAuth Credentials (required for Strava OAuth)
export PIERRE_STRAVA_CLIENT_ID=your-strava-client-id
export PIERRE_STRAVA_CLIENT_SECRET=your-strava-client-secret
# Advanced: Override default Strava endpoints (optional)
# Uncomment to customize for testing or proxy scenarios
# export PIERRE_STRAVA_AUTH_URL=https://www.strava.com/oauth/authorize
# export PIERRE_STRAVA_TOKEN_URL=https://www.strava.com/oauth/token
# export PIERRE_STRAVA_API_BASE_URL=https://www.strava.com/api/v3
# export PIERRE_STRAVA_REVOKE_URL=https://www.strava.com/oauth/deauthorize
# Advanced: Override default scopes (optional)
# export PIERRE_STRAVA_SCOPES="activity:read_all,profile:read_all"
# Legacy Variables (backward compatible - will be used if PIERRE_* vars not set)
export STRAVA_CLIENT_ID=your-strava-client-id
export STRAVA_CLIENT_SECRET=your-strava-client-secret
export STRAVA_REDIRECT_URI=http://localhost:8081/api/oauth/callback/strava
# ----------------------------------------------------------------------------
# Garmin Connect Provider Configuration
# ----------------------------------------------------------------------------
# OAuth Credentials (required for Garmin OAuth)
export PIERRE_GARMIN_CLIENT_ID=your-garmin-consumer-key
export PIERRE_GARMIN_CLIENT_SECRET=your-garmin-consumer-secret
# Advanced: Override default Garmin endpoints (optional)
# Uncomment to customize for testing or proxy scenarios
# export PIERRE_GARMIN_AUTH_URL=https://connect.garmin.com/oauthConfirm
# export PIERRE_GARMIN_TOKEN_URL=https://connectapi.garmin.com/oauth-service/oauth/access_token
# export PIERRE_GARMIN_API_BASE_URL=https://apis.garmin.com/wellness-api/rest
# export PIERRE_GARMIN_REVOKE_URL=https://connectapi.garmin.com/oauth-service/oauth/revoke
# Advanced: Override default scopes (optional)
# export PIERRE_GARMIN_SCOPES="wellness:read,activities:read"
# Legacy Variables (backward compatible - will be used if PIERRE_* vars not set)
export GARMIN_CLIENT_ID=your-garmin-consumer-key
export GARMIN_CLIENT_SECRET=your-garmin-consumer-secret
export GARMIN_REDIRECT_URI=http://localhost:8081/api/oauth/callback/garmin
# ----------------------------------------------------------------------------
# Synthetic Provider Configuration
# ----------------------------------------------------------------------------
# No OAuth credentials needed - synthetic provider works out of the box!
# Perfect for development, testing, and demos without external API dependencies.
# Just set PIERRE_DEFAULT_PROVIDER=synthetic (or omit it, as synthetic is the default)
# Bridge OAuth Callback Configuration
# After provider OAuth completes, server redirects to bridge callback server to trigger focus recovery
export OAUTH_CALLBACK_PORT=35535
# Weather Service Configuration
export OPENWEATHER_API_KEY="your-openweathermap-api-key"
# ----------------------------------------------------------------------------
# LLM Provider Configuration
# ----------------------------------------------------------------------------
# Provider selection: gemini, groq, or local (Ollama)
export PIERRE_LLM_PROVIDER=gemini
# Gemini Configuration (when PIERRE_LLM_PROVIDER=gemini)
export GEMINI_API_KEY="your-gemini-api-key"
export PIERRE_LLM_DEFAULT_MODEL=gemini-3-flash-preview
export PIERRE_LLM_FALLBACK_MODEL=gemini-2.5-flash
# Groq Configuration (when PIERRE_LLM_PROVIDER=groq)
export GROQ_API_KEY="your-groq-api-key"
# export GROQ_DEFAULT_MODEL=llama-3.3-70b-versatile
# export GROQ_FALLBACK_MODEL=llama-3.3-70b-versatile
# Local LLM Configuration (when PIERRE_LLM_PROVIDER=local)
# export LOCAL_LLM_BASE_URL="http://localhost:11434/v1"
# export LOCAL_LLM_MODEL="qwen2.5:14b-instruct"
# export LOCAL_LLM_FALLBACK_MODEL="qwen2.5:14b-instruct"
# Server Configuration - Unified Single Port Architecture
export HTTP_PORT="8081"
export RUST_LOG="info"
# Database Configuration
export DATABASE_URL="sqlite:./data/users.db"
# For PostgreSQL: export DATABASE_URL="postgresql://user:pass@localhost/pierre_db"
export JWT_EXPIRY_HOURS="24"
# Admin Token Cache Configuration
# Cache validated admin tokens to reduce database lookups (seconds)
export ADMIN_TOKEN_CACHE_TTL_SECS="300" # Default: 300 (5 minutes)
# PostgreSQL Connection Pool Configuration (when using PostgreSQL)
# These values are automatically optimized for CI vs production environments
export POSTGRES_MAX_CONNECTIONS="10" # Default: 10 (prod), 5 (CI)
export POSTGRES_MIN_CONNECTIONS="0" # Default: 0 (prod), 1 (CI)
export POSTGRES_ACQUIRE_TIMEOUT="30" # Default: 30 (prod), 30 (CI)
# Master Encryption Key for persistent two-tier key management
# Generate with: openssl rand -base64 32
export PIERRE_MASTER_ENCRYPTION_KEY="your-base64-encoded-master-key"
# RSA Key Size for JWT signing (RS256)
# Production: 4096 (higher security, slower ~10s key generation)
# Testing: 2048 (faster ~250ms key generation, sufficient for dev/test)
export PIERRE_RSA_KEY_SIZE="2048" # Use 4096 for production
# Rate Limiting Configuration (tier-based burst limits)
export RATE_LIMIT_FREE_TIER_BURST="10"
export RATE_LIMIT_PROFESSIONAL_BURST="50"
export RATE_LIMIT_ENTERPRISE_BURST="100"
# Backup Configuration
export BACKUP_ENABLED="true"
export BACKUP_INTERVAL="21600" # 6 hours in seconds
export BACKUP_RETENTION="7"
export BACKUP_DIRECTORY="./backups"
# Activity Fetch Limits
export MAX_ACTIVITIES_FETCH="100"
export DEFAULT_ACTIVITIES_LIMIT="20"
# ============================================================================
# FITNESS CONFIGURATION - Environment-Only (Cloud-Native Approach)
# ============================================================================
# All fitness algorithm parameters are now configured via environment variables
# for easy cloud deployment. No TOML files - single source of truth.
# Fitness Effort Thresholds (1-10 scale for workout intensity classification)
export FITNESS_EFFORT_LIGHT_MAX="3.0"
export FITNESS_EFFORT_MODERATE_MAX="5.0"
export FITNESS_EFFORT_HARD_MAX="7.0"
# > 7.0 = very_high
# Heart Rate Zone Thresholds (percentage of max HR)
export FITNESS_ZONE_RECOVERY_MAX="60.0"
export FITNESS_ZONE_ENDURANCE_MAX="70.0"
export FITNESS_ZONE_TEMPO_MAX="80.0"
export FITNESS_ZONE_THRESHOLD_MAX="90.0"
# > 90.0 = vo2max
# Weather Integration Settings
export FITNESS_WEATHER_WIND_THRESHOLD="15.0"
export FITNESS_WEATHER_ENABLED="true"
export FITNESS_WEATHER_CACHE_DURATION_HOURS="24"
export FITNESS_WEATHER_REQUEST_TIMEOUT_SECONDS="10"
export FITNESS_WEATHER_RATE_LIMIT_PER_MINUTE="60"
# Personal Records Configuration
export FITNESS_PR_PACE_IMPROVEMENT_THRESHOLD="5.0"
# OAuth Login Form Defaults (for dev/test only - leave empty in production)
export OAUTH_DEFAULT_EMAIL="user@example.com"
export OAUTH_DEFAULT_PASSWORD="userpass123"
# Admin User Defaults (for dev/test scripts - leave empty in production)
export ADMIN_EMAIL="admin@pierre.mcp"
export ADMIN_PASSWORD="adminpass123"
# ============================================================================
# CACHE CONFIGURATION
# ============================================================================
# Cache TTL Configuration (seconds)
export CACHE_TTL_PROFILE_SECS="86400" # 24 hours - athlete profiles change infrequently
export CACHE_TTL_ACTIVITY_LIST_SECS="900" # 15 minutes - needs to be fresh for new activities
export CACHE_TTL_ACTIVITY_SECS="3600" # 1 hour - activity details rarely change
export CACHE_TTL_STATS_SECS="21600" # 6 hours - stats aggregate over time windows
# Cache General Settings
export CACHE_MAX_ENTRIES="10000"
export CACHE_CLEANUP_INTERVAL_SECS="300" # 5 minutes
# Redis Connection Configuration (when using Redis cache)
# export REDIS_URL="redis://localhost:6379"
export REDIS_CONNECTION_TIMEOUT_SECS="10"
export REDIS_RESPONSE_TIMEOUT_SECS="5"
export REDIS_RECONNECTION_RETRIES="5"
export REDIS_RETRY_EXPONENT_BASE="2"
export REDIS_MAX_RETRY_DELAY_MS="30000"
export REDIS_INITIAL_CONNECTION_RETRIES="3"
export REDIS_INITIAL_RETRY_DELAY_MS="500"
# ============================================================================
# TOOL SELECTION CONFIGURATION
# ============================================================================
# Global tool disabling - comma-separated list of tool names to disable globally
# These tools will be hidden from ALL tenants regardless of plan or overrides
# Use this for experimental features, tools under maintenance, or staged rollouts
#
# Example: Disable performance prediction and activity intelligence
# export PIERRE_DISABLED_TOOLS="predict_performance,get_activity_intelligence"
#
# Common use cases:
# - Disable beta features: export PIERRE_DISABLED_TOOLS="experimental_feature"
# - Maintenance mode: export PIERRE_DISABLED_TOOLS="connect_provider"
# - Staged rollout: Start with all advanced tools disabled, enable gradually
#
# Tool enablement precedence (highest to lowest):
# 1. PIERRE_DISABLED_TOOLS (global disable - this setting)
# 2. Plan restrictions (tools require minimum tenant plan)
# 3. Tenant overrides (admin-configured per-tenant settings)
# 4. Catalog defaults (tool_catalog.is_enabled_by_default)
#
# Leave empty or unset to allow all tools based on plan and overrides
# export PIERRE_DISABLED_TOOLS=""
# ============================================================================
# HTTP CLIENT CONFIGURATION
# ============================================================================
# HTTP Client Timeouts (seconds)
export HTTP_CLIENT_TIMEOUT_SECS="30"
export HTTP_CLIENT_CONNECT_TIMEOUT_SECS="10"
export OAUTH_CLIENT_TIMEOUT_SECS="15"
export OAUTH_CLIENT_CONNECT_TIMEOUT_SECS="5"
export API_CLIENT_TIMEOUT_SECS="60"
export API_CLIENT_CONNECT_TIMEOUT_SECS="10"
export HEALTH_CHECK_TIMEOUT_SECS="5"
export OAUTH_CALLBACK_NOTIFICATION_TIMEOUT_SECS="5"
# HTTP Client Retry Configuration
export HTTP_CLIENT_ENABLE_RETRIES="true"
export HTTP_CLIENT_MAX_RETRIES="3"
export HTTP_CLIENT_RETRY_BASE_DELAY_MS="100"
export HTTP_CLIENT_RETRY_MAX_DELAY_MS="5000"
export HTTP_CLIENT_RETRY_JITTER_ENABLED="true"
# ============================================================================
# PROVIDER RETRY CONFIGURATION - Exponential Backoff
# ============================================================================
# These settings control retry behavior for provider API calls (Strava, Garmin, etc.)
# Uses exponential backoff with jitter to prevent thundering herd problems.
# Maximum retry attempts (not counting initial attempt)
# Valid range: 1-100, Default: 3
export PIERRE_RETRY_MAX_ATTEMPTS="3"
# Base delay for exponential backoff (milliseconds)
# Delay doubles with each retry: 1000ms, 2000ms, 4000ms...
# Valid range: 100-300000, Default: 1000
export PIERRE_RETRY_BASE_DELAY_MS="1000"
# Maximum delay between retries (milliseconds)
# Caps the exponential growth to prevent excessive waits
# Valid range: 1000-600000, Default: 30000
export PIERRE_RETRY_MAX_DELAY_MS="30000"
# Jitter factor (0.0 to 1.0) to randomize delays
# Prevents synchronized retries across multiple clients
# Valid range: 0.0-1.0, Default: 0.1
export PIERRE_RETRY_JITTER_FACTOR="0.1"
# ============================================================================
# SSE (SERVER-SENT EVENTS) CONFIGURATION
# ============================================================================
export SSE_CLEANUP_INTERVAL_SECS="300" # 5 minutes
export SSE_CONNECTION_TIMEOUT_SECS="600" # 10 minutes
export SSE_MAX_BUFFER_SIZE="1000"
export SSE_BUFFER_OVERFLOW_STRATEGY="drop_oldest" # Options: drop_oldest, drop_new, close_connection
export SSE_BROADCAST_CHANNEL_SIZE="1000"
export SSE_MAX_CONNECTIONS_PER_USER="5"
export SESSION_COOKIE_MAX_AGE_SECS="86400" # 24 hours
export SESSION_COOKIE_SECURE="false" # Set to true in production with HTTPS
# ============================================================================
# MCP SERVER CONFIGURATION
# ============================================================================
export MCP_PROTOCOL_VERSION="2025-06-18"
export SERVER_NAME="pierre-mcp-server"
export MCP_SESSION_CACHE_SIZE="100"
export MCP_MAX_REQUEST_SIZE="1048576" # 1MB
export MCP_MAX_RESPONSE_SIZE="10485760" # 10MB
export MCP_NOTIFICATION_CHANNEL_SIZE="100"
export MCP_WEBSOCKET_CHANNEL_CAPACITY="1000"
export TCP_KEEP_ALIVE_SECS="60"
# ============================================================================
# PROVIDER RATE LIMITS AND ACTIVITY SETTINGS
# ============================================================================
# Strava Provider Settings
export STRAVA_DEFAULT_ACTIVITIES_PER_PAGE="30"
export STRAVA_MAX_ACTIVITIES_PER_REQUEST="200"
export STRAVA_RATE_LIMIT_15MIN="100"
export STRAVA_RATE_LIMIT_DAILY="15000"
# Fitbit Provider Settings
export FITBIT_RATE_LIMIT_HOURLY="150"
export FITBIT_RATE_LIMIT_DAILY="1000"
# Garmin Provider Settings
export GARMIN_DEFAULT_ACTIVITIES_PER_PAGE="20"
export GARMIN_MAX_ACTIVITIES_PER_REQUEST="100"
export GARMIN_MAX_REQUESTS_PER_HOUR="100"
export GARMIN_MIN_LOGIN_INTERVAL_SECS="300" # 5 minutes
export GARMIN_RATE_LIMIT_BLOCK_DURATION_SECS="3600" # 1 hour
# ============================================================================
# OAUTH RATE LIMITING
# ============================================================================
export OAUTH_AUTHORIZE_RATE_LIMIT_RPM="60"
export OAUTH_TOKEN_RATE_LIMIT_RPM="30"
export OAUTH_REGISTER_RATE_LIMIT_RPM="10"
export OAUTH2_RATE_LIMIT_WINDOW_SECS="60"
export RATE_LIMITER_CLEANUP_THRESHOLD="1000"
export RATE_LIMITER_STALE_ENTRY_TIMEOUT_SECS="120"
# ============================================================================
# SYSTEM MONITORING
# ============================================================================
export MONITORING_MEMORY_WARNING_THRESHOLD="80.0" # Warn at 80% memory usage
export MONITORING_DISK_WARNING_THRESHOLD="85.0" # Warn at 85% disk usage
# ============================================================================
# ROUTE TIMEOUT CONFIGURATION
# ============================================================================
export ROUTE_TIMEOUT_DATABASE_SECS="30"
export ROUTE_TIMEOUT_PROVIDER_API_SECS="60"
export ROUTE_TIMEOUT_SSE_EVENT_SECS="5"
export ROUTE_TIMEOUT_OAUTH_SECS="15"
export ROUTE_TIMEOUT_DEFAULT_SECS="30"
export ROUTE_TIMEOUT_UPLOAD_SECS="300"
export ROUTE_TIMEOUT_LONG_POLLING_SECS="300"
export ROUTE_TIMEOUT_MCP_SAMPLING_SECS="30"
export ROUTE_TIMEOUT_GEOCODING_SECS="10"
# ============================================================================
# TOKIO RUNTIME CONFIGURATION
# ============================================================================
# Uncomment to customize Tokio runtime settings
# export TOKIO_WORKER_THREADS="" # Default: CPU count
# export TOKIO_THREAD_STACK_SIZE="" # Default: ~2MB
export TOKIO_THREAD_NAME="pierre-worker"
# ============================================================================
# SQLX CONNECTION POOL CONFIGURATION
# ============================================================================
# export SQLX_IDLE_TIMEOUT_SECS="" # Default: 10 min (PostgreSQL)
# export SQLX_MAX_LIFETIME_SECS="" # Default: 30 min
export SQLX_TEST_BEFORE_ACQUIRE="true"
# export SQLX_STATEMENT_CACHE_CAPACITY="" # Default: 100