Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Query ClinicalTrials.gov via APIv2. Use when you want to search for trials by condition, drug, location, status, or phase; retrieve trial details by NCT ID; check eligibility/inclusion criteria; count trials across conditions or time periods; identify a sponsor's trial portfolio; find recruiting trials for patient matching.
.claude/skills/mkurman-clinical-trials-database/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 343% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 219% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 160% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 237% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 253% | 0% |
uv: Read the uv skill and follow its Setup instructions to ensureuv is installed and on PATH.
this skill directory then (1) prominently notify the user to check the terms at https://clinicaltrials.gov/, then (2) create the file recording the notification text and timestamp.
Access worldwide clinical trial data from ClinicalTrials.gov via the REST API v2. The CLI script at scripts/clinical_trials_api.py wraps the API with dedicated flags for common filters (phase, age group, status, intervention, sponsor, etc.) so you rarely need to construct raw queries.
database rather than accessing the database directly. The scripts automatically enforce the required rate limit gracefully.
--fields — trial JSON records can be very large; restrictto the data points you need.
--count-total first — check result volume before fetching allrecords.
--limit with --page-token toiterate.
explicitly asked to verify detailed eligibility.
output.
Trial JSON records can be very large. Always use the --fields parameter to restrict the response to only the data points you need. After writing to file, read only the fields you need rather than the entire file.
> !TIP] Use references/studies_schema.md to identify exact field paths for > --fields.
API responses contain a list of studies (usually in a studies[] array). Each study is split into protocolSection and optional resultsSection.
> !Tip] Use the shorthand aliases below with the --fields parameter to > request specific data and keep responses small.
totalCount — Total studies matching query (integer)studies[] — Array of study objectsnextPageToken — cursor string for paginationprotocolSection.identificationModule.nctId (NCTId) — Unique trial IDprotocolSection.identificationModule.briefTitle (BriefTitle) — Shorttitle
protocolSection.statusModule.overallStatus (OverallStatus) —Recruitment status
protocolSection.descriptionModule.briefSummary (BriefSummary) —Short description
protocolSection.armsInterventionsModule.interventions(ArmsInterventionsModule)
protocolSection.eligibilityModule.eligibilityCriteria(EligibilityCriteria) — Inclusion/Exclusion
protocolSection.eligibilityModule.stdAges (StdAge) — CHILD, ADULT,etc.
Consult references/studies_schema.md for full paths (Locations, Outcomes, Results) and common --fields recipes.
Use for: finding trials by disease, drug, phase, status, age group, or any combination of these filters.
bashuv run scripts/clinical_trials_api.py search \ --condition "<disease>" \ --intervention "<drug_or_treatment>" \ --status "<status>" \ --phase "<phase>" \ --age-group "<age_group>" \ --study-type "<study_type>" \ --sponsor "<sponsor_name>" \ --has-results \ --sort "<field>:<asc|desc>" \ --fields "<fields>" \ --limit <N> \ --count-total \ --page-token "<token>" \ --output /tmp/search_results.json
All flags are optional and combine via AND logic.
Flag reference:
--condition — Disease or condition to search for (e.g. "cysticfibrosis").
--intervention — Drug, device, or treatment name (e.g. "pembrolizumab").--status — Recruitment status filter. Values: RECRUITING, COMPLETED,NOT_YET_RECRUITING, ACTIVE_NOT_RECRUITING, ENROLLING_BY_INVITATION, TERMINATED, SUSPENDED, WITHDRAWN.
--phase — Trial phase filter. Values: PHASE1, PHASE2, PHASE3, PHASE4,EARLY_PHASE1, NA.
--age-group — Patient age group filter. Values: CHILD (0–17), ADULT(18–64), OLDER_ADULT (65+).
--study-type — Type of study. Values: INTERVENTIONAL, OBSERVATIONAL,EXPANDED_ACCESS.
--sponsor — Lead sponsor or institution name (e.g. "National CancerInstitute").
--has-results — Boolean flag (no value needed). When present, filters forstudies that have results available on ClinicalTrials.gov.
--sort — Sort order as FieldName:asc or FieldName:desc. Common fields:LastUpdatePostDate, EnrollmentCount, StudyFirstPostDate, StartDate.
--fields — Comma-separated list of JSON field names to include in theresponse. Use this to keep responses small (e.g. "NCTId,BriefTitle,OverallStatus,Phase"). See references/studies_schema.md for available field paths.
--limit — Maximum number of studies to return per request (1–1000, default10).
--count-total — Boolean flag (no value needed). When present, the responseincludes a totalCount field showing the total number of matching studies across all pages.
--page-token — An opaque cursor string used to fetch the next page ofresults. Obtain this value from the nextPageToken field in a previous search response. Do not construct this string yourself; always copy it verbatim from the API response. See the Pagination section below.
--advanced — Raw Essie filter expression for structured queries beyond thededicated flags (e.g. "AREA[LocationCountry]United States"). Combined with other flags via AND. See references/clinical_trials_api.md for syntax.
--output — (Required) File path where the JSON response is written.Example — actively recruiting Phase 3 pediatric cystic fibrosis trials:
bashuv run scripts/clinical_trials_api.py search \ --condition "cystic fibrosis" \ --status RECRUITING \ --phase PHASE3 \ --age-group CHILD \ --fields "NCTId,BriefTitle,OverallStatus,Phase" \ --limit 10 \ --output /tmp/cf_trials.json
Example — recruiting atezolizumab trials for esophageal cancer:
bashuv run scripts/clinical_trials_api.py search \ --condition "esophageal cancer" \ --intervention "Atezolizumab" \ --status RECRUITING \ --fields "NCTId,BriefTitle,Phase" \ --limit 10 \ --output /tmp/atezolizumab_trials.json
Use for: fetching full details of a specific trial when you already have the NCT identifier.
bashuv run scripts/clinical_trials_api.py get-study \ <nct_id> [--fields "<fields>"] \ --output /tmp/study.json
Returns a useful default set of fields if --fields is omitted: NCTId,BriefTitle,OverallStatus,Phase,BriefSummary, ConditionsModule,ArmsInterventionsModule,EligibilityModule
Structure of the default response:
json{ "protocolSection": { "identificationModule": { "nctId": "NCT00000000", "briefTitle": "Study Title" }, "statusModule": { "overallStatus": "RECRUITING" }, "descriptionModule": { "briefSummary": "This study is about..." }, "conditionsModule": { "conditions": [ "Condition Name" ] }, "armsInterventionsModule": { "interventions": [ { "type": "DRUG", "name": "Drug Name" } ] }, "eligibilityModule": { "eligibilityCriteria": "Inclusion:\n- ...", "stdAges": [ "ADULT" ] } } }
Use for: pulling inclusion/exclusion rules, age ranges, and sex requirements for patient-matching tasks.
bashuv run scripts/clinical_trials_api.py \ get-eligibility <nct_id> \ --output /tmp/eligibility.json
Shortcut that returns title and the full eligibility module (inclusion/exclusion criteria, age range, sex).
Example — inclusion criteria for NCT04886804:
bashuv run scripts/clinical_trials_api.py \ get-eligibility NCT04886804 \ --output /tmp/eligibility_NCT04886804.json
Use for: exploring the trial landscape — checking how many trials exist for a condition, phase, or status before fetching full records.
bashuv run scripts/clinical_trials_api.py count \ --condition "<disease>" \ [--status "<status>"] [--phase "<phase>"] ... \ --output /tmp/count.json
Returns only the total count of clinical trials matching the search criteria without fetching study records. Accepts the same filter flags as search.
Use for: narrowing trials to a specific country, state, or city.
Use --advanced with AREA[LocationCountry] or AREA[LocationCity] to restrict results by geography:
bashuv run scripts/clinical_trials_api.py search \ --condition "cystic fibrosis" \ --status RECRUITING \ --advanced "AREA[LocationCity]New York" \ --fields "NCTId,BriefTitle" \ --limit 20 \ --output /tmp/nyc_cf_trials.json
Use for: identifying a sponsor's or institution's trial portfolio.
Use --sponsor to find trials run by a specific institution or company:
bashuv run scripts/clinical_trials_api.py search \ --sponsor "National Cancer Institute" \ --fields "NCTId,BriefTitle,LeadSponsorName" \ --limit 20 \ --output /tmp/nci_trials.json
Use for: complex queries that layer multiple filters (condition and drug and phase and geography and sponsor, etc.).
All flags combine via AND, so you can layer conditions, interventions, status, phase, geography, and sponsor in a single query:
bashuv run scripts/clinical_trials_api.py search \ --condition "pancreatic cancer" \ --intervention "immunotherapy" \ --status RECRUITING \ --phase PHASE3 \ --advanced "AREA[LocationCountry]United States" \ --fields "NCTId,BriefTitle,Phase,LeadSponsorName" \ --limit 20 \ --output /tmp/panc_trials.json
Use for: uncommon endpoints or parameter combinations not covered by the dedicated flags.
bashuv run scripts/clinical_trials_api.py raw-query \ --endpoint <path> \ --params '<json_dict>' \ --output /tmp/raw_result.json
When results exceed --limit, the response includes a nextPageToken. Pass it with --page-token to fetch the next page:
bashuv run scripts/clinical_trials_api.py search \ --condition "breast cancer" \ --status RECRUITING \ --limit 50 --count-total \ --output /tmp/breast_cancer_p1.json uv run scripts/clinical_trials_api.py search \ --condition "breast cancer" \ --status RECRUITING \ --limit 50 --page-token "CAo=" \ --output /tmp/breast_cancer_p2.json
For complex filtering beyond the dedicated flags, use --advanced with an Essie expression.
What is an Essie Expression? Essie is the search engine powering ClinicalTrials.gov. An Essie expression is a structured query that targets specific fields (e.g., country, phase) rather than doing general keyword searches.
AREA[Field]Value: Targets a specific field.AREA[LocationCountry]United StatesAREA[Phase]PHASE3AND, OR, NOT.RANGE[min, max]: For numeric/date fields (e.g. RANGE[500, MAX]).See references/clinical_trials_api.md for syntax and available fields.
It is combined with other flags via AND:
bashuv run scripts/clinical_trials_api.py search \ --condition "diabetes" \ --advanced "AREA[LocationCountry]United States \ AND AREA[EnrollmentCount]RANGE[500, MAX]" \ --fields "NCTId,BriefTitle,EnrollmentCount" \ --output /tmp/diabetes_us_large.json
references/clinical_trials_api.md
--fields recipes: references/studies_schema.md| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 16,005 | 6,743 | -58% | 1 | 1 | 0% | 3,070 | 3,640 | +19% | 0 | 0 | — |
case-11 | fail→fail | 5,376 | 6,431 | +20% | 1 | 1 | 0% | 249 | 3,740 | +1402% | 0 | 0 | — |
case-02 | fail→fail | 15,363 | 5,298 | -66% | 1 | 1 | 0% | 2,639 | 3,683 | +40% | 0 | 0 | — |
case-03 | fail→fail | 12,382 | 24,880 | +101% | 1 | 1 | 0% | 2,267 | 3,741 | +65% | 0 | 0 | — |
case-04 | pass→pass | 11,183 | 23,341 | +109% | 1 | 1 | 0% | 2,247 | 7,937 | +253% | 0 | 0 | — |
case-05 | pass→pass | 11,909 | 20,395 | +71% | 1 | 1 | 0% | 1,922 | 6,682 | +248% | 0 | 0 | — |
case-10 | fail→fail | 13,687 | 6,462 | -53% | 1 | 1 | 0% | 2,368 | 3,880 | +64% | 0 | 0 | — |
case-06 | pass→pass | 2,972 | 4,400 | +48% | 1 | 1 | 0% | 498 | 4,057 | +715% | 0 | 0 | — |
case-07 | fail→pass | 5,830 | 2,486 | -57% | 1 | 1 | 0% | 870 | 3,855 | +343% | 0 | 0 | — |
case-08 | fail→fail | 8,004 | 6,477 | -19% | 1 | 1 | 0% | 1,367 | 3,745 | +174% | 0 | 0 | — |
case-09 | fail→fail | 18,335 | 5,433 | -70% | 1 | 1 | 0% | 1,454 | 3,770 | +159% | 0 | 0 | — |
case-12 | fail→fail | 5,210 | 5,898 | +13% | 1 | 1 | 0% | 169 | 3,799 | +2148% | 0 | 0 | — |
case-13 | fail→fail | 9,213 | 5,296 | -43% | 1 | 1 | 0% | 1,738 | 3,653 | +110% | 0 | 0 | — |
case-14 | fail→pass | 9,422 | 13,713 | +46% | 1 | 1 | 0% | 1,639 | 5,222 | +219% | 0 | 0 | — |
case-15 | fail→fail | 13,421 | 54,105 | +303% | 1 | 1 | 0% | 2,412 | 3,914 | +62% | 0 | 0 | — |
case-16 | fail→pass | 11,312 | 11,835 | +5% | 1 | 1 | 0% | 1,887 | 4,898 | +160% | 0 | 0 | — |
case-17 | fail→fail | 7,240 | 11,692 | +61% | 1 | 1 | 0% | 1,249 | 4,570 | +266% | 0 | 0 | — |
case-18 | fail→fail | 17,203 | 7,508 | -56% | 1 | 1 | 0% | 2,899 | 3,728 | +29% | 0 | 0 | — |
case-19 | fail→fail | 11,431 | 8,437 | -26% | 1 | 1 | 0% | 1,049 | 3,999 | +281% | 0 | 0 | — |
case-20 | fail→pass | 6,616 | 5,590 | -16% | 1 | 1 | 0% | 1,281 | 4,323 | +237% | 0 | 0 | — |
case-21 | fail→fail | 15,229 | 6,781 | -55% | 1 | 1 | 0% | 2,923 | 3,744 | +28% | 0 | 0 | — |
case-22 | fail→fail | 16,627 | 6,990 | -58% | 1 | 1 | 0% | 2,941 | 3,853 | +31% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 8 counted toward the lift figure. The other 14 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +18 percentage points is the difference between those two pass rates over the 8 comparable cases. 3 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.