Schema Valid Is Not Exchange Ready
Clinical phenotype data can satisfy JSON syntax while omitting ontology resources, repeating assertions, or marking the same term both observed and excluded.
phenopacketlint checks packet identity and metadata, resource references, ontology identifier shape, labels, duplicates, and observed-versus-excluded contradictions, then returns field-level errors, warnings, and a quality score.
Make Every Finding Actionable
Every finding carries a path back into the packet, and the same engine runs through the CLI, the API, the workbench, the Docker image, and the tests. No patient payload leaves the local process.
The Demo
The committed rare-disease fixture has three phenotype features, two observed and one excluded, and passes every semantic check with a quality score of 100. It's an exchange-readiness layer, not a replacement for the official protobuf validator, terminology services, consent review, or clinical interpretation.
A Clean Demo Proves Nothing, So I Broke It Nine Ways
The contradiction check had a contradiction of its own. The excluded field was read with a plain bool(...), and in Python bool("false") is True, because any non-empty string is truthy. A producer that serialized the flag as the string "false" had its meaning silently inverted, so two entries that both meant "not excluded" were reported as contradicting each other, and the observed and excluded counts came out backwards. It now interprets the common string spellings explicitly instead of trusting truthiness.
Auditing this page, I hit the bigger problem: the only example scored 100, so nothing in the repo ever showed the linter catching anything. There's now a planted-defect corpus that starts from the clean packet and breaks exactly one thing per case: a missing packet id, missing metadata resources, an identifier that isn't in PREFIX:LOCAL form, a genuine observed-and-excluded contradiction, that same contradiction string-encoded, an ontology prefix no resource declares, a missing label, a duplicate entry, and a missing subject id.
9 of 9 detected, and the clean packet still fires nothing: zero errors, zero warnings, score 100. That second half is the one I watch. A linter that flags a good file teaches people to ignore it. Both properties are held by tests, and CI runs them on Python 3.10 through 3.13 before building the image and checking the workbench loads.
Standards Basis
The checks target the GA4GH Phenopacket Schema v2 exchange model for computable phenotype and disease information. Read the GA4GH Phenopackets v2 specification.
Try It
No dependencies, and nothing leaves the machine:
git clone https://github.com/ahmeddoghri/phenopacketlint && cd phenopacketlint
pip install -e .
phenopacketlint demo # the clean packet: score 100
python -m phenopacketlint.planted # 9 planted defects, 9 caught
phenopacketlint analyze your_packet.json
phenopacketlint serve # workbench on :8090