Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Fast short-read DNA aligner for WGS/WES/ChIP-seq. 2× faster BWA-MEM successor; outputs SAM/BAM with read group headers for GATK. Primary plus supplementary records for chimeric reads. Use STAR for RNA-seq splice-aware alignment; Bowtie2 is a comparable alternative.
.claude/skills/jaechang-hits-bwa-mem2-dna-aligner/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 178% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 386% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 185% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 161% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 246% | 0% |
BWA-MEM2 aligns short DNA reads (Illumina, 50–250 bp) to a reference genome using the BWT-FM index. It is the standard aligner for whole-genome sequencing (WGS), whole-exome sequencing (WES), ChIP-seq, and ATAC-seq DNA alignment. BWA-MEM2 is 2× faster than the original BWA-MEM while producing identical results. It outputs SAM format with proper read group (@RG) headers required by GATK HaplotypeCaller and Picard tools. For paired-end reads, it marks proper pairs and resolves chimeric/split reads into supplementary alignments.
@RG read group tags> Check before installing: The tool may already be available in the current environment (e.g., inside a pixi / conda env). Run command -v bwa-mem2 first and skip the install commands below if it returns a path. When running inside a pixi project, invoke the tool via pixi run bwa-mem2 rather than bare bwa-mem2.
bash# Install with conda (recommended) conda install -c bioconda bwa-mem2 samtools # Or download pre-compiled binary wget https://github.com/bwa-mem2/bwa-mem2/releases/download/v2.2.1/bwa-mem2-2.2.1_x64-linux.tar.bz2 tar -jxf bwa-mem2-2.2.1_x64-linux.tar.bz2 export PATH="$PWD/bwa-mem2-2.2.1_x64-linux:$PATH" # Verify bwa-mem2 version # 2.2.1
bash# 1. Build genome index (~30 min, run once) bwa-mem2 index GRCh38.fa # 2. Align paired-end reads and sort bwa-mem2 mem -t 16 -R "@RG\tID:sample1\tSM:sample1\tPL:ILLUMINA" \ GRCh38.fa sample1_R1.fastq.gz sample1_R2.fastq.gz \ | samtools sort -@ 8 -o sample1.sorted.bam # 3. Index the BAM samtools index sample1.sorted.bam echo "Aligned reads: $(samtools view -c -F 4 sample1.sorted.bam)"
Obtain the reference genome FASTA file matching the target assembly.
bash# Download GRCh38 primary assembly (human) wget https://ftp.ncbi.nlm.nih.gov/genomes/all/GCA/000/001/405/GCA_000001405.15_GRCh38/seqs_for_alignment_pipelines.ucsc_ids/GCA_000001405.15_GRCh38_no_alt_analysis_set.fna.gz gunzip GCA_000001405.15_GRCh38_no_alt_analysis_set.fna.gz mv GCA_000001405.15_GRCh38_no_alt_analysis_set.fna GRCh38.fa # Or use ENSEMBL/GENCODE wget https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_47/GRCh38.primary_assembly.genome.fa.gz gunzip GRCh38.primary_assembly.genome.fa.gz echo "Reference size: $(du -sh GRCh38.fa)"
Index the reference genome — required once per genome, takes ~25-35 min for human.
bash# Build index (~28 GB RAM required for human genome) bwa-mem2 index GRCh38.fa # This creates: GRCh38.fa.0123, GRCh38.fa.amb, GRCh38.fa.ann, # GRCh38.fa.bwt.2bit.64, GRCh38.fa.pac echo "Index files: $(ls GRCh38.fa.* | wc -l) created" ls -lh GRCh38.fa.*
Align FASTQ reads with a read group header required for GATK compatibility.
bash# Align with read group (required for GATK) # @RG fields: ID (run ID), SM (sample name), PL (platform), LB (library), PU (flowcell) bwa-mem2 mem \ -t 16 \ -R "@RG\tID:sample1_run1\tSM:sample1\tPL:ILLUMINA\tLB:lib1\tPU:flowcell1" \ GRCh38.fa \ sample1_R1.fastq.gz \ sample1_R2.fastq.gz \ | samtools sort -@ 8 -m 2G -o sample1.sorted.bam samtools index sample1.sorted.bam echo "Alignment complete." echo "Total reads: $(samtools view -c sample1.sorted.bam)" echo "Mapped reads: $(samtools view -c -F 4 sample1.sorted.bam)"
Remove or mark optical and PCR duplicates before variant calling.
bash# Option A: samtools markdup (fast) samtools fixmate -m sample1.sorted.bam sample1.fixmate.bam samtools sort -@ 8 -o sample1.fixmate.sorted.bam sample1.fixmate.bam samtools markdup -@ 8 sample1.fixmate.sorted.bam sample1.markdup.bam samtools index sample1.markdup.bam echo "Duplication rate:" samtools flagstat sample1.markdup.bam | grep "duplicate" # Option B: Picard MarkDuplicates (GATK best practices) picard MarkDuplicates \ INPUT=sample1.sorted.bam \ OUTPUT=sample1.markdup.bam \ METRICS_FILE=sample1.dupmetrics.txt \ REMOVE_DUPLICATES=false \ CREATE_INDEX=true cat sample1.dupmetrics.txt | grep -A2 "ESTIMATED"
Generate alignment statistics and check key quality metrics.
bash# Full alignment statistics samtools flagstat sample1.markdup.bam > sample1.flagstat.txt cat sample1.flagstat.txt # Coverage statistics samtools coverage sample1.markdup.bam | head -30 # Parse key metrics with Python python3 - << 'EOF' from pathlib import Path flagstat = Path("sample1.flagstat.txt").read_text() for line in flagstat.splitlines(): if any(kw in line for kw in ["total", "mapped", "properly paired", "duplicate"]): print(line) EOF
Pipe BWA-MEM2 output directly into GATK HaplotypeCaller.
bash#!/bin/bash # Complete WGS alignment → variant calling pipeline GENOME="GRCh38.fa" SAMPLE="sample1" R1="data/${SAMPLE}_R1.fastq.gz" R2="data/${SAMPLE}_R2.fastq.gz" THREADS=16 OUTDIR="results/${SAMPLE}" mkdir -p "$OUTDIR" # Step 1: Align + sort bwa-mem2 mem -t $THREADS \ -R "@RG\tID:${SAMPLE}\tSM:${SAMPLE}\tPL:ILLUMINA\tLB:lib1\tPU:run1" \ $GENOME $R1 $R2 \ | samtools sort -@ 8 -o $OUTDIR/${SAMPLE}.sorted.bam samtools index $OUTDIR/${SAMPLE}.sorted.bam # Step 2: Mark duplicates samtools fixmate -m $OUTDIR/${SAMPLE}.sorted.bam - \ | samtools sort -@ 8 \ | samtools markdup -@ 8 - $OUTDIR/${SAMPLE}.markdup.bam samtools index $OUTDIR/${SAMPLE}.markdup.bam # Step 3: GATK variant calling gatk HaplotypeCaller \ -R $GENOME \ -I $OUTDIR/${SAMPLE}.markdup.bam \ -O $OUTDIR/${SAMPLE}.g.vcf.gz \ -ERC GVCF \ --native-pair-hmm-threads 4 echo "Pipeline complete: $OUTDIR/${SAMPLE}.g.vcf.gz"
| Parameter | Default | Range/Options | Effect | |-----------|---------|---------------|--------| | -t | 1 | 1–64 | CPU threads; use 8–16 for production runs | | -R | — | @RG\tID:...\tSM:... | Read group string; required for GATK compatibility | | -k | 19 | 10–28 | Minimum seed length; lower = more sensitive for shorter reads | | -w | 100 | 50–500 | Band width for Smith-Waterman alignment | | -M | off | flag | Mark split/supplementary reads as secondary (BWA-MEM style); needed for Picard compatibility | | -a | off | flag | Output all alignments for single-end reads (for seeding; increases file size) | | -p | off | flag | Treat input as interleaved paired-end FASTQ | | -c | 500 | 100–10000 | Skip alignment for MEM count > threshold (reduces multi-mapper noise) | | -T | 30 | 20–60 | Minimum alignment score threshold; lower = report more low-quality alignments | | -Y | off | flag | Use soft clipping for supplementary alignments (recommended for GATK) |
bash#!/bin/bash # Align all samples in parallel using GNU parallel or sequential loop GENOME="GRCh38.fa" SAMPLES=(ctrl_1 ctrl_2 treat_1 treat_2) THREADS=12 for sample in "${SAMPLES[@]}"; do echo "=== Aligning $sample ===" bwa-mem2 mem -t $THREADS \ -R "@RG\tID:${sample}\tSM:${sample}\tPL:ILLUMINA\tLB:lib1\tPU:run1" \ $GENOME \ data/${sample}_R1.fastq.gz \ data/${sample}_R2.fastq.gz \ | samtools sort -@ 4 -m 2G -o results/${sample}.sorted.bam samtools index results/${sample}.sorted.bam MAPPED=$(samtools view -c -F 4 results/${sample}.sorted.bam) TOTAL=$(samtools view -c results/${sample}.sorted.bam) echo "$sample: $MAPPED / $TOTAL reads mapped" done
pythonimport subprocess import pandas as pd from pathlib import Path samples = ["ctrl_1", "ctrl_2", "treat_1", "treat_2"] metrics = [] for sample in samples: bam = f"results/{sample}.sorted.bam" result = subprocess.run( ["samtools", "flagstat", bam], capture_output=True, text=True ) stats = {} for line in result.stdout.splitlines(): if "total" in line: stats["total"] = int(line.split()[0]) elif "mapped" in line and "%" in line: stats["mapped"] = int(line.split()[0]) stats["pct_mapped"] = float(line.split("(")[1].split("%")[0]) elif "properly paired" in line: stats["properly_paired"] = int(line.split()[0]) stats["sample"] = sample metrics.append(stats) df = pd.DataFrame(metrics).set_index("sample") print(df[["total", "mapped", "pct_mapped", "properly_paired"]]) df.to_csv("alignment_metrics.tsv", sep="\t")
| Output | Format | Description | |--------|--------|-------------| | *.sorted.bam | BAM | Coordinate-sorted aligned reads; index with samtools index | | *.sorted.bam.bai | BAI | BAM index; required for random access by GATK and IGV | | *.flagstat.txt | Text | Alignment summary: total/mapped/paired/duplicate counts and percentages | | *.markdup.bam | BAM | Duplicate-marked BAM; use as input to GATK HaplotypeCaller | | *.dupmetrics.txt | Text | Picard duplication metrics with estimated library size |
| Problem | Cause | Solution | |---------|-------|----------| | Low mapping rate (< 85%) | Genome mismatch, contamination, or low quality reads | Verify genome assembly matches sample; run FastQC; trim adapters with Trim Galore | | @RG header missing error in GATK | -R flag not specified during alignment | Re-align with -R "@RG\tID:...\tSM:...\tPL:ILLUMINA" | | Out of memory during indexing | Insufficient RAM for genome index | BWA-MEM2 requires ~28 GB for human; use classic bwa with less RAM if needed | | Unbalanced paired-end counts | Interleaved FASTQ or file mismatch | Add -p for interleaved; verify R1/R2 read counts with zcat r1.fq.gz \| wc -l | | [E::bwa_idx_load_from_disk] error | Index files missing or wrong prefix | Re-run bwa-mem2 index genome.fa; ensure all .0123, .bwt.2bit.64 files exist | | Slow alignment speed | Low thread count or slow I/O | Use -t 16 or more; store data on SSD; pipe directly to samtools sort | | Supplementary alignments causing issues | Split reads in downstream tools | Add -M flag to mark split reads as secondary (Picard compatibility) | | GATK base quality score recalibration fails | Missing known variant VCF | Download dbSNP VCF for your genome assembly from NCBI or GATK resource bundle |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 10,969 | 19,169 | +75% | 1 | 1 | 0% | 2,102 | 5,847 | +178% | 0 | 0 | — |
case-02 | pass→pass | 11,645 | 8,834 | -24% | 1 | 1 | 0% | 2,090 | 5,462 | +161% | 0 | 0 | — |
case-03 | pass→pass | 12,342 | 11,637 | -6% | 1 | 1 | 0% | 1,745 | 6,035 | +246% | 0 | 0 | — |
case-04 | pass→pass | 14,771 | 12,447 | -16% | 1 | 1 | 0% | 2,404 | 6,039 | +151% | 0 | 0 | — |
case-05 | fail→pass | 6,214 | 4,472 | -28% | 1 | 1 | 0% | 968 | 4,708 | +386% | 0 | 0 | — |
case-06 | pass→pass | 4,501 | 2,678 | -41% | 1 | 1 | 0% | 698 | 4,437 | +536% | 0 | 0 | — |
case-07 | pass→pass | 7,969 | 2,703 | -66% | 1 | 1 | 0% | 1,382 | 4,422 | +220% | 0 | 0 | — |
case-08 | pass→pass | 5,484 | 4,766 | -13% | 1 | 1 | 0% | 1,027 | 4,777 | +365% | 0 | 0 | — |
case-09 | pass→pass | 6,500 | 4,282 | -34% | 1 | 1 | 0% | 1,153 | 4,801 | +316% | 0 | 0 | — |
case-10 | pass→pass | 10,617 | 5,544 | -48% | 1 | 1 | 0% | 1,696 | 4,884 | +188% | 0 | 0 | — |
case-11 | pass→pass | 9,681 | 6,596 | -32% | 1 | 1 | 0% | 1,513 | 5,088 | +236% | 0 | 0 | — |
case-12 | pass→pass | 4,029 | 3,104 | -23% | 1 | 1 | 0% | 590 | 4,518 | +666% | 0 | 0 | — |
case-13 | pass→pass | 10,331 | 6,380 | -38% | 1 | 1 | 0% | 1,780 | 5,142 | +189% | 0 | 0 | — |
case-14 | pass→pass | 4,617 | 2,301 | -50% | 1 | 1 | 0% | 749 | 4,320 | +477% | 0 | 0 | — |
case-15 | pass→pass | 11,761 | 6,981 | -41% | 1 | 1 | 0% | 2,019 | 5,174 | +156% | 0 | 0 | — |
case-16 | fail→pass | 9,124 | 2,247 | -75% | 1 | 1 | 0% | 1,536 | 4,375 | +185% | 0 | 0 | — |
case-22 | pass→pass | 25,770 | 15,354 | -40% | 1 | 1 | 0% | 4,017 | 7,127 | +77% | 0 | 0 | — |
case-17 | pass→pass | 2,877 | 3,641 | +27% | 1 | 1 | 0% | 442 | 4,590 | +938% | 0 | 0 | — |
case-18 | pass→pass | 5,281 | 2,111 | -60% | 1 | 1 | 0% | 818 | 4,337 | +430% | 0 | 0 | — |
case-19 | pass→pass | 6,423 | 3,635 | -43% | 1 | 1 | 0% | 880 | 4,603 | +423% | 0 | 0 | — |
case-20 | pass→pass | 7,421 | 5,990 | -19% | 1 | 1 | 0% | 1,739 | 5,134 | +195% | 0 | 0 | — |
case-21 | pass→pass | 17,460 | 11,342 | -35% | 1 | 1 | 0% | 2,692 | 5,708 | +112% | 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 +14 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.
Other measured skills in the registry, with their headline benchmark lift.