Use when searching for the date, venue, or location of historic or modern bodybuilding contests to populate contest_locations.json.
Searches the web for contest dates, venues, and locations, then writes results to ~/workspace/musmem/contest_locations.json.
Use when the user gives a contest name, optionally with a year or range.
"Nationals - NPC, 1995" → research that specific year (always, even if data exists)"Nationals - NPC, 1982-2025" → research that year range, skip years with existing data"Nationals - NPC" → query API for all years in DB, research only years with no existing dataWorkflow: look up years in DB → web search per year → write results (see Path A Workflow below).
Use when the user gives a year (with or without an org name).
"IFBB, 2025" → fetch listing page for IFBB in 2025, extract date+location for all contests"2025" → fetch listing pages for all orgs (IFBB, NPC, NPC Worldwide, CPA) for 2025"NPC, 2023-2025" → fetch listing pages for NPC for each year in the rangeWorkflow: fetch npcnewsonline.com listing pages → parse date+location in bulk → match to MuscleMemory contest names → write results (see Path B Workflow below).
Python scripting rule: Never use
python3 -c "..."orpython3 - <<'PYEOF'heredocs. Always write scripts to/tmp/script.pyusing the Write tool, then runpython3 /tmp/script.py.
GET https://musclememory.net/api/contests # all contests across all orgs
GET https://musclememory.net/api/contests/{year} # all contests across all orgs for a year
GET https://musclememory.net/api/org?name={ORG} # all contest names for one org (use to find exact contest name)
GET https://musclememory.net/api/contest/years?name={contest} # all years DB has results for a specific contest
Use browser User-Agent for all musclememory.net API calls (server blocks bots):
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
File: ~/workspace/musmem/contest_locations.json
[
{
"contest": "Contest Name - ORG",
"years": {
"1940": {
"date": "May 25, 1940",
"venue": "Madison Square Garden",
"location": "New York, New York, USA"
},
"1947": { "date": "", "venue": "", "location": "" }
}
}
]
date — free text, can be a range (e.g., "June 1-2, 1946"), empty string if unknownvenue — building/arena name, empty string if unknownlocation — "City, State, Country" format, empty string if unknownUse curl + Python (write script to /tmp/). Listing URLs from npcnewsonline.com:
| Org | URL |
|---|---|
| IFBB | https://contests.npcnewsonline.com/contests/{year}/ifbb |
| NPC | https://contests.npcnewsonline.com/contests/{year}/npc |
| NPC Worldwide | https://contests.npcnewsonline.com/contests/{year}/npc_worldwide |
| CPA | https://contests.npcnewsonline.com/contests/{year}/cpa |
User-Agent for curl: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Write a Python script to /tmp/parse_listing.py that parses the HTML and extracts, for each contest:
Examine the HTML structure on first use to identify the relevant tags and classes.
Apply the same normalization as musmem-contests:
IFBB Arnold Classic → Arnold Classic) - {ORG} (e.g., Arnold Classic - IFBB)contest_locations.json for an existing entrydate, venue, and location fields for each matched contest+yearList contests written, skipped (existing data), and any that could not be matched to a MuscleMemory contest name.
If the user gave the exact contest name (e.g., "Nationals - NPC"), use it directly.
If the name is ambiguous or the org is given instead:
GET /api/org?name={ORG} → pick the matching contest name from the listSpecific year given (e.g., "Nationals - NPC, 1995"):
Year range given (e.g., "1982-2025" or "1982 to present"):
GET /api/contest/years?name={contest} → get years in DBNo year given:
GET /api/contest/years?name={contest} → get all years in DBProcess sequentially — one year at a time. Use Search Tiers below.
Specific year was given AND data already exists in JSON:
All other cases:
After all targets: list what was found, what was skipped (had existing data), and what remains empty (not found after exhausting all search tiers).
Tier 1 — Org website (modern contests):
npcnewsonline.com contest listing or result page — often includes date and venue"[Contest Name] [year] [org]" schedule OR resultsTier 2 — General web search:
"[Contest Name] [year]" bodybuilding date location"[Contest Name] [year]" bodybuilding "[org]"Tier 3 — Declare unknown:
| Mistake | Fix |
|---|---|
| Searching year-by-year via API | Use /api/contest/years to get all years at once |
| Overwriting existing data without confirmation | Only overwrite when user gave a specific year AND confirmed |
| Invalid JSON | Validate structure before writing — array at top level, no trailing commas |
| Stopping after one failed search | Try all tiers before declaring unknown |
| Processing entries in parallel | One year at a time — no parallel agents |
| Writing location as "City, State" | Always include country: "City, State, USA" |
Using python3 -c or heredoc for Python | Write script to /tmp/script.py, run python3 /tmp/script.py |