TrialSchema
Format Reference · v1.1
Back to app

TrialSchema v1.1

TrialSchema is an open, portable representation of clinical-trial eligibility designed for automated patient matching. It captures the same information a clinician extracts when reading a trial protocol — what to check, where to look, and how to evaluate — in a shape that an AI agent can execute deterministically.

The primary consumer is not a human reader. It is an AI agent, matching engine, or workflow system that needs explicit trial logic, deterministic routing hints, and a stable wire format it can process end-to-end.

What to check
Each criterion names the patient-level concept and assertion polarity.
Where to look
Document types, visit order, and criterion routing direct the agent to the right record sources.
How to evaluate
Constraints encode comparisons, ranges, code sets, boolean checks, existence checks, or text fallback.
When evidence counts
Optional timing distinguishes current state, any history, and lookback windows before screening.
Which trials first
Care paths are normalized for first-pass trial filtering.
Source of truth
docs/schemas/trialschema.v1.schema.json
JSON Schema 2020-12 · $id: https://trialschema.org/v1/export.schema.json

2. Design principles

  • Agent-first. The target runtime is an AI agent or matching system, so the format makes what to check, where to look, and how to evaluate explicit.
  • Domain-neutral. Oncology, cardiology, metabolic, rare disease — the format makes no assumptions about specialty or treatment modality.
  • Standards-aligned, not standards-bound. Codings follow FHIR shape (system+code+display); units use UCUM. But every place that accepts a code also accepts plain text — end users never have to map criteria to ontologies by hand.
  • Graceful degradation. When a constraint cannot be machine-evaluated, the extractor emits {"kind": "text", "description": …}. The matcher always has the verbatim source_text as ultimate fallback.
  • Decoupled responsibilities. A criterion's clinical concept says what to check, constraint and assertion say how to evaluate it, routing says where to look, and optional timing says when evidence counts.
  • Human-in-the-loop friendly. Every criterion has an enabled toggle, a rank, an editable clarified_text, and free-text guidance.
  • Minimal surface. Every field earns its place. Extension data goes in namespaced extensions bags.

3. Export envelope

The top-level document.

{
  "format":         "trialschema",
  "format_version": "1.1",
  "generated_at":   "2026-05-21T12:00:00Z",
  "generator":      { "name": "trialschema-ui", "version": "1.1.0" },
  "routing_profile": { /* document types + default scan set + visit order */ },
  "care_path_catalog": [ /* normalized care paths */ ],
  "trial_count":    1,
  "trials":         [ /* Trial objects */ ]
}
FieldTypeNotes
formatconst "trialschema"Magic string for sniffing.
format_versionstringMAJOR.MINOR. Minor versions are additive.
generated_atdate-timeISO-8601 timestamp.
generatorobjectName + version of the producing tool.
routing_profileRoutingProfileDocument types, labels, hints, default scan set, and general agent visit order used by extraction and matching.
care_path_catalogCarePathCatalogEntry[]Optional normalized care paths used as a first-pass matching filter.
trialsTrial[]Order is preserved.

4. Primitives

Coding

FHIR-shaped reference to a concept in a terminology. Every field is optional; text alone is a valid free-text fallback.

{ "system": "http://loinc.org", "code": "2160-0", "display": "Creatinine" }
{ "text": "ECOG performance status" }             // fallback when no code is known

Recommended systems: http://loinc.org (observations), http://snomed.info/sct (conditions/procedures), http://www.nlm.nih.gov/research/umls/rxnorm (medications), http://hl7.org/fhir/sid/icd-10, http://www.genenames.org (genes).

Quantity

{ "value": 50, "unit": "mL/min", "system": "http://unitsofmeasure.org", "code": "mL/min" }

UCUM is recommended. unit is the human-readable label; code is the canonical UCUM code (e.g. "a" for years, "mo" for months, "d" for days).

PartialDate

ISO-8601 date with optional precision: "2024", "2024-06", or "2024-06-15". Empty string means unknown.

5. Trial

{
  "id":          "NCT04567890",
  "kind":        "trial",
  "enabled":     true,
  "title":       "PALOMA-3",
  "identifiers": [{ "system": "https://clinicaltrials.gov", "value": "NCT04567890" }],
  "sponsor":     { "name": "Pfizer" },
  "conditions":  [{ "system": "http://snomed.info/sct", "code": "254837009", "display": "Malignant neoplasm of breast" }],
  "interventions": [{ "type": "drug", "label": "palbociclib", "code": { "system": "…/rxnorm", "code": "1601480" } }],
  "lifecycle":   {
    "start_date":      "2013-10-07",
    "completion_date": ""
  },
  "care_path_ids": ["breast_cancer"],
  "criteria":    [ /* Criterion[] — array index === run order */ ]
}
FieldTypeNotes
idstringStable primary key. NCT id recommended.
enabledbooleanMatcher inclusion toggle, independent of recruitment status.
conditionsCoding[]SNOMED CT recommended; free-text fallback allowed.
interventionsIntervention[]{ type, label, code? }. type ∈ drug · device · procedure · biological · behavioral · radiation · diagnostic-test · other.
care_path_idsstring[]Optional normalized care paths from care_path_catalog for first-pass matching.

6. Criterion

A single patient-level eligibility rule. The shape decouples what the criterion is about (concept), how to evaluate it (constraint, assertion), where to look (routing), and when evidence counts (timing). The raw source text remains available for audit, while clarified_text can carry the more explicit agent-facing rewrite.

{
  "id":             "INC-03",
  "kind":           "inclusion",           // inclusion | exclusion
  "enabled":        true,
  "rank":           3,                       // 1..N run order

  "source_text":    "Creatinine clearance ≥ 50 mL/min within 14 days of screening",
  "clarified_text": "Creatinine clearance must be at least 50 mL/min, measured within 14 days before screening.",

  "concept": {
    "domain": "observation",           // see Concept domains below
    "code":   { "system": "http://loinc.org", "code": "2164-2", "display": "Creatinine clearance" },
    "text":   "Creatinine clearance"
  },

  "assertion":  "present",                  // present | absent | unknown
  "constraint": {
    "kind":     "comparison",
    "operator": ">=",
    "quantity": { "value": 50, "unit": "mL/min", "system": "http://unitsofmeasure.org", "code": "mL/min" }
  },

  "timing": {
    "scope": "window",
    "lookback": { "value": 14, "unit": "days", "code": "d" },
    "description": "within 14 days of screening"
  },
  "routing":  { "primary": ["core-lab", "intake-notes", "mdt-notes"], "fallback": [] },
  "guidance": "",

  "provenance": { "extracted_at": "2026-05-21T12:00:00Z", "extracted_by": "openai/gpt-…" }
}

Concept domains

High-level clinical category. Tells the matcher which kind of patient data to fetch.

demographics — age, sex, etc.
condition — diagnoses, problem list
observation — labs, vitals, scores
medication — drugs, prior therapy
procedure — surgery, intervention
adverse-event — toxicity history
genomic — mutations, biomarkers
consent — willingness, ICF
logistic — travel, language, etc.
other — anything else

Evidence timing (optional, since v1.1)

Timing tells the matcher which part of the patient's history counts as evidence, independently of assertion, constraint, and routing. Missing timing means unspecified; consumers must interpret the criterion text rather than assume current-only evidence.

ScopeMeaningLookback
currentState at screening (e.g. active infection).Forbidden
everAny history up to screening (e.g. prior myocardial infarction).Forbidden
windowEvidence within a lookback before screening.Required; positive numeric value
"timing": {
  "scope": "window",
  "lookback": { "value": 5, "unit": "years", "code": "a" },
  "description": "in de afgelopen 5 jaar"
}

scope is required. Optional description preserves the source timing phrase, including Dutch wording and boundary details. For a window, lookback.value, unit, and code are required. Unit/code pairs are hours/h, days/d, weeks/wk, months/mo, and years/a. Optional system must be http://unitsofmeasure.org. Other fields are rejected. Keep months and years in their stated units instead of converting to an assumed number of days.

All windows count back from screening; there is no anchor field. Other anchors, future intervals, minimum washouts, and mixed timelines remain in criterion text/guidance with timing omitted. A maximum lookback does not encode “at least 4 weeks since chemotherapy.” No new constraint kinds are introduced.

Use the clinical event or measurement date, not just the document date. A recent note may describe an old event; history sections remain relevant. Timing does not change assertion polarity: “no history of” uses ever with absent. A lab threshold remains in constraint while its recency belongs in timing.

Assertion

present — the patient must satisfy the constraint. absent — the patient must NOT satisfy it (e.g. "no history of"). unknown — no assertion. Combining this with kind: "exclusion" + assertion: "present" reads naturally as "patient must NOT have …".

7. Constraints (tagged union)

Every constraint is discriminated by kind. The text variant is the always-valid fallback.

comparison
{ "kind": "comparison", "operator": ">=", "quantity": { "value": 18, "unit": "years", "code": "a" } }
Operators: < · <= · = · >= · > · !=
range
{ "kind": "range", "low": { "value": 0 }, "high": { "value": 2 } }
Inclusive bounds. Either low or high may be omitted.
code-set
{ "kind": "code-set", "match": "any",
  "values": [ { "system": "http://snomed.info/sct", "code": "254837009" } ] }
match ∈ any · all · none. Patient matches if their codes intersect / contain / disjoint values.
boolean
{ "kind": "boolean", "value": true }
exists
{ "kind": "exists" }
Pure presence/absence. Combine with assertion.
text · always-valid fallback
{ "kind": "text", "description": "ECOG performance status 0 or 1" }
Use whenever the constraint cannot be safely structured. The matcher will defer to LLM judgement.

8. Routing

Routing is the schema's answer to where should the agent look? It has two layers. The top-level routing_profile defines the patient-document types available in this export, the default scan set for most criteria, and the general visit order. Each criterion's routing then marks which of those documents are primary or fallback for that specific rule. Empty arrays mean no criterion-specific preference; use routing_profile.default_scan_set in default_visit_order.

{
  "routing_profile": {
    "id": "default-clinical",
    "document_type_system": "https://trialschema.org/v1/document-types",
    "default_scan_set": ["intake-notes", "referral-letters", "mdt-notes"],
    "default_visit_order": ["intake-notes", "referral-letters", "mdt-notes", "pathology"],
    "document_types": [
      { "id": "intake-notes", "label": "Intake Notes", "hint": "Demographics, admin rules, general medical history" },
      { "id": "referral-letters", "label": "Referral Letters", "hint": "External clinical history validation" },
      { "id": "mdt-notes", "label": "Multidisciplinary Team Notes", "hint": "Team or specialty board decisions and therapeutic strategy" },
      { "id": "pathology", "label": "Pathology", "hint": "Histology, tissue biomarkers, biopsies" }
    ]
  }
}
IdLabelTypical content
intake-notesIntake notesDemographics, admin rules, general medical history.
referral-lettersReferral lettersExternal clinical history validation.
mdt-notesMultidisciplinary Team NotesMultidisciplinary team / specialty board decisions, consensus reviews, therapeutic strategy.
pathologyHistology / pathologyMicroscopic properties, tissue biomarkers, biopsies.
imagingImaging / functional testingX-ray, CT, MRI, PET, US, plus EKG, EEG, echo, spirometry.
treatment-historyTreatment historyPrior systemic therapy, medication lines, washouts, surgery.
molecular-genomicAdvanced / genomic labsSequencing, molecular profiling, liquid biopsy.
core-labCore laboratoryCBC, LFTs, GFR, electrolytes, glucose, lipids.
otherOther / soft criterionConsent, willingness, logistics — pair with guidance.

Default system URI: https://trialschema.org/v1/document-types. Profiles may add custom ids; criterion routing ids must be declared in routing_profile.document_types.

9. Care path optional

A care path is the clinical path or care domain a trial belongs to. TrialSchema uses it as a first-pass matching signal: should this trial be considered for this patient path before the agent spends work on detailed criteria?

The export-level care_path_catalog stores stable English ids and labels, while aliases preserve source values and cross-language spellings from the upload. Each trial references one or more care paths via care_path_ids. TrialSchema v1 stores these normalized references; detailed pathway phases or actions can be modeled in extensions or future versions when needed. If no care path is known, omit care_path_ids or leave it empty; the matcher can still evaluate criteria without this first-pass filter.

{
  "care_path_catalog": [
    {
      "id": "breast_cancer",
      "label": "Breast cancer",
      "aliases": ["mammacarcinoom", "breast oncology"],
      "concept": { "system": "http://snomed.info/sct", "code": "254837009" }
    }
  ],
  "trials": [{ "id": "NCT...", "kind": "trial", "enabled": true, "care_path_ids": ["breast_cancer"], "criteria": [] }]
}

10. Full example

{
  "format": "trialschema", "format_version": "1.1",
  "generated_at": "2026-05-21T12:00:00Z",
  "routing_profile": {
    "id": "default-clinical",
    "label": "Default clinical document profile",
    "document_type_system": "https://trialschema.org/v1/document-types",
    "default_scan_set": ["intake-notes", "referral-letters", "mdt-notes"],
    "default_visit_order": ["intake-notes", "referral-letters", "mdt-notes", "pathology", "imaging", "treatment-history", "molecular-genomic", "core-lab", "other"],
    "document_types": [
      { "id": "intake-notes", "label": "Intake Notes", "hint": "Demographics, admin rules, general medical history" },
      { "id": "referral-letters", "label": "Referral Letters", "hint": "External clinical history validation" },
      { "id": "mdt-notes", "label": "Multidisciplinary Team Notes", "hint": "Team or specialty board decisions and therapeutic strategy" },
      { "id": "pathology", "label": "Pathology", "hint": "Histology, tissue biomarkers, biopsies" },
      { "id": "imaging", "label": "Imaging / Functional Testing", "hint": "CT, MRI, PET, echo, EKG, spirometry" },
      { "id": "treatment-history", "label": "Treatment History", "hint": "Prior therapy, washouts, surgeries" },
      { "id": "molecular-genomic", "label": "Molecular / Genomic Labs", "hint": "Sequencing, molecular profiling, liquid biopsy" },
      { "id": "core-lab", "label": "Core Laboratory", "hint": "CBC, chemistry, renal and liver function" },
      { "id": "other", "label": "Other / Soft criterion", "hint": "Consent, willingness, logistics" }
    ]
  },
  "care_path_catalog": [
    { "id": "breast_cancer", "label": "Breast cancer", "aliases": ["mammacarcinoom"] }
  ],
  "trials": [{
    "id": "NCT04567890", "kind": "trial", "enabled": true, "title": "PALOMA-3",
    "conditions": [{ "system": "http://snomed.info/sct", "code": "254837009", "display": "Breast cancer" }],
    "lifecycle": { "start_date": "2013-10-07" },
    "care_path_ids": ["breast_cancer"],
    "criteria": [
      {
        "id": "INC-01", "kind": "inclusion", "enabled": true, "rank": 1,
        "source_text": "Age ≥ 18 years",
        "concept": { "domain": "demographics", "text": "Age", "code": { "system": "http://loinc.org", "code": "30525-0" } },
        "assertion": "present",
        "constraint": { "kind": "comparison", "operator": ">=", "quantity": { "value": 18, "unit": "years", "code": "a" } },
        "routing": { "primary": ["intake-notes"], "fallback": [] }
      },
      {
        "id": "INC-02", "kind": "inclusion", "enabled": true, "rank": 2,
        "source_text": "HER2-negative tumor",
        "concept": { "domain": "genomic", "text": "HER2", "code": { "system": "http://www.genenames.org", "code": "3430", "display": "ERBB2" } },
        "assertion": "absent",
        "constraint": { "kind": "exists" },
        "routing": { "primary": ["pathology", "molecular-genomic"], "fallback": [] }
      }
    ]
  }]
}

11. FHIR & standards alignment

TrialSchema v1 is a deliberate subset of HL7 FHIR R5 ResearchStudy with eligibility-focused additions. Every Trial-level element maps cleanly:

TrialSchema v1FHIR R5Notes
TrialResearchStudy1:1 conceptually.
id / identifiersResearchStudy.identifierPrimary id is the NCT number when present.
titleResearchStudy.title
sponsorResearchStudy.associatedParty[role=sponsor]
conditionsResearchStudy.conditionCodings (SNOMED CT recommended).
interventionsResearchStudy.focusWith type annotation.
lifecycle.start_date / completion_dateResearchStudy.periodDate precision per PartialDate.
criteria[]ResearchStudy.recruitment.eligibilityv1 inlines criteria instead of referencing a Group.
care_path_catalog / care_path_idsTrialSchema additionNormalized care-path references for first-pass matching; detailed phases can be added through extensions or future versions.
Coding / Quantity / IdentifierFHIR Coding / Quantity / IdentifierField names and shape preserved.

Other standards

  • UCUM — recommended for all unit codes (Quantity.code).
  • SNOMED CT — conditions, procedures (http://snomed.info/sct).
  • LOINC — observations, lab tests (http://loinc.org).
  • RxNorm / ATC — medications.
  • ICD-10 / ICD-11 — diagnoses.
  • HGNC — genes / molecular biomarkers.
  • OMOP CDM — concept.domain values (condition, observation, medication, procedure) align with OMOP domain ids.
  • HL7 CQL — the constraint tagged union is shaped so a CQL transpiler can map each variant to exists, comparison, or interval expressions.

12. Ingesting ClinicalTrials.gov

The TrialSchema UI accepts the CT.gov API v2 JSON shape directly. Drop a single study record, an array of studies, or a JSONL file of records into the upload box — the format is auto-detected.

What happens automatically:

  • NCT id, title, sponsor, conditions, interventions, and matching-window lifecycle dates are pulled deterministically from protocolSection — no LLM round-trip.
  • The free-text eligibilityModule.eligibilityCriteria blob is parsed into structured Inclusion / Exclusion criteria by the LLM, with best-effort LOINC / SNOMED / RxNorm code hints attached to each criterion's concept.
  • Routing is set per criterion based on its concept domain.
// CT.gov v2 → TrialSchema v1 (deterministic field map)
protocolSection.identificationModule.nctId            →  trial.id
protocolSection.identificationModule.briefTitle       →  trial.title
protocolSection.sponsorCollaboratorsModule.leadSponsor.name
                                                     →  trial.sponsor.name
protocolSection.conditionsModule.conditions[]         →  trial.conditions[].text
protocolSection.armsInterventionsModule.interventions →  trial.interventions[]
protocolSection.statusModule.startDateStruct.date     →  trial.lifecycle.start_date
protocolSection.statusModule.completionDateStruct.date
                                                     →  trial.lifecycle.completion_date
protocolSection.eligibilityModule.eligibilityCriteria →  trial.criteria[]      // LLM-structured

13. Versioning

format_version uses MAJOR.MINOR. Minor versions are strictly additive (new optional fields, new enum members marked as such). Major versions may make breaking changes; this is 1.1, adding optional criterion timing. Existing 1.0 exports remain valid against the updated schema. The major-version schema URL stays unchanged. Older strict 1.0 validators need the updated schema to accept timing; old consumers must ignore unknown optional fields.

Implementers SHOULD reject documents with an unknown format value or with a format_version whose MAJOR they do not understand. They SHOULD ignore unknown fields within a known major version.