Skip to main content

CDC WONDER query CLI — explore, build, and refine public health data queries

Project description

pulse

CDC WONDER public health query CLI — explore datasets, run bundled queries, and use Claude to build and refine custom XML queries for public health data that Americans should care about.

What is this?

CDC WONDER (Wide-ranging ONline Data for Epidemiologic Research) is the government's primary interface for public health statistics: drug overdose deaths, maternal mortality, birth rates, COVID deaths by race, suicide trends, vaccine adverse events, and much more. Its XML API is powerful but opaque.

pulse makes it usable:

  • Explore all datasets with clear descriptions of what they cover and when
  • Search by topic to find the right dataset or a working example query
  • Run bundled, validated XML queries directly against the CDC API
  • Build new queries from natural language using Claude
  • Refine existing queries with conversational feedback

Setup

# Install (requires Python 3.12+)
uv sync

# For build/query/refine/compare/chat commands, set your Anthropic API key:
export ANTHROPIC_API_KEY=sk-ant-...
# or put it in a .env file:
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env

LLM provider

pulse defaults to Anthropic Claude but can also run against an Azure OpenAI Foundry deployment (e.g. GPT-5.4). Select the provider with LLM_PROVIDER (defaults to anthropic):

# Anthropic (default) — needs ANTHROPIC_API_KEY as above

# Azure OpenAI Foundry
export LLM_PROVIDER=azure_openai
export AZURE_OPENAI_API_KEY=...
export AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com
export AZURE_OPENAI_DEPLOYMENT=<your-gpt-5.4-deployment-name>
export AZURE_OPENAI_API_VERSION=<api-version-your-resource-supports>

All four AZURE_OPENAI_* variables are required when LLM_PROVIDER=azure_openai; pulse will tell you which ones are missing. These can also go in a .env file alongside ANTHROPIC_API_KEY.

If the LLM endpoint isn't directly reachable — e.g. an Azure OpenAI resource with public network access disabled, requiring a private endpoint — bridge the connection through a proxy with LLM_HTTP_PROXY. Applies to both providers, and supports http://, https://, socks5://, and socks5h:// (DNS resolved through the proxy):

export LLM_HTTP_PROXY=socks5h://user:pass@host:port

Commands

pulse datasets — what's available

pulse datasets                    # all datasets
pulse datasets --topic Mortality  # filter by topic
pulse datasets --json             # JSON output

Shows all 26+ CDC WONDER datasets with: topic, year range, what the data covers, number of bundled example queries, and whether age-adjusted rates are available.

Topics: Mortality · Infant Mortality · Natality · Environment · Vaccine Safety · Infectious Disease

pulse info <ID> — deep dive on a dataset

pulse info D176    # Provisional Mortality (2018–present)
pulse info D66     # Natality / birth data
pulse info D8      # VAERS vaccine adverse events

Shows: subject description, available measures, key grouping dimensions, and all bundled example queries for that dataset.

pulse search "<topic>" — find what you need

pulse search "opioid overdose deaths by state"
pulse search "maternal mortality by race"
pulse search "birth rates 2010 to 2020"
pulse search "tick-borne disease cases" --queries   # queries only
pulse search "recent COVID deaths" --datasets       # datasets only

pulse list-queries — all bundled example queries

pulse list-queries
pulse list-queries --dataset D176   # filter by dataset

23 working XML queries covering: drug/opioid/fentanyl deaths, maternal mortality, births, COVID deaths by race, suicide, tick-borne diseases, racial mortality gap, infant mortality, heart disease vs. cancer, and more.

pulse run <query> — execute a query

# Run a bundled query by filename (no path needed)
pulse run drug-deaths-by-year-2018-2024-req.xml

# Output formats
pulse run opioid-overdose-deaths-2018-2024-req.xml -f csv
pulse run mortality-by-year-cause-2021-2024-req.xml -f json
pulse run births-by-year-2007-2024-req.xml -f table -o births.csv

# Run your own query file
pulse run /path/to/my-query.xml

Hits the live CDC WONDER API. No login required; CDC requires a ~2-minute cooldown between queries.

pulse build "<description>" — build a query with Claude

# Requires ANTHROPIC_API_KEY
pulse build "drug overdose deaths by state and year 2018-2023"
pulse build "maternal mortality by race, 2018-2023" -o maternal-race.xml
pulse build "birth rates by age of mother 2010 to 2024" --no-suggest

Suggests closest existing queries first, then calls Claude to build a new XML query. The LLM selects the right dataset and generates overrides merged onto a validated base template.

pulse query "<description>" — build and run in one step

pulse query "fentanyl deaths by state 2020-2024" -f csv
pulse query "infant mortality by race 2018-2023" --save-xml infant-race.xml

pulse refine <file> "<feedback>" — iterate on a query

pulse refine opioid-overdose-deaths-2018-2024-req.xml "break it down by state"
pulse refine drug-deaths-by-year-2018-2024-req.xml "add sex breakdown" -o drug-sex.xml
pulse refine drug-deaths-by-year-2018-2024-req.xml "show monthly not yearly" --run -f csv

Testing

uv run pytest                  # unit tests only — fast, no network (default)
uv run pytest -m integration   # + integration tests (see below)

Unit tests cover catalog/matcher lookups, XML template merging (including the CDC WONDER radio-button-trap regression), AAR constraints, provider selection, and the offline-network-free CLI commands.

Integration tests (tests/integration/) are excluded by default and split into two kinds:

  • test_socks_proxy_integration.py — always runs. Spins up a local SOCKS5 relay and a local mock LLM HTTP server, so it genuinely exercises LLM_HTTP_PROXY end-to-end (real SOCKS handshake, real HTTP request/response) without needing real Azure/Anthropic credentials.
  • test_llm_provider_live.py — hits whatever ANTHROPIC_API_KEY / LLM_PROVIDER=azure_openai + AZURE_OPENAI_* / LLM_HTTP_PROXY you actually have configured. Skips if credentials aren't set; also skips (rather than fails) if the provider is reachable but blocked at the network layer (e.g. an Azure OpenAI resource with public access disabled and no working proxy) — that's an environment gap, not a code defect.

Bundled Datasets (with base templates)

ID Subject Years
D176 Provisional mortality — opioids, COVID, suicide, heart disease 2018–present
D157 Final mortality, single race (MCD+UCD) 2018–2023
D158 Underlying cause of death, single race — maternal mortality 2018–2023
D77 Multiple cause of death — drug deaths (historical) 1999–2020
D76 Underlying cause of death — suicide, cancer (historical) 1999–2020
D141 MCD with US-Mexico border regions 1999–2020
D140 Compressed mortality ICD-10 1999–2016
D16 Compressed mortality ICD-9 1979–1998
D74 Compressed mortality ICD-8 1968–1978
D69 Linked birth/infant death records 2007–2023
D159 Linked birth/infant death, expanded race 2017–2023
D31/D18/D23 Linked birth/infant death (historical) 1995–2006
D66 Natality — birth rates, birth outcomes 2007–2024
D149 Natality, expanded race detail 2016–2024
D192 Provisional natality (monthly) 2023–present
D27/D10 Natality (historical) 1995–2006
D8 VAERS vaccine adverse events 1990–present
D104 Heat wave days by county 1981–2010
D60/D80/D81 NLDAS temperature, sunlight, precipitation 1979–2011
D73 PM2.5 fine particulate matter 2003–2011
D61 MODIS land surface temperature 2003–2008

Public Health Questions You Can Answer

  • How did opioid overdose deaths trend from 1999 to today, broken down by drug type?
  • What is the racial gap in COVID-19 mortality?
  • How does maternal mortality differ by race and state?
  • Which states have the highest suicide rates by sex?
  • How have birth rates changed by age of mother since 1995?
  • Are tick-borne disease cases increasing?
  • How do PM2.5 air quality levels correlate with where people live?
  • What are the most common adverse events reported after COVID vaccines?

Releasing

Releases are cut by pushing a tag. publish.yml (single workflow, one run per tag) handles the rest as three sequential jobs:

  1. Bump version in pyproject.toml, commit it.
  2. git tag vX.Y.Z && git push origin vX.Y.Z
  3. build builds the sdist/wheel, failing fast if the tag doesn't match pyproject.toml's version.
  4. release (needs build) creates the GitHub Release with the built artifacts attached — the source of truth for what shipped.
  5. publish (needs release) publishes those same artifacts to PyPI (pulse-code) via trusted publishing (OIDC) against the prod environment — no API tokens stored in the repo.

The needs: chain means a failure at any step blocks everything after it — e.g. a PyPI hiccup can't leave a GitHub Release around for a package that isn't actually installable. If the publish job fails after release succeeds, use "Re-run failed jobs" on that workflow run rather than re-tagging. PyPI publishing is immutable: once a version is published it can't be re-uploaded, so a bad release means bumping to a new version.

Based On

Built using fartbagxp/health as reference — a comprehensive collection of CDC data pipelines and the CDC WONDER XML API client and LLM query builder this tool builds on.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pulse_code-1.0.1.tar.gz (74.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pulse_code-1.0.1-py3-none-any.whl (111.6 kB view details)

Uploaded Python 3

File details

Details for the file pulse_code-1.0.1.tar.gz.

File metadata

  • Download URL: pulse_code-1.0.1.tar.gz
  • Upload date:
  • Size: 74.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pulse_code-1.0.1.tar.gz
Algorithm Hash digest
SHA256 af252854a8abfc81c9491899b4496913f811c59b5f39ff8088d2b12577b451dc
MD5 010e0222e6aa8e8bbb9036ff48277062
BLAKE2b-256 9c5ed36ec672517e09e066ceccc2be7e6f5b711d6a0e7be0a4a6577b1c3ffc27

See more details on using hashes here.

Provenance

The following attestation bundles were made for pulse_code-1.0.1.tar.gz:

Publisher: publish.yml on fartbagxp/pulse-code

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pulse_code-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: pulse_code-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 111.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pulse_code-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 863e9672eac609a4a6092b126035bdf940f9faa21769e20b1c0d396af101bf6e
MD5 2d48099eb694a8d6f2cd51b0c15606da
BLAKE2b-256 2ad38894ffef2c0a9fe6f0929a58e2947bf98aa09a21b8bfa92dac7a6a7939f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for pulse_code-1.0.1-py3-none-any.whl:

Publisher: publish.yml on fartbagxp/pulse-code

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page