Install any skill in seconds. Free to start, no credit card required.
Get Started Free →End-to-end copy number variant detection workflow from BAM files. Covers CNVkit analysis for exome/targeted sequencing with visualization and annotation. Use when detecting copy number alterations from sequencing data.
.claude/skills/bio-workflows-cnv-pipeline/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 7% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 94% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 82% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 45% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 59% | 0% |
<!--
#
#
-->
Complete workflow for detecting copy number variants from exome or targeted sequencing data.
BAM files (tumor/normal or germline)
|
v
[1. Target Preparation] --> Create/access target BED
|
v
[2. Coverage Calculation] --> Read depth per target
|
v
[3. Reference Creation] --> Pool of normals
|
v
[4. CNV Calling] --------> Log2 ratios, segmentation
|
v
[5. Visualization] ------> Scatter plots, heatmaps
|
v
[6. Annotation] ---------> Gene-level CNVs
|
v
CNV calls with gene annotationsbash# If using exome capture kit BED cnvkit.py target capture_targets.bed \ --annotate refFlat.txt \ --split \ -o targets.bed # Access regions (off-target for WGS-like sensitivity) cnvkit.py access genome.fa \ -o access.bed cnvkit.py antitarget targets.bed \ --access access.bed \ -o antitargets.bed
bash# For each sample for bam in *.bam; do sample=$(basename $bam .bam) # Target coverage cnvkit.py coverage $bam targets.bed \ -o coverage/${sample}.targetcoverage.cnn # Antitarget coverage cnvkit.py coverage $bam antitargets.bed \ -o coverage/${sample}.antitargetcoverage.cnn done
bash# From normal samples cnvkit.py reference \ coverage/normal*.targetcoverage.cnn \ coverage/normal*.antitargetcoverage.cnn \ --fasta genome.fa \ -o reference.cnn # Or flat reference (no normals available) cnvkit.py reference \ --fasta genome.fa \ --targets targets.bed \ --antitargets antitargets.bed \ -o flat_reference.cnn
bashfor bam in tumor*.bam; do sample=$(basename $bam .bam) # Fix and segment cnvkit.py fix \ coverage/${sample}.targetcoverage.cnn \ coverage/${sample}.antitargetcoverage.cnn \ reference.cnn \ -o cnv/${sample}.cnr # Segment cnvkit.py segment cnv/${sample}.cnr \ -o cnv/${sample}.cns # Call integer copy numbers cnvkit.py call cnv/${sample}.cns \ -o cnv/${sample}.call.cns done
bash# Scatter plot for single sample cnvkit.py scatter cnv/tumor1.cnr \ -s cnv/tumor1.cns \ -o plots/tumor1_scatter.pdf # Chromosome-specific cnvkit.py scatter cnv/tumor1.cnr \ -s cnv/tumor1.cns \ -c chr17 \ -o plots/tumor1_chr17.pdf # Diagram (chromosome ideogram) cnvkit.py diagram cnv/tumor1.cnr \ -s cnv/tumor1.cns \ -o plots/tumor1_diagram.pdf # Heatmap for multiple samples cnvkit.py heatmap cnv/*.cns \ -o plots/cohort_heatmap.pdf
bash# Export to various formats cnvkit.py export seg cnv/*.cns -o cnv/cohort.seg cnvkit.py export vcf cnv/tumor1.call.cns -o cnv/tumor1.vcf # Gene-level summary cnvkit.py genemetrics cnv/tumor1.cnr \ -s cnv/tumor1.cns \ --threshold 0.2 \ -o cnv/tumor1_genes.tsv # Filter for significant CNVs awk '$6 < -0.4 || $6 > 0.3' cnv/tumor1_genes.tsv > cnv/tumor1_significant_genes.tsv
bash#!/bin/bash set -e TARGETS="targets.bed" REFERENCE="reference.cnn" OUTDIR="cnv_results" mkdir -p ${OUTDIR}/{coverage,cnv,plots} # Process all tumor samples for bam in tumor*.bam; do sample=$(basename $bam .bam) echo "Processing ${sample}..." # Coverage cnvkit.py coverage $bam ${TARGETS} \ -o ${OUTDIR}/coverage/${sample}.targetcoverage.cnn # Fix cnvkit.py fix \ ${OUTDIR}/coverage/${sample}.targetcoverage.cnn \ ${OUTDIR}/coverage/${sample}.antitargetcoverage.cnn \ ${REFERENCE} \ -o ${OUTDIR}/cnv/${sample}.cnr # Segment cnvkit.py segment ${OUTDIR}/cnv/${sample}.cnr \ -o ${OUTDIR}/cnv/${sample}.cns # Call cnvkit.py call ${OUTDIR}/cnv/${sample}.cns \ -o ${OUTDIR}/cnv/${sample}.call.cns # Plot cnvkit.py scatter ${OUTDIR}/cnv/${sample}.cnr \ -s ${OUTDIR}/cnv/${sample}.cns \ -o ${OUTDIR}/plots/${sample}.pdf done # Cohort heatmap cnvkit.py heatmap ${OUTDIR}/cnv/*.cns -o ${OUTDIR}/plots/heatmap.pdf
bash# For germline analysis (no tumor-normal) cnvkit.py batch sample*.bam \ --normal normal*.bam \ --targets targets.bed \ --fasta genome.fa \ --output-reference reference.cnn \ --output-dir cnv_output \ --scatter --diagram # Or use flat reference cnvkit.py batch sample.bam \ --method hybrid \ --targets targets.bed \ --fasta genome.fa \ --output-dir cnv_output
| Step | Parameter | Value | |------|-----------|-------| | target | --split | Yes (for WES) | | segment | --method | cbs (default) | | call | --ploidy | 2 (adjust if known) | | call | --purity | Estimate if tumor | | genemetrics | --threshold | 0.2 |
| Issue | Likely Cause | Solution | |-------|--------------|----------| | Noisy signal | Low coverage | Increase sequencing depth | | No CNVs | Flat reference, normal sample | Check reference creation | | Many small CNVs | Over-segmentation | Increase segment min size | | Batch effects | Different capture kits | Match samples to correct reference |
bash#!/bin/bash set -e GENOME="genome.fa" TARGETS="capture_targets.bed" REFFLAT="refFlat.txt" NORMAL_BAMS="normal*.bam" TUMOR_BAMS="tumor*.bam" OUTDIR="cnv_results" mkdir -p ${OUTDIR}/{coverage,cnv,plots,annotation} # Step 1: Prepare targets cnvkit.py target ${TARGETS} --annotate ${REFFLAT} --split -o ${OUTDIR}/targets.bed cnvkit.py access ${GENOME} -o ${OUTDIR}/access.bed cnvkit.py antitarget ${OUTDIR}/targets.bed --access ${OUTDIR}/access.bed -o ${OUTDIR}/antitargets.bed # Step 2: Coverage (normals) for bam in ${NORMAL_BAMS}; do sample=$(basename $bam .bam) cnvkit.py coverage $bam ${OUTDIR}/targets.bed -o ${OUTDIR}/coverage/${sample}.targetcoverage.cnn cnvkit.py coverage $bam ${OUTDIR}/antitargets.bed -o ${OUTDIR}/coverage/${sample}.antitargetcoverage.cnn done # Step 3: Reference cnvkit.py reference ${OUTDIR}/coverage/normal*.cnn --fasta ${GENOME} -o ${OUTDIR}/reference.cnn # Step 4-5: Process tumors for bam in ${TUMOR_BAMS}; do sample=$(basename $bam .bam) cnvkit.py coverage $bam ${OUTDIR}/targets.bed -o ${OUTDIR}/coverage/${sample}.targetcoverage.cnn cnvkit.py coverage $bam ${OUTDIR}/antitargets.bed -o ${OUTDIR}/coverage/${sample}.antitargetcoverage.cnn cnvkit.py fix ${OUTDIR}/coverage/${sample}.targetcoverage.cnn \ ${OUTDIR}/coverage/${sample}.antitargetcoverage.cnn \ ${OUTDIR}/reference.cnn -o ${OUTDIR}/cnv/${sample}.cnr cnvkit.py segment ${OUTDIR}/cnv/${sample}.cnr -o ${OUTDIR}/cnv/${sample}.cns cnvkit.py call ${OUTDIR}/cnv/${sample}.cns -o ${OUTDIR}/cnv/${sample}.call.cns cnvkit.py scatter ${OUTDIR}/cnv/${sample}.cnr -s ${OUTDIR}/cnv/${sample}.cns -o ${OUTDIR}/plots/${sample}.pdf cnvkit.py genemetrics ${OUTDIR}/cnv/${sample}.cnr -s ${OUTDIR}/cnv/${sample}.cns -o ${OUTDIR}/annotation/${sample}_genes.tsv done echo "Pipeline complete. Results in ${OUTDIR}/"
<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 24,314 | 13,998 | -42% | 1 | 1 | 0% | 5,355 | 5,741 | +7% | 0 | 0 | — |
case-02 | fail→pass | 11,597 | 10,443 | -10% | 1 | 1 | 0% | 2,395 | 4,638 | +94% | 0 | 0 | — |
case-03 | fail→pass | 9,605 | 4,601 | -52% | 1 | 1 | 0% | 1,830 | 3,335 | +82% | 0 | 0 | — |
case-12 | pass→pass | 10,266 | 4,712 | -54% | 1 | 1 | 0% | 2,140 | 3,341 | +56% | 0 | 0 | — |
case-22 | pass→pass | 14,913 | 13,690 | -8% | 1 | 1 | 0% | 2,607 | 5,333 | +105% | 0 | 0 | — |
case-04 | fail→pass | 13,687 | 6,927 | -49% | 1 | 1 | 0% | 2,607 | 3,791 | +45% | 0 | 0 | — |
case-05 | fail→pass | 15,807 | 7,872 | -50% | 1 | 1 | 0% | 2,641 | 4,204 | +59% | 0 | 0 | — |
case-06 | fail→pass | 18,659 | 3,491 | -81% | 1 | 1 | 0% | 1,773 | 3,100 | +75% | 0 | 0 | — |
case-07 | pass→pass | 4,672 | 4,090 | -12% | 1 | 1 | 0% | 888 | 3,340 | +276% | 0 | 0 | — |
case-08 | fail→pass | 10,565 | 3,186 | -70% | 1 | 1 | 0% | 1,803 | 2,972 | +65% | 0 | 0 | — |
case-09 | pass→pass | 4,646 | 2,720 | -41% | 1 | 1 | 0% | 851 | 2,948 | +246% | 0 | 0 | — |
case-10 | pass→pass | 3,253 | 2,789 | -14% | 1 | 1 | 0% | 538 | 2,968 | +452% | 0 | 0 | — |
case-11 | pass→pass | 5,737 | 3,036 | -47% | 1 | 1 | 0% | 970 | 3,073 | +217% | 0 | 0 | — |
case-13 | fail→pass | 12,252 | 7,373 | -40% | 1 | 1 | 0% | 2,276 | 3,912 | +72% | 0 | 0 | — |
case-14 | pass→pass | 8,626 | 6,372 | -26% | 1 | 1 | 0% | 1,588 | 3,680 | +132% | 0 | 0 | — |
case-15 | pass→pass | 6,008 | 3,990 | -34% | 1 | 1 | 0% | 995 | 3,277 | +229% | 0 | 0 | — |
case-16 | fail→pass | 7,362 | 4,378 | -41% | 1 | 1 | 0% | 1,303 | 3,245 | +149% | 0 | 0 | — |
case-17 | fail→fail | 11,712 | 6,100 | -48% | 1 | 1 | 0% | 2,019 | 3,588 | +78% | 0 | 0 | — |
case-18 | pass→pass | 14,119 | 12,499 | -11% | 1 | 1 | 0% | 2,228 | 4,919 | +121% | 0 | 0 | — |
case-19 | pass→pass | 15,975 | 12,219 | -24% | 1 | 1 | 0% | 2,542 | 4,515 | +78% | 0 | 0 | — |
case-20 | pass→pass | 7,752 | 6,600 | -15% | 1 | 1 | 0% | 1,562 | 3,761 | +141% | 0 | 0 | — |
case-21 | pass→pass | 8,967 | 6,370 | -29% | 1 | 1 | 0% | 1,723 | 3,803 | +121% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +41 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/26/2026 | +27% |
Other measured skills in the registry, with their headline benchmark lift.