Summary
Add a RunkeeperPlugin source plugin that loads activity history from a Runkeeper data export. Runkeeper exports a summary CSV alongside individual GPX files per activity — the summary CSV is the primary input for Phase 1, giving a clean what-when record of every workout.
Architecture
This plugin follows the project-wide source plugin contract:
-
Download-then-display — the plugin reads only from a previously downloaded local export file. No outbound network or API calls are made at Streamlit runtime. If the data file is absent, fetch() raises FileNotFoundError with a message directing the user to obtain and place the export file.
-
Data sovereignty — the plugin has no knowledge of other sources. fetch() returns only this source's canonical DataFrame. No filtering, joining, or merging with other sources is performed here; that is the exclusive responsibility of DataBroker.
Data export
How to get: runkeeper.com → Settings → Export Data → "Export Data" button (immediate ZIP download)
Format: ZIP containing:
cardioActivities.csv — one row per activity (summary)
- Individual
.gpx files per activity (GPS tracks, not needed for Phase 1)
Key fields in cardioActivities.csv:
| Field |
Maps to |
Date (YYYY-MM-DD HH:MM:SS) |
timestamp |
Type |
sublabel (e.g. "Running", "Cycling") |
Route Name |
label |
Distance (km) |
preserve as distance_km |
Duration (HH:MM:SS) |
preserve as duration_s |
Average Pace |
preserve |
Average Speed (km/h) |
preserve |
Calories Burned |
preserve |
Average Heart Rate (bpm) |
preserve as avg_hr |
Notes |
preserve |
GPX File |
preserve as gpx_file (filename reference) |
Plugin spec
PLUGIN_TYPE: what-when
PLUGIN_ID: runkeeper
DISPLAY_NAME: Runkeeper Activities
- Config fields:
export_dir (path to the unzipped Runkeeper export directory; loads cardioActivities.csv from within it)
- Parse
Date string to Unix timestamp
- Convert
Duration (HH:MM:SS string) to integer seconds for duration_s
label → Route Name (fall back to Type if blank), category → "fitness"
Normalized output schema
timestamp int Unix timestamp of activity start
label str Route name or activity type if unnamed
sublabel str Activity type ("Running", "Cycling", etc.)
category str "fitness"
source_id str "runkeeper"
distance_km float Distance in kilometres (NaN if not recorded)
duration_s int Duration in seconds
avg_hr float Average heart rate (NaN if not recorded)
Acceptance criteria
Summary
Add a
RunkeeperPluginsource plugin that loads activity history from a Runkeeper data export. Runkeeper exports a summary CSV alongside individual GPX files per activity — the summary CSV is the primary input for Phase 1, giving a cleanwhat-whenrecord of every workout.Architecture
This plugin follows the project-wide source plugin contract:
Download-then-display — the plugin reads only from a previously downloaded local export file. No outbound network or API calls are made at Streamlit runtime. If the data file is absent,
fetch()raisesFileNotFoundErrorwith a message directing the user to obtain and place the export file.Data sovereignty — the plugin has no knowledge of other sources.
fetch()returns only this source's canonical DataFrame. No filtering, joining, or merging with other sources is performed here; that is the exclusive responsibility ofDataBroker.Data export
How to get: runkeeper.com → Settings → Export Data → "Export Data" button (immediate ZIP download)
Format: ZIP containing:
cardioActivities.csv— one row per activity (summary).gpxfiles per activity (GPS tracks, not needed for Phase 1)Key fields in
cardioActivities.csv:Date(YYYY-MM-DD HH:MM:SS)timestampTypesublabel(e.g. "Running", "Cycling")Route NamelabelDistance (km)distance_kmDuration(HH:MM:SS)duration_sAverage PaceAverage Speed (km/h)Calories BurnedAverage Heart Rate (bpm)avg_hrNotesGPX Filegpx_file(filename reference)Plugin spec
PLUGIN_TYPE:what-whenPLUGIN_ID:runkeeperDISPLAY_NAME:Runkeeper Activitiesexport_dir(path to the unzipped Runkeeper export directory; loadscardioActivities.csvfrom within it)Datestring to Unix timestampDuration(HH:MM:SS string) to integer seconds forduration_slabel→Route Name(fall back toTypeif blank),category→"fitness"Normalized output schema
Acceptance criteria
RunkeeperPluginregistered via@registerand added toload_builtin_plugins()DateandDurationfields parsed correctlylabelvalidate_schema()passes on output