This guide explains how to create an automated JSON data mirror of your Intervals.icu training data for use with AI coaching systems.
Prefer an interactive guide? Paste SETUP_ASSISTANT.md into any AI chat and it will walk you through this entire setup step by step.
Running an agentic platform locally? If your AI coach runs on the same machine as your data (OpenClaw, Claude Code, Cowork, etc.), consider local sync instead — simpler setup, no GitHub needed, data never leaves your machine.
The data mirror automatically syncs your Intervals.icu metrics to a GitHub repository every 15 minutes, producing a static JSON URL that AI systems can read.
Result:
https://raw.githubusercontent.com/[you]/[repo]/main/latest.jsonhttps://raw.githubusercontent.com/[you]/[repo]/main/history.jsonhttps://raw.githubusercontent.com/[you]/[repo]/main/ftp_history.jsonhttps://raw.githubusercontent.com/[you]/[repo]/main/intervals.jsonhttps://raw.githubusercontent.com/[you]/[repo]/main/routes.json(when events have GPX/TCX attachments)
- Intervals.icu account with training data
- GitHub account
- 10 minutes for setup
Finding your credentials:
- Athlete ID: Intervals.icu → Settings → bottom of page (e.g.,
i123456) - API Key: Intervals.icu → Settings → Developer Settings → API Key
- Go to github.com/CrankAddict/section-11 → Fork
- Rename to
training-dataor similar - Set to Private in repo settings
- Skip to Step 3: Add Repository Secrets
- Go to github.com/new
- Name it something like
training-data - Set to Private (recommended) — most AI platforms now have GitHub connectors that can access private repos. See the main README for details.
- Check Add a README file
- Click Create repository
Then add these files to your repository:
| File | Location | Description |
|---|---|---|
sync.py |
Root | The sync script |
auto-sync.yml |
.github/workflows/ |
GitHub Actions workflow |
DATA_REPO_README.md |
Root (rename to README.md) |
README template with sync badge |
To create the workflow folder:
- Click "Add file" → "Create new file"
- Name it:
.github/workflows/auto-sync.yml - Paste the workflow content from examples/json-auto-sync/auto-sync.yml
- Commit
- Go to your repo → Settings → Secrets and variables → Actions
- Click New repository secret
- Add these secrets:
| Secret Name | Value |
|---|---|
ATHLETE_ID |
Your Intervals.icu athlete ID (e.g., i123456) |
INTERVALS_KEY |
Your Intervals.icu API key |
Optional: If your training week starts on a day other than Monday, add one more secret:
| Secret Name | Value |
|---|---|
WEEK_START |
Training week start day: mon, tue, wed, thu, fri, sat, or sun |
If not set, defaults to mon (ISO week). This controls phase detection windows — ensures deload/build classification aligns with your actual training week structure.
Optional: If you want HR zones used for aggregations in specific sports (e.g., running with auto-generated watch power):
| Secret Name | Value |
|---|---|
ZONE_PREFERENCE |
Per-sport zone override, e.g. run:hr,cycling:power |
Only override what you need — unspecified sports default to power-preferred with HR fallback. Valid values per sport are power or hr. Sport families: cycling, run, ski, rowing, swim, walk, strength, other.
Note: GITHUB_TOKEN is provided automatically by GitHub Actions.
- Still in Settings, click Actions → General in the left sidebar
- Scroll down to "Workflow permissions"
- Select "Read and write permissions"
- Click Save
This allows the sync workflow to commit updated data files to the repo. Without this, the workflow may fail silently on push.
- Go to your repo → Actions tab
- If prompted, enable workflows
- Click on "Auto-Sync Intervals.icu Data" workflow
- Click Run workflow → Run workflow (green button)
Wait 30-60 seconds, then check if latest.json has been updated.
If the run fails with a permission error, go back and check that workflow permissions are set to "Read and write" in Step 4.
Your data should now be accessible at:
https://raw.githubusercontent.com/[your-username]/[repo-name]/main/latest.json
https://raw.githubusercontent.com/[your-username]/[repo-name]/main/history.json
https://raw.githubusercontent.com/[your-username]/[repo-name]/main/ftp_history.json
https://raw.githubusercontent.com/[your-username]/[repo-name]/main/intervals.json
Test by opening the URLs in your browser — you should see your training data as JSON.
latest.json— current 7-day snapshot with activities, wellness, fitness metrics, and derived Section 11 valueshistory.json— longitudinal data with tiered granularity: daily (90 days), weekly (180 days), and monthly (up to 3 years). Generated automatically on first run, regenerated when outdated.intervals.json— per-interval segment data for recent structured sessions (14-day retention). Generated automatically for activities with detected interval structure.routes.json— route/terrain data for planned events with GPX/TCX attachments. Includes climb/descent detection, course character, and polyline. Generated when attachments exist, cached by attachment ID.
The sync script automatically creates and maintains ftp_history.json to track FTP changes over time. This enables Benchmark Index calculation.
{
"indoor": {
"2025-10-15": 255,
"2025-11-03": 260,
"2025-12-01": 265
},
"outdoor": {
"2025-10-15": 265,
"2025-11-03": 270,
"2025-12-01": 278
}
}- Created automatically on first run of
sync.py - New entries added only when FTP changes (not on every run)
- Indoor and outdoor FTP tracked separately
- GitHub Actions workflow commits updates automatically
The Benchmark Index measures FTP progression over 8 weeks:
Benchmark Index = (Current FTP - FTP 8 weeks ago) / FTP 8 weeks ago
| Value | Interpretation |
|---|---|
| +5% | Strong progression |
| +2% to +5% | Normal build phase gains |
| 0% to +2% | Maintenance |
| -2% to 0% | Minor regression (may be normal in recovery) |
| < -2% | Significant regression — investigate |
Note: Requires ~8 weeks of data before Benchmark Index becomes available.
Once set up, configure your AI platform using the instructions in the main README.
GitHub connector users: If your AI platform has a GitHub connector, connect your data repo directly — the AI reads latest.json, history.json, intervals.json, routes.json, and any other committed files through the connector. No URLs needed. If you commit DOSSIER.md and SECTION_11.md to the repo, the connector provides everything in one connection.
URL fetch users: Provide these URLs to your AI coach:
https://raw.githubusercontent.com/[your-username]/[repo-name]/main/latest.json
https://raw.githubusercontent.com/[your-username]/[repo-name]/main/history.json
https://raw.githubusercontent.com/[your-username]/[repo-name]/main/ftp_history.json
https://raw.githubusercontent.com/[your-username]/[repo-name]/main/intervals.json
https://raw.githubusercontent.com/[your-username]/[repo-name]/main/routes.json
latest.json has the current 7-day snapshot, history.json provides longitudinal context for trend analysis, intervals.json has per-interval detail for recent structured sessions, and routes.json has route/terrain data for events with GPX/TCX attachments.
- Check secret names match exactly:
ATHLETE_ID,INTERVALS_KEY - Secrets are case-sensitive
- This happens when generated files (like
history.json) conflict duringgit pull - Use the latest
auto-sync.ymlfrom this folder — it stages all generated files before pulling
- Verify your Intervals.icu API key is valid
- Check you have activities in the last 7 days
- Look at workflow logs for specific errors
- Ensure your
auto-sync.ymlincludesgit add ftp_history.json - Check workflow logs for git errors
- History generates automatically on first run, then regenerates when outdated
- Delete
history.jsonfrom your repo and re-run to force regeneration - Check workflow logs — history generation is non-critical and won't fail the sync
- Ensure
latest.jsonexists in repo root - If using a public repo, verify URL format (use
mainnotmaster) - For private repo access from AI platforms, see the main README troubleshooting
For general AI platform issues (data not fetching, AI fabricating metrics, connector problems), see the main README troubleshooting guide.
Change sync frequency:
Edit the cron schedule in auto-sync.yml:
- Every 15 min:
*/15 * * * * - Every hour:
0 * * * * - Every 6 hours:
0 */6 * * *
Change data range:
Edit sync.py call in workflow:
run: python sync.py --days 14Disable anonymization:
run: python sync.py --no-anonymizeBy default, the script anonymizes your data:
- Athlete ID → "REDACTED"
- Outdoor activity names → "Training Session"
Activity and event IDs are always real (opaque database keys, not PII) to enable features like coach annotations and planned-vs-actual pairing. Indoor/virtual ride names are preserved for workout identification.
For additional privacy, use a private repository and a separate GitHub account for your data repository.
| File | Purpose | Auto-created |
|---|---|---|
latest.json |
Current 7-day training data for AI consumption | Yes |
history.json |
Longitudinal data — daily (90d), weekly (180d), monthly (3y) | Yes |
intervals.json |
Per-interval segment data for recent structured sessions | Yes |
routes.json |
Route/terrain data for events with GPX/TCX attachments | When attachments exist |
ftp_history.json |
FTP progression tracking for Benchmark Index | Yes |
archive/ |
Timestamped snapshots of each sync | Yes |
The sync script checks for upstream updates using manifest.json from the Section 11 repository. When new versions are available, a GitHub Issue is created in your data repo listing the changed files. No action is needed — just watch your Issues tab.
For local setups (non-GitHub), see json-local-sync for the local update mechanism.