Find motorsport track days — HPDE, time trials, open-track/lapping, autocross, and wheel-to-wheel racing — near you, from the comfort of a terminal instead of the motorsportsreg.com website.
It queries MotorsportReg's public Global Events Calendar (GEC) GraphQL API. No account, no login, no scraping.
uv tool install trackday # from PyPI
uv tool install --editable . # from a source checkoutThis puts trackday in ~/.local/bin with its dependencies in an isolated environment,
the same way uv tool installs ruff — so the command works from any directory. That
matters if you want the agent skill, which assumes a bare
trackday is runnable everywhere; trackday skill install refuses to install if it
isn't. pipx install trackday works equally well.
A project-local uv pip install -e . is fine for development, but the entry point then
exists only inside that venv.
# First run: create the config interactively (validates your postal code)
trackday setup
# ...or set values individually
trackday config set postalcode 94010
trackday config set radius_mi 100
# What's running near me in the next ~4 months?
trackday search
# Just HPDE and time trials this summer
trackday search --type hpde --type tt --from 2026-06-07 --to 2026-09-01
# Only events within 60 miles, at Sonoma, as JSON
trackday search --radius 60 --track sonoma --json
# Export a calendar file to import into Google/Apple Calendar
trackday search --type hpde --ics hpde.ics
# What kinds of events are available nearby?
trackday types
# Full detail for one event (id comes from `search --json`)
trackday show <event-id>| Bucket | Aliases you can pass | Includes (raw MSR disciplines) |
|---|---|---|
HPDE |
hpde, de |
HPDE, Driver Education |
Time Trial |
tt, time trial, timeattack |
Time Trial, Time Attack |
Open Track |
open, lapping, trackday |
Open Track, Lapping, Track Day |
Autocross |
ax, autox, autocross,solo |
Autocross/Solo, RallyCross |
Racing |
race, w2w |
Club/Pro/Endurance/Vintage/Spec racing |
Other |
other |
clinics, concours, rallies, etc. |
Membership/gift-card/test-event "noise" is filtered out by default; pass
--include-noise to keep it.
Every search shows whether each event is actually open for registration, with the closing date when there is one — an event you can't enter is rarely the one you want.
MotorsportReg's search endpoint returns a stale snapshot: measured against the live site,
its registration status was wrong for 11% of events and its registration dates for 16%,
including one that was 459 days out of date. Worse, the errors run in the direction that
matters — it reported "open" for events that had already closed. So trackday re-checks
each event against the authoritative single-event endpoint before showing it to you.
The same check catches events that have been withdrawn entirely: the search index still returns events whose detail record and public page are both gone (2 of 78 in a typical Bay Area search). Those are dropped rather than shown with a URL that 404s.
That costs one request per event, which is why it happens after filtering — only the
events you're actually going to see get checked (78 events takes ~4s cold, ~0.3s cached).
Pass --no-status to skip it, at the cost of unverified statuses and the odd dead event. In JSON output, status_verified tells you whether a
given event's status was confirmed; events that fail the check keep the search API's
value and are flagged rather than dropped.
--radius is a true great-circle limit in miles, applied locally. --max-distance is an
alias for it; if you pass both, the tighter one wins.
MotorsportReg's API ignores the radius it is sent and always returns everything
within 200 miles, so no search can reach further than that no matter what you ask for —
--radius 500 warns and behaves as --radius 200. The measurements behind that claim
are in docs/api-notes.md.
trackday ships an agent skill that teaches assistants how to drive the CLI — the JSON
workflow, the type taxonomy, the distance semantics, and the failure modes. Install it
once:
trackday skill install # -> ~/.claude/skills/trackdayIt symlinks by default, so upgrading trackday also updates the skill. Use --copy for
a standalone copy, --force to replace an existing install, --dir for a different
skills directory, and trackday skill path to print the packaged source. The skill
itself lives at src/trackday/_skill/SKILL.md.
Because the skill is user-level, it assumes trackday is on PATH everywhere — so the
install refuses unless the CLI is genuinely user-level (see Install). A
project venv only works while activated, which an agent in another directory won't have.
Use --skip-path-check to override, or --dir .claude/skills to scope the skill to one
project instead.
Run trackday setup once — it prompts for your postal code, how far you'll travel, and
how far ahead to look, checks the postal code actually geocodes, and writes
~/.config/trackday/config.toml. Until that exists (and with no --zip or .env),
searching exits 1 and tells you to run it. setup needs a terminal; in scripts and
agents use --zip or trackday config set instead.
Precedence (low → high): built-in defaults → ~/.config/trackday/config.toml
(via trackday setup / trackday config set) → a local .env → real environment
variables. Note that a .env is found by walking up from the current directory, so a
project-local .env overrides your user config while you're inside that project.
.env / env keys: TRACKDAY_POSTALCODE, TRACKDAY_RADIUS, TRACKDAY_COUNTRY,
TRACKDAY_API_URL, TRACKDAY_API_KEY. See .env.example.
No MotorsportReg account or credentials are needed. The MSR REST API's Basic auth requires an organization-admin account; this tool uses the public GraphQL API instead.
- Endpoint:
https://api-v2.motorsportreg.com/graphql, which requires anx-api-keyheader. The key is not a credential you create — it's the public client-side widget key motorsportreg.com's own calendar ships to every browser. - No key is checked into this repo. On first use, trackday scrapes the key from
MSR's official demo page (
https://assets.motorsportreg.com/gec/demo.html) and caches it at~/.config/trackday/api-key. If MSR rotates the key, the next 403 triggers a re-scrape automatically — no manual fixup needed. - To pin an explicit key instead (skipping auto-discovery), set
TRACKDAY_API_KEYortrackday config set api_key <key>. Clear it withtrackday config set api_key ''to return to auto-discovery. - ZIP → coordinates is done via the free zippopotam.us API; MSR's search takes lat/lon, not postal codes.
- Full API notes (schema, queries, working curl examples) are in
docs/api-notes.md.
- Core + CLI ← you are here
- Agent skill — done, see Use with an AI agent.
- Calendar-aware planning — extend the skill with Google Calendar / Gmail integration to check availability and plan attendance.
uv pip install -e '.[dev]'
pytest