Quantified Self
Like many worthwhile endeavors, I originally started doing this out of spite: if everyone is surveilling me & profiting from my data, shouldnβt I also get to derive some value from it? Or at the very least: can I get a copy?
In the past I had written some #python scrapers and done basic processing with my limited #programming ability, like calculating stats from my Strava #cycling logs. But now that Claude Code can one-shot this type of task, I got a little more ambitious with this experiment.
Iβm also interested in the idea of agent visibility - if I give an agent tools to use this data, what connections can an #LLM find?
Personal Data
The flow of personal data from services, to private git repos, and then ultimately used in downstream tools.
Data Collection
flowchart LR
subgraph sources["Data Sources"]
HA["π Home Assistant"]
G["π Garmin"]
ST["π΄ Strava"]
SA["π΄ Sleep as Android"]
end
subgraph repos["Private Repos"]
R[("JSON Format")]
end
subgraph downstream["Tools"]
MCP["π€ Brad MCP"]
RPT["π Reports"]
WEB["π brad.quest"]
end
subgraph audience["Audience"]
AG["Agents"]
ME["Me"]
PL["Public"]
end
HA & G & ST & SA --> R
R --> MCP & WEB & RPT
MCP --> AG & ME
WEB --> PL
RPT --> ME
For each data source, I run a Python script using Forgejo Actions on a regular schedule. If new data is found, itβs committed back into the repo and the script calculates out additional metrics & enrichment.
Data Sources
| Source | Type | MCP Domain |
|---|---|---|
| Last.fm | Cloud | music |
| Withings | Cloud | weight |
| Sleep as Android | Calendar | sleep |
| Strava | Cloud | fitness |
| Steam | Cloud | gaming |
| RetroAchievements | Cloud | gaming |
| Letterboxd | Cloud | films |
| BoardGameGeek | Cloud | boardgames |
| Home Assistant | Self-hosted | home |
| Nutrition | Agent | nutrition |
| iNaturalist | Cloud | nature |
Repo Structure
Each source has its own private repo. All repos follow the same general structure β a data/ folder with daily JSON files and an index.json for quick lookups. Using music scrobbles from LastFM as an example:
scrobbles/
βββ data/
βββ index.json # aggregate stats + list of all daily file dates
βββ summary.json # archive completeness, last fetch timestamp
βββ fetch_state.json # incremental sync progress
βββ library_artists.json # all artists with total play counts
βββ loved_tracks.json
βββ top/
β βββ artists/
β β βββ 7day.json
β β βββ 1month.json
β β βββ overall.json
β βββ albums/
β βββ tracks/
βββ charts/ # weekly charts (historical backfill)
β βββ artists/
β β βββ 2005-W08.json
β β βββ 2026-W05.json
β βββ albums/
β βββ tracks/
βββ scrobbles/ # one file per day with listening activity
βββ 2005-05-24.json
βββ 2005-05-25.json
βββ 2026-02-04.json
JSON Format
Data is aggregated into a consistent JSON format. For example, daily files are named YYYY-MM-DD.json. A scrobble entry looks like:
{
"date": "2026-02-04",
"scrobble_count": 42,
"scrobbles": [
{
"timestamp": 1770175192,
"datetime": "2026-02-04T03:19:52+00:00",
"track": "The Paradox",
"artist": "At the Gates",
"album": "The Nightmare of Being",
"image": "https://lastfm.freetls.fastly.net/...",
"mbid": "6671f0ea-dd8b-407e-a5aa-9de39edcf68a",
"loved": false
}
]
}
Personal Tools
Downstream of that data collection, Iβve started building personal tooling that incorporates it.
Bands in Town
We are lucky in the #bayarea to have the long-running JRL List, which conveniently publishes itβs DIY show listings in plaintext.
I have a script that simply scrapes the list and fuzzy matches against artists from my listening history to create a web view and a calendar feed.
Daily Email
A very obvious thing to do. I get a basic morning summary of health, sleep, and top media for the week alongside my upcoming calendar & tasks. This is just a script that runs as an action.
MCP
See Brad MCP
brad.quest
This site's pages for Listening, Map, and Now pages are all derived from my personal data.