Running Manager is an open-source Streamlit application for managing trail running coaching. It provides coaches and athletes with tools to plan training sessions, track activities from Strava or Garmin, analyze performance metrics, and manage running goals.
Key screenshots from the application to give a quick visual overview:
- Weekly Planner: Create and manage training sessions with flexible session types (fundamental endurance, long runs, intervals, races)
- Session Templates: Save and reuse session configurations for consistent planning
- Strava Integration: OAuth-based sync with automatic activity import (14-day window, incremental updates)
- Activity Linking: Manual matching of planned sessions with logged activities; RPE tracking
- Performance Analytics:
- Planned vs actual workload comparison (weekly/daily)
- Training load metrics (acute/chronic TRIMP, distance-equivalent)
- Multi-metric visualization (time, distance, DistEq, TRIMP)
- Speed-effort scatter plots
- Advanced Metrics:
- Distance-equivalent (DistEq) calculations accounting for elevation gain
- Sport-specific equivalence (e.g., bike ride DistEq factors)
- TRIMP (Training Impulse) using HR reserve weighting
- Rolling training loads (7-day acute, 28-day chronic)
- Interval Workouts: Structured interval step editor with repeatable blocks and recovery phases
- Garmin Support: (Stub) Framework for future Garmin Connect integration
- FR/EN Locale: Fr-FR formatting for European users; extensible to other languages
- Python 3.11 or later
- uv package manager (recommended) or pip
# Clone the repository
git clone https://github.com/piromagnus/RunningManager
cd RunningManager
# Install dependencies
uv sync
rm -rf data/* # Clean the data directory to start fresh
# Or with pip:
# pip install -r requirements.txt
# Run the application
uv run streamlit run app.pyThe app will open at http://localhost:8501.
Create a .env file in the project root:
cp .env.example .envEdit .env with your configuration:
# Data storage directory
DATA_DIR=./data
# Strava API Integration (optional)
STRAVA_CLIENT_ID=your_client_id
STRAVA_CLIENT_SECRET=your_client_secret
STRAVA_REDIRECT_URI=http://localhost:8501/callback
# Encryption key for token storage (required if using Strava)
ENCRYPTION_KEY=<generate-via-command-below>
# Mapbox for premium basemaps (optional)
MAPBOX_API_KEY=your_mapbox_tokenpython3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"- Go to Strava API Settings
- Create an app with:
- Application Name: RunningManager
- Category: Other
- Callback Domain:
localhost(dev) or your domain (prod)
- Copy
Client IDandClient Secretto.env - Set
STRAVA_REDIRECT_URI(default:"http://localhost:8501/Settings")
- Create account at Mapbox
- Generate access token
- Add to
.envasMAPBOX_API_KEY
uv run streamlit run app.py- Planner: Create and manage weekly training sessions
- Activities: View activity feed, link unlinked sessions, browse activity details
- Dashboard: Training load trends and performance analytics
- Analytics: Planned vs actual metrics with flexible date ranges and category filters
- Settings: Strava integration, metrics recomputation, thresholds and goals configuration
- Athlete: Athlete profile management
- Goals: Set and track race/performance goals
# Run the full test suite
pytest
# Run with coverage
pytest --cov# Lint code (Ruff, line length 100)
ruff check .
# Format code
ruff format .RunningManager/
βββ app.py (Streamlit entry)
βββ pages/ (UI multi-page app)
β βββ Planner.py: Session planning
β βββ Dashboard.py: Training load trends
β βββ Analytics.py: Planned vs actual analysis
β βββ Activities.py: Activity feed & linking
β βββ Settings.py: Integrations & config
βββ widgets/ (Reusable UI components)
β βββ athlete_selector.py: Athlete selection widget
β βββ session_forms.py: Session type form renderers
β βββ template_selector.py: Template selection UI
β βββ comparison_panel.py: Activity comparison display
β βββ ...
βββ graph/ (Visualization components)
β βββ training_load.py: Acute/chronic load charts
β βββ hr_speed.py: HR vs Speed scatter plots
β βββ elevation.py: Elevation profile with grade coloring
β βββ analytics.py: Planned vs actual bar charts
β βββ ...
βββ services/ (Domain logic)
β βββ planner_service.py: Estimation (pace, distance, TRIMP)
β βββ metrics_service.py: Metrics pipeline
β βββ analytics_service.py: Analytics computations
β βββ strava_service.py: OAuth & sync
β βββ dashboard_data_service.py: Dashboard data loading
β βββ ...
βββ persistence/ (CSV storage)
β βββ csv_storage.py: Pandas + portalocker IO
β βββ repositories.py: CRUD repos
βββ utils/ (Helpers)
βββ config.py: Env loading & secrets
βββ formatting.py: fr-FR locale display
βββ segments.py: Segment merging utilities
βββ dashboard_state.py: Dashboard state management
βββ elevation_preprocessing.py: Elevation data preprocessing
βββ ...CSV Tables (stored in DATA_DIR, default ./data/):
activities.csv: Imported from Strava/Garminplanned_sessions.csv: Coach-created training sessionslinks.csv: Manual matches between sessions and activitiesactivities_metrics.csv: Computed per-activity metricsplanned_metrics.csv: Computed per-session estimatesweekly_metrics.csv: Weekly aggregates (planned/actual)daily_metrics.csv: Daily aggregates with rolling windowsathletes.csv,settings.csv,thresholds.csv,goals.csv,templates.csv, etc.
Timeseries: data/timeseries/{activityId}.csv β sampled HR, pace, elevation, etc.
- CSV Decimals: Always use
.(period) as decimal separator; never locale-specific commas - Locale Display: Use
utils/formatting.pyfor UI display only; storage keeps raw decimals - File Locking: All CSV reads/writes use
portalockerfor safe concurrent access - Secrets: Never hardcode; load via
.env; encrypt sensitive tokens with Fernet
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Install dev dependencies:
uv sync - Make your changes
- Run tests:
pytest - Lint:
ruff check . && ruff format . - Commit with clear messages:
git commit -m "feat: add feature X" - Push and create a Pull Request
- Line Length: 100 characters (Ruff configured)
- Imports: Sorted with Ruff (isort rules)
- Format: Black-compatible formatting via Ruff
- Type Hints: Use type annotations for public APIs
- Testing: Add tests for new behavior; maintain >80% coverage
- File Organization: Keep files under 500 lines; extract reusable components to
widgets/and visualizations tograph/
- Bug Fixes: Report issues on GitHub; PRs welcome
- Features: Garmin integration, additional analytics, TCX export enhancements
- Documentation: Improve guides, add examples, translate to other languages
- Performance: Optimize CSV loading, chart rendering, metrics computation
- Testing: Expand test coverage, add integration tests
- UI/UX: Improve interface clarity, accessibility, internationalization
When reporting bugs, please include:
- Python version and OS
- Steps to reproduce
- Expected vs actual behavior
- Relevant logs or error messages
- Ensure all tests pass:
pytest - Update
AGENTS.mdordocs/if adding/changing architecture - Add tests for new features or bug fixes
- Keep commits focused and descriptive
- Reference related issues (e.g.,
Fixes #123)
This project is licensed under the GNU General Public License v3.0 (GPLv3). See LICENSE for full details.
Summary: You are free to use, modify, and distribute this software, provided that:
- You retain the copyright notice and license
- You provide a copy of the license with any distribution
- Any modifications are also licensed under GPLv3
- You disclose the source code if distributing the software
- Issues: Report bugs and request features on GitHub Issues
- Discussions: Join conversations on GitHub Discussions
- Documentation: See
AGENTS.mdfor developer guidelines
Thanks to all contributors who have helped improve Running Manager!
Running Manager is built by a trail running enthusiast, for coaches and athletes who want sophisticated training analytics in open source. We welcome your contributions and feedback!



