ML pipeline for distinguishing genuine CRISPR-induced indels from sequencing artifacts in whole-genome sequencing (WGS) data.
crispr-sieve is a drop-in enrichment step for nf-core/scge. It receives the indel TSV produced by find_edited_reads.py and appends two columns:
| Column | Description |
|---|---|
sieve_score |
XGBoost probability that this indel is a genuine CRISPR edit (0–1) |
sieve_label |
Binary classification at threshold 0.5 |
The existing output schema is preserved exactly, so the downstream scge report requires no changes.
The incumbent find_edited_reads.py uses heuristic filters (--max-in-control, --max-mutation-distance) and a 17-feature sklearn model. Both are too blunt for clinical scientist trust. crispr-sieve adds:
- Strand bias — strong forward/reverse asymmetry flags PCR artifacts
- Phred confidence — mean base quality at the indel position
- Homopolymer context — runs ≥4 identical bases signal polymerase slippage
- Repair thermodynamics — InDelphi/FORECasT predicted outcome match and entropy
- Off-target cleavage prior — CRISPR-Net probability; un-cleavable sites → artifact
All tools are WGS-appropriate. Amplicon-only tools (CRISPResso2, CRISPECTOR 2.0, ampliCan) are explicitly excluded.
nf-core/scge pipeline
DRAGEN tumor-normal
↓
find_edited_reads.py ← existing; emits indel TSV
↓
crispr-sieve ← this repo; enriches TSV with sieve_score + sieve_label
↓
Annotate SVs / VEP
↓
scge report
See ROADMAP.md for the full architecture, feature set, diffusion levels 0–4, and Nextflow integration details.
# Install environment (pixi handles everything including nextflow)
pixi install
# Run tests
pixi run test
# Validate Nextflow DAG (no data required)
pixi run stub
# Score a find_edited_reads.py TSV
pixi run score \
--input sample.tsv \
--edited-bam edited.bam \
--control-bam control.bam \
--reference hg38.fa \
--target-vcf targets.vcf \
--output sample.sieve.tsvcrispr-sieve/
├── sieve/ # installable Python package
│ ├── features/ # FeatureExtractor plugins (cigar, repair, offtarget, spatial)
│ ├── io/ # pysam BAM reader, cyvcf2 VCF reader, TSV IO
│ ├── classify.py # XGBoost + leave-one-donor-out CV + SHAP
│ ├── labels.py # 5%/1% threshold labeling
│ └── matrix.py # feature assembler
├── workflow/ # Nextflow DSL2 pipeline
│ ├── main.nf
│ ├── modules/sieve/ # nf-core-compatible process
│ └── conf/params.config
├── tests/ # 45 pytest tests; synthetic BAM fixtures
├── models/ # trained .pkl artifacts (not committed)
├── find_edited_reads.py # reference implementation (read-only baseline)
├── pixi.toml # environment + task shortcuts
└── ROADMAP.md # architecture reference
pixi run test # full pytest suite
pixi run cov # pytest + coverage report
pixi run stub # validate Nextflow DAG without running tools
pixi run check-imports # verify all package imports resolve
pixi run train # train XGBoost model (requires labeled data)| Level | Goal | Status |
|---|---|---|
| 0 | Skeleton: SiteRecord, FeatureExtractor ABC, Nextflow stub, 23-feature set, 45 tests | complete |
| 1 | Parity: strand bias + Phred + homopolymer; XGBoost beats existing .pkl ROC-AUC | pending |
| 2 | Repair priors: InDelphi + FORECasT predicted_repair_match + repair_entropy | pending |
| 3 | Off-target prior: CRISPR-Net off_target_cleavage_prob | pending |
| 4 | Production: Optuna sweep, SHAP report, nf-core/scge PR | pending |
MIT