Deterministic, receipt-bearing verifier for biomedical claims — the trust layer beneath biomedical AI
Project description
biosingularity
The substrate determines the ceiling. This is the trust layer beneath biomedical AI.
A provenance & groundedness verifier for biomedical evidence chains. Give it a claim, a DOI, or a reference list, and it returns a verdict — grounded / unsupported / contradicted / built-on-retracted — with the receipt every time.
It does not try to be another evidence-aggregation platform (Causaly, the free Open Targets) or another benchmark (CZI's Open Problems, Arc's Virtual Cell Challenge). It is the connective trust tissue those tools lack: is this statement true, and where exactly does it come from?
v1 (this repo) — the smallest useful slice
Audit a reference list for retracted and unverifiable sources against PubMed. Crisp ground truth, real pain (systematic reviews routinely, unwittingly cite retracted work), demonstrably correct.
# zero pip installs needed — the audit runtime is stdlib-only
PYTHONPATH=src python -m biosingularity audit examples/sample.bib
# GROUND a whole free-text answer in ONE call — decompose -> verify every part -> one verdict + pass/review/reject
PYTHONPATH=src python -m biosingularity ground \
"APP is linked to Alzheimer's disease (10.1038/nature04533), and warfarin with ibuprofen is safe."
# -> 🔴 REJECT: retracted citation + a MAJOR interaction caught; the immunity-system call for biomedical AI
# audit specific DOIs, drugs (ChEMBL), and trials (ClinicalTrials.gov)
PYTHONPATH=src python -m biosingularity audit --doi 10.1038/nature04533
PYTHONPATH=src python -m biosingularity audit examples/sample.bib \
--drug aducanumab --drug cerivastatin --nct NCT02477800
PYTHONPATH=src python -m biosingularity audit examples/sample.bib --json
# persist findings into the substrate (needs psycopg + a Postgres at BIOSINGULARITY_DATABASE_URL)
PYTHONPATH=src python -m biosingularity audit examples/sample.bib --persist
# resolve offline against a local OpenAlex snapshot (no API; set the path)
export BIOSINGULARITY_OPENALEX_DUCKDB=/path/to/openalex.duckdb
PYTHONPATH=src python -m biosingularity audit examples/sample.bib --source openalex
# verify a claim against a paper's PMC full text (needs the crosswalk loaded — see below)
PYTHONPATH=src python -m biosingularity verify-claim --doi 10.1186/s40478-014-0135-5 \
"the amyloid hypothesis has driven drug development strategies for Alzheimer's disease"
# add an LLM entailment judgment over the retrieved passages (opt-in, paid API call)
export ANTHROPIC_API_KEY=sk-ant-... # judge model: BIOSINGULARITY_JUDGE_MODEL (default claude-opus-4-8)
PYTHONPATH=src python -m biosingularity verify-claim --judge --doi 10.1186/s40478-014-0135-5 \
"the amyloid hypothesis has driven drug development strategies for Alzheimer's disease"
# serve the web report page
PYTHONPATH=src python -m biosingularity.server --port 8765
# MCP server — let ANY agent (Claude Desktop, Claude Science, …) ground its claims by calling the verifiers
pip install 'biosingularity[mcp,store]'
biosingularity-mcp # stdio; tools: audit_references, verify_variant, corroborate_gene_disease, check_drug_interaction, provenance, scan_folder, …
# Claude Desktop — add to claude_desktop_config.json:
# { "mcpServers": { "biosingularity": { "command": "biosingularity-mcp" } } }
# Connector setup (Desktop / Code / Science + one-click .mcpb bundle): docs/CONNECTOR.md
# DEMO — ground a fluent (but wrong) AI answer: 1 true claim affirmed, 3 errors caught (retracted/contradicted/MAJOR)
PYTHONPATH=src python examples/ground_your_output.py
# trace a paper's funding (which grants funded it): PubMed GrantList (all funders),
# enriched with NIH RePORTER, EU/EC (OpenAIRE) and UKRI (Gateway to Research) detail
PYTHONPATH=src python -m biosingularity grants --pmid 28766406 --persist
PYTHONPATH=src python -m biosingularity grants --doi 10.1038/s41586-019-1373-2 # EU/H2020 grants
PYTHONPATH=src python -m biosingularity grants --pmid 38381819 # UKRI council grants
PYTHONPATH=src python -m biosingularity grants --grant R01AI104987 # a grant -> what it produced
# verify a gene/target against genetic + functional evidence (local Open Targets datalake)
PYTHONPATH=src python -m biosingularity audit --target APP --disease "Alzheimer disease"
# verify a genetic variant against ClinVar — and CONTRADICT a false claim
PYTHONPATH=src python -m biosingularity audit --variant "CFTR p.Phe508del"
PYTHONPATH=src python -m biosingularity audit --variant "CFTR p.Phe508del" --asserts benign # -> red, contradicted
# check a drug-drug interaction (safety) against DDInter
PYTHONPATH=src python -m biosingularity audit --interaction "warfarin + ibuprofen" # -> red, MAJOR
# check a gene cancer-dependency claim against DepMap
PYTHONPATH=src python -m biosingularity audit --essential KRAS # -> selective dependency
# verify a gene-disease association (MONDO-normalized) against DisGeNET
PYTHONPATH=src python -m biosingularity audit --gene-disease "APP : Alzheimer disease" # -> supported
# CORROBORATE a gene-disease claim across DisGeNET + Open Targets + GWAS at once (consensus + confidence)
PYTHONPATH=src python -m biosingularity audit --corroborate "APP : Alzheimer disease" # -> corroborated by 3 sources, 100%
PYTHONPATH=src python -m biosingularity audit --corroborate "ERBB2 : breast carcinoma" # -> single-source (Open Targets), corroborate first
# verify a variant/gene-trait association against the GWAS Catalog (genome-wide significance)
PYTHONPATH=src python -m biosingularity audit --variant-trait "rs7903146 : type 2 diabetes" # -> significant
PYTHONPATH=src python -m biosingularity audit --variant-trait "APOE : Alzheimer disease" # -> rs429358, p<1e-300
# verify a gene-phenotype claim against HPO (Human Phenotype Ontology)
PYTHONPATH=src python -m biosingularity audit --phenotype "FBN1 : ectopia lentis" # -> supported (Marfan)
# resolve drugs offline against a local ChEMBL mirror (no EBI dependency, fast & reliable)
PYTHONPATH=src python -m biosingularity audit --drug cerivastatin --drug-source local
# decompose a free-text claim into entities and verify each (genes -> Open Targets, drugs -> ChEMBL)
pip install 'biosingularity[nlp]' # local OpenMed NER models (optional extra)
PYTHONPATH=src python -m biosingularity decompose \
"Aducanumab targets APP to treat Alzheimer's disease" --audit
# score the substrate's OWN accuracy against a labelled claim set (precision/recall/F1, confusion matrix)
PYTHONPATH=src python -m biosingularity eval # runs the full pipeline on data/eval_claims.json
# HONEST miss-rate: of N random known-true DisGeNET associations, how many does the pipeline confirm / cross-corroborate?
PYTHONPATH=src python -m biosingularity eval --recall 100 # -> round-trip recall + cross-source agreement %
# scan a folder (thesis / manuscript / reading list) -> trust-metadata layer + a visual HTML dashboard
PYTHONPATH=src python -m biosingularity scan ~/thesis --html report.html --sidecars # flags any retracted refs you cite
# durable provenance: everything the substrate knows about a reference (every flag, receipt, and when)
PYTHONPATH=src python -m biosingularity provenance 10.1038/nature04533 # -> retracted, with receipts + dates
# DISCLOSE data freshness — how old is the ground truth behind each datalake verdict? (every verdict now stamps its data age)
PYTHONPATH=src python -m biosingularity freshness # -> ClinVar/GWAS undated, Open Targets 486d old, ...
# freshness: re-audit stored papers/drugs and flag any status DRIFT (cron-friendly; exit 2 on drift)
PYTHONPATH=src python -m biosingularity refresh --kind paper --limit 50
# evidence-handling micro-bench: does substrate-grounding lift a model's answers?
PYTHONPATH=src python -m biosingularity microbench --demo # deterministic, no API spend
PYTHONPATH=src python -m biosingularity microbench --model claude-opus-4-8 # live model (key-gated, paid)
# funder coverage: which of the top funders do we cover at depth vs breadth?
PYTHONPATH=src python -m biosingularity funders --gaps 10
PYTHONPATH=src python -m biosingularity funders --lookup "Wellcome Trust"
The datalake-backed commands read local Postgres mirrors — point them with
BIOSINGULARITY_CHEMBL_DSN (local ChEMBL) and BIOSINGULARITY_OPENSCIENCE_DSN
(Open Targets); both default to postgresql://localhost:5432/{chembl_temp,openscience_local}.
Pre-populate the DOI→{OpenAlex id, PMC id} crosswalk (one-time, from a local snapshot):
psql -d biosingularity -f db/migrations/0004_doi_crosswalk.sql
BIOSINGULARITY_CROSSWALK_DUCKDB=/path/to/crosswalk.duckdb scripts/load_crosswalk.sh
Exit code reflects the worst finding: 0 clean, 1 amber (unresolved / corrected
/ stopped-early / black-box), 2 red (retracted / withdrawn drug). Set
BIOSINGULARITY_NCBI_API_KEY / BIOSINGULARITY_NCBI_EMAIL to raise NCBI rate limits.
Architecture
db/migrations/0001_init.sql the provenance substrate (entities, aliases, edges, flags, claims, logs)
src/biosingularity/
bibtex.py DOI extraction (regex — exact, offline, free)
pubmed.py NCBI E-utilities client: resolve DOI -> PMID, fetch publication types + retraction links
classify.py pure rules: ArticleMeta / drug / trial / target -> flags (never assert grounded without a receipt)
audit.py orchestration: DOIs -> resolve -> fetch -> classify -> AuditReport
nlp.py claim decomposition (OpenMed NER) -> disease/drug/gene entities [nlp extra]
funding.py funding provenance: PubMed GrantList + NIH RePORTER -> FundingReport
verify.py PMC full-text claim retrieval; judge.py LLM entailment judge [llm extra]
models.py frozen domain values
report.py red/amber/green rendering (text + JSON)
cli.py `biosingularity {audit,verify-claim,grants,decompose,microbench,funders}`
sources/ pluggable resolvers: chembl(+_local), clinicaltrials, opentargets_local, clinvar_local, ddinter_local, depmap_local, ontology_local, disgenet_local, gwas_local, hpo_local,
openalex_local, crosswalk, pmc_fulltext, nih_reporter, openaire, ukri, crossref, nsf, usaspending, europepmc, funder_registry
microbench/ evidence-handling benchmark: baseline vs substrate-grounded, rubric grader
store.py persist audits/funding into the Postgres substrate [store extra]
tests/ offline unit tests (no network) — 101 and counting
The schema deliberately mirrors a PID-first design: every entity carries
external_ids (DOI/PMID/PMCID/ChEMBL/NCT/ORCID/ROR), identity resolution lives in
entity_aliases, every edge and flag records its source and a receipt, and every
run is logged in import_logs.
Tests
python -m unittest discover -s tests # stdlib, zero deps
# or: pip install -e ".[dev]" && pytest
Roadmap
- Persist audits into the substrate (
db/migrations/*.sql+store.py, wired via--persist) - ChEMBL + ClinicalTrials checks (drug withdrawal, black-box, stopped-early trials) via
--drug/--nct - Shareable report page (
server.py+web/) — the free-academic adoption artifact - Offline resolution against a local OpenAlex snapshot (
--source openalex) - DOI crosswalk — pre-populated PMC/OpenAlex ids stamped into
external_idson persist - PMC full-text claim verification (
verify-claim) — locate where a paper states a claim - LLM entailment judge (
verify-claim --judge) — supported / refuted / not-addressed, grounded in the retrieved passages - Funding provenance (
grants) — PubMed GrantList (all funders) + NIH RePORTER enrichment, persisted asfunded_byedges - Genetic target-evidence (
audit --target) — verify a gene/target against the local Open Targets datalake - Variant pathogenicity (
audit --variant [--asserts]) — verify a variant against ClinVar; first CONTRADICTED verdict (claim refuted by authoritative ground truth) - Drug–drug interaction (
audit --interaction) — DDInter; a MAJOR interaction surfaces red - Gene essentiality (
audit --essential) — DepMap cancer-dependency; a claimed dependency DepMap doesn't support is flagged - Gene–disease association (
audit --gene-disease) — DisGeNET (publication-backed), MONDO-normalized; a claimed association absent from the authoritative set is flagged - Variant–trait association (
audit --variant-trait) — GWAS Catalog; genome-wide significance (p<=5e-8) grounds the claim, a sub-threshold/absent association surfaces amber (L2G evaluated — unusable, rsid/gene keys empty — so GWAS Catalog is authoritative) - Gene–phenotype corroboration (
audit --phenotype) — HPO; a free-text phenotype is resolved to its HP id (full-text), then the gene+phenotype annotation is the receipt; no annotation surfaces amber with data-richness context - HGNC/MONDO entity normalization (
ontology_local) — gene aliases -> approved symbol, disease names -> MONDO id + xrefs; wired into the gene verifiers (HER2 -> ERBB2) - Offline drug resolution (
--drug-source local) — local ChEMBL mirror; no EBI dependency - Claim decomposition (
decompose) — OpenMed NER -> entities, multi-entity routing (gene+disease -> cross-source corroboration; gene-alone -> Open Targets; drug -> ChEMBL), a claim-level rollup verdict, and explicit 'unverifiable' (never a silent skip) when a datalake is down - Evidence-handling micro-bench (
microbench) — measures the lift substrate-grounding gives a model - Substrate accuracy eval (
eval) — labelled claim set run through the full pipeline; exact-severity accuracy per claim-kind + red/flagged precision/recall/F1 + confusion matrix; a regression gate (21-case v1, expandable) - Web UI for claim decomposition + target evidence (
server.pytabs: Audit / Decompose / Verify a target) - EU (OpenAIRE) + UKRI (Gateway to Research) funder enrichment in
grants, on top of NIH + the universal PubMed backbone - Crossref long-tail funder breadth — DOI -> all funders (Funder Registry
10.13039/*ids + awards) across ~30k funders, persisted with canonical funder identity - NSF depth enrichment — Crossref's NSF award numbers -> NSF Awards API (title, PI, institution, $amount)
- Funder registry (
funders) — 740 top funders crosswalked to canonical Crossref Funder Registry ids; coverage scorecard (depth/breadth/attribution); cross-source funder dedup on persist - USAspending.gov depth — all US federal funders (DOE/CDC/SAMHSA/DoD/NASA/…, 71 in the registry) via federal award numbers Crossref surfaces; depth coverage 43%->70% of $
- Europe PMC grantsList breadth — acknowledgement-mined / non-MEDLINE funder attribution (catches funders Crossref + PubMed GrantList miss)
- Evaluated, not cleanly integrable: OpenAlex grants (field empty), Gates/IATI (no award↔paper linkage), DFG/GEPRIS (HTML-only), KAKEN (key + JP), NHMRC/CIHR (brittle per-year CKAN), Europe PMC Grist depth (XML, fiddly grant-id linkage)
- Cross-source corroboration (
audit --corroborate) — one gene-disease claim fanned out to DisGeNET + Open Targets + GWAS at once; verdict is corroborated (≥2 agree, confidence via noisy-OR) / single-source / unsupported / inconclusive (a source was unreachable — never conflated with a real "no") -
contradicts/supportsgraph edges in the substrate (Consensus / scite enrichment) - Drug/trial auditing in the web UI (4th tab over /api/entities)
- Hosted datalake access —
server.pyhardened for tunnel exposure (BIOSINGULARITY_API_KEYgate + CORS allow-list +/api/health); the SPA's datalake tabs point at a configurabledatalakeApiBase(web/config.js). See docs/DEPLOY.md — run the local server behind a Cloudflare/Tailscale tunnel and every tab works live against the full 493GB. - Durable provenance API (
provenance+GET /api/provenance) — any reference (DOI/PMID/drug/NCT/gene/pair) resolves through the alias graph to its full flag history with receipts + detection dates; the citable "audit_id → provenance record" - Staleness / re-audit (
refresh) — re-audits stored papers/drugs stalest-first, persists fresh flags, and reports status DRIFT (e.g. a paper now retracted that was clean); exit 2 on drift so a cron can alert - MCP server (
biosingularity-mcp) — exposes the verifiers as agent tools (audit_references, verify_variant [+contradiction], corroborate_gene_disease, check_drug_interaction, gene_essentiality, variant_trait, phenotype, check_drug/trial, provenance, scan_folder) so any MCP client can GROUND a claim before asserting it — the integration play: be the trust layer beneath generative biomedical AI, not a competitor to it - Commercial slice: private audits + "substrate-verified" certification + metered API
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file biosingularity-0.1.0.tar.gz.
File metadata
- Download URL: biosingularity-0.1.0.tar.gz
- Upload date:
- Size: 239.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3eade566994e737efa39fa636bbf9da446cd54d13712b09fd00b37a2d5edd92
|
|
| MD5 |
a26d79d1342dcc8961e5ca9bfe184fb2
|
|
| BLAKE2b-256 |
16f6c9f7a0a977375a424dc5ef989bc94d93ef95a82fc80ebeacc188bfe26378
|
Provenance
The following attestation bundles were made for biosingularity-0.1.0.tar.gz:
Publisher:
publish.yml on markhahnel/biosingularity
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
biosingularity-0.1.0.tar.gz -
Subject digest:
e3eade566994e737efa39fa636bbf9da446cd54d13712b09fd00b37a2d5edd92 - Sigstore transparency entry: 2047455927
- Sigstore integration time:
-
Permalink:
markhahnel/biosingularity@d3e93a173fdd885ffc4456d7fa2c622a7bbc3f63 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/markhahnel
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d3e93a173fdd885ffc4456d7fa2c622a7bbc3f63 -
Trigger Event:
release
-
Statement type:
File details
Details for the file biosingularity-0.1.0-py3-none-any.whl.
File metadata
- Download URL: biosingularity-0.1.0-py3-none-any.whl
- Upload date:
- Size: 211.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3232d7f09761ed7ad333d1457b13a075fad92d55f3a8a49fed7ecc1178817aeb
|
|
| MD5 |
33eb154e86b0643d22d7a848138b4d4f
|
|
| BLAKE2b-256 |
1d46103ec13ec972907eabae2855ee931c7f8530f68eccc37ef5a6a01aa00927
|
Provenance
The following attestation bundles were made for biosingularity-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on markhahnel/biosingularity
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
biosingularity-0.1.0-py3-none-any.whl -
Subject digest:
3232d7f09761ed7ad333d1457b13a075fad92d55f3a8a49fed7ecc1178817aeb - Sigstore transparency entry: 2047455932
- Sigstore integration time:
-
Permalink:
markhahnel/biosingularity@d3e93a173fdd885ffc4456d7fa2c622a7bbc3f63 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/markhahnel
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d3e93a173fdd885ffc4456d7fa2c622a7bbc3f63 -
Trigger Event:
release
-
Statement type: