Important
The vast majority of the content in this repository is AI-generated. Schema files, knowledge-base entries, documentation, and code have been produced by AI agents (e.g., Claude) working under human direction.
A person's name on a commit, pull request, issue, or knowledge-base entry does not mean that person authored the content themselves. It means that person guided an AI agent, which made the change on their behalf. Human contributors direct, review, and approve the work, but the content itself is written by AI.
A LinkML schema for representing Key Event and Outcome measurements, assays, and experimental protocols in the context of environmental health sciences (EHS) outcomes research.
Documentation · Schema · Examples · Artifacts
This data model provides a standardized way to capture and exchange data about airway biology assays relevant to respiratory health outcomes, including:
- Ciliary function - Beat frequency, active area, morphology
- Airway surface liquid - ASL height, periciliary layer depth, ion composition
- Mucociliary clearance - Transport rates, directionality, clearance efficiency
- Oxidative stress - ROS, lipid peroxidation, antioxidant capacity
- Ion channel function - CFTR chloride secretion, sweat chloride
- Signaling pathways - EGFR phosphorylation, downstream kinases
- Mucin biology - Goblet cells, MUC5AC/MUC5B expression
- Inflammatory markers - BALF/sputum cell counts, cytokines
- Lung function - Spirometry outcomes (FEV1, FVC)
- Gene expression - Target gene mRNA levels
- Assay-centric architecture with domain-specific assay classes using named measurement slots
- StudySubject hierarchy for describing biological systems: cell cultures, human/animal subjects, populations
- Typed protocol hierarchy: ImagingProtocol, MolecularAssayProtocol, StainingProtocol, SpirometryProtocol
- AOP Framework integration: KeyEvent and AdverseOutcomePathway classes with assay linkage
- Ontology-backed entities mapped to GO, ChEBI, CL, UO, OBI, and other biomedical ontologies
The schema can be used to:
- Validate data - Ensure your data conforms to the model
- Generate code - Create Python dataclasses, Pydantic models, JSON Schema
- Transform data - Convert between JSON, YAML, RDF, and other formats
For local development, use uv and just as the canonical entry points.
The repository may contain underlying Python, npm, and LinkML commands, but contributors
should treat the just recipes as the supported interface for routine setup, testing,
and generation tasks.
uvfor Python environment and dependency managementjustfor repository task automationnodeandnpmfor DataHarmonizer frontend builds
Install the Python dependencies managed by the repo:
just install- Run the full validation workflow:
just test - Regenerate project artifacts:
just gen-project - Regenerate schema documentation:
just gen-doc - Build the DataHarmonizer assets:
just build-dh - List all available recipes:
just --list
If you need to run a Python tool directly, prefer uv run ... so it executes inside the
managed project environment.
The kb/publications/*.yaml files are the source of truth. Two generated products
make them queryable; both are gitignored and rebuilt on demand, never hand-edited.
just build-db— buildexports/soma.duckdb, a local DuckDB database with one table per schema class.just dump-tsv— dump every table and view toexports/tsv/*.tsv.just build-db-all— both of the above.just query 'SELECT ...'— run one query; with no argument, list the relations.just generate-workbook— the pooled Excel workbook (seescripts/build_workbook.py).
Start with the measurement_full view: one row per number in the KB, already
joined to its paper, assay, exposure condition, experimental group and key event.
just query "SELECT paper_id, measurement, value, unit_label, exposure_agent_label \
FROM measurement_full WHERE measurement LIKE '%beat%'"Alongside the per-class tables, four carry what a class-per-table layout cannot:
measurement— long format, one row per number anywhere in the KB, with its unit, dispersion, central tendency, sample size, and avalue_qualifierthat preserves a recorded<0.05instead of silently turning it into0.05.link— every entity-to-entity edge, and the table to use for many-to-many slots such asfollows_protocols. An edge from a paper to one of its top-level entities hasparent_type = 'paper'and carries the source filename asparent_id, since that is thepapertable's key.term— every ontology term referenced, with its label.term_ref— each place a term is used, which is whatterm_usagecounts.
The views assay and assay_output union the 11 assay and 11 output subclasses,
so a cross-assay question does not need an 11-way UNION.
Rows are keyed on source_file, not on the cited PMID: two kb files may
legitimately cite one paper, and keying on the PMID would either abort the build
on a primary-key clash or silently merge the two files' entities. paper_id
remains on every row for grouping and display.
The DuckDB schema is derived from the installed soma-schema at build time, so a
version bump regenerates it — inspect it with just db-schema. It deliberately
differs from LinkML's own relational model (just db-schema-linkml) in three ways,
documented in scripts/soma_duckdb.py: value objects such
as QuantityValue are flattened into named columns rather than joined through a
shared table, reused children carry one parent_type/parent_id pair instead of one
nullable foreign key per possible parent, and multivalued scalars stay on the parent
row as DuckDB LIST columns instead of side tables.
- docs/ - mkdocs-managed documentation
- examples/ - Examples of using the schema
- project/ - project files (auto-generated, do not edit)
- Schema and datamodel: the soma-schema package, maintained in EHS-Data-Standards/soma
- tests/ - Python tests
There are several pre-defined command-recipes available.
They are written for the command runner just. To list all pre-defined commands, run just or just --list.
This project uses the template linkml-project-copier published as doi:10.5281/zenodo.15163584.