Install any skill in seconds. Free to start, no credit card required.
Get Started Free →CLI toolkit for SAM/BAM/CRAM: sort, index, convert, filter, QC alignments. Core commands: view, sort, index, flagstat, stats, depth, markdup, merge. Required between alignment and variant/peak calling. Use pysam for Python-native BAM access; deeptools for normalized coverage tracks.
.claude/skills/jaechang-hits-samtools-bam-processing/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 220% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 244% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 530% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 106% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 667% | 0% |
samtools is the standard command-line toolkit for processing sequence alignment files in SAM, BAM, and CRAM formats. It handles the complete alignment file lifecycle: format conversion, coordinate sorting, index creation, quality control statistics, read filtering, duplicate marking, and multi-file merging. samtools is a near-universal component of NGS pipelines between alignment (STAR, BWA) and downstream analysis (variant calling, peak calling, coverage).
pysam instead for Python-native BAM manipulation in custom scriptsdeeptools bamCoverage instead when you need normalized bigWig coverage tracksmosdepth instead for whole-genome per-base depth (faster, parallelized)samtools faidx for FASTA indexing; samtools sort before samtools index> Check before installing: The tool may already be available in the current environment (e.g., inside a pixi / conda env). Run command -v samtools first and skip the install commands below if it returns a path. When running inside a pixi project, invoke the tool via pixi run samtools rather than bare samtools.
bash# Bioconda (recommended) conda install -c bioconda samtools # Homebrew (macOS) brew install samtools # Verify samtools --version | head -1
bash# Typical post-alignment workflow: sort → index → QC samtools sort -@ 8 -o sorted.bam input.bam samtools index sorted.bam samtools flagstat sorted.bam
Convert between SAM/BAM/CRAM formats and extract subsets.
bash# SAM → BAM (saves ~75% disk space) samtools view -b -h input.sam -o output.bam # BAM → CRAM (saves additional 40-50%) samtools view -C -T reference.fa input.bam -o output.cram # Filter: mapping quality ≥20, exclude unmapped (-F 4) samtools view -q 20 -F 4 input.bam -o filtered.bam # Extract specific region (requires index) samtools view -h sorted.bam "chr1:1000000-2000000" -o region.bam # Count reads matching filter samtools view -c -F 4 input.bam # Output: 45231923 (number of mapped reads)
bash# Extract reads as FASTQ (for realignment or de novo assembly) samtools fastq -@ 4 -1 R1.fastq.gz -2 R2.fastq.gz -0 unpaired.fastq.gz input.bam # Extract reads as FASTA samtools fasta input.bam > reads.fasta # Filter by read group samtools view -r SAMPLE_001 multi_rg.bam -o sample001.bam
Organize BAM files for efficient random access.
bash# Sort by coordinate (required before indexing) samtools sort -@ 8 -m 2G input.bam -o sorted.bam # Sort by read name (required for fixmate/markdup) samtools sort -n -@ 8 input.bam -o namesorted.bam # Index sorted BAM (creates sorted.bam.bai) samtools index sorted.bam # For chromosomes > 512 Mbp: use CSI index instead samtools index -c sorted.bam # Group reads by name (fast, for fixmate — no full sort needed) samtools collate -o collated.bam input.bam
Generate alignment QC metrics and coverage reports.
bash# Quick summary: total, mapped, paired, properly paired samtools flagstat sorted.bam # Example output: # 50000000 + 0 in total (QC-passed reads + QC-failed reads) # 48523111 + 0 mapped (97.05% : N/A) # 50000000 + 0 paired in sequencing # 48490234 + 0 properly paired (96.98% : N/A) # Per-chromosome mapped/unmapped read counts samtools idxstats sorted.bam # chr1 248956422 12345678 0 # chr2 242193529 11234567 0 # Comprehensive stats (insert sizes, GC content, base quality) samtools stats -r reference.fa sorted.bam > full_stats.txt grep "^SN" full_stats.txt | cut -f2,3 # Summary Numbers only # Coverage report (min/max/mean per region/chromosome) samtools coverage sorted.bam
bash# Per-base read depth for specific regions samtools depth -b target_regions.bed sorted.bam > depth.txt # Output: chr pos depth (e.g., chr1 1000 45) # Statistics split by read group samtools stats -S RG sorted.bam > per_rg_stats.txt
Filter reads using SAM FLAG bits for specific subsets.
bash# FLAG reference — common masks: # 1 = paired 4 = unmapped # 2 = proper pair 8 = mate unmapped # 16 = reverse strand 64 = R1 (first in pair) # 128 = R2 256= secondary alignment # 1024 = PCR duplicate 2048= supplementary # Extract properly paired, mapped reads (FLAG 2 set, 4 unset) samtools view -f 2 -F 4 sorted.bam -o proper_pairs.bam # Extract R1 reads only samtools view -f 64 sorted.bam -o R1.bam # Remove secondary and supplementary alignments samtools view -F 2304 sorted.bam -o primary.bam # Extract reads from BED file regions samtools view -L regions.bed -b sorted.bam -o regions.bam
Mark or remove PCR duplicates before variant calling.
bash# Full duplicate marking workflow (collate → fixmate → sort → markdup) samtools collate -@ 8 -o collated.bam input.bam samtools fixmate -m -@ 8 collated.bam fixmated.bam samtools sort -@ 8 -o sorted.bam fixmated.bam samtools markdup -@ 8 sorted.bam marked.bam samtools index marked.bam # Check duplication rate samtools flagstat marked.bam | grep "duplicates" # Output: 2345678 + 0 duplicates (4.83%)
bash# NovaSeq optical duplicate detection (2500 pixel distance) samtools markdup -d 2500 sorted.bam marked_novaseq.bam # Remove duplicates instead of marking samtools markdup -r sorted.bam deduped.bam # Get duplication stats without writing output samtools markdup -s sorted.bam /dev/null
Merge BAM files and perform region-level analysis.
bash# Merge multiple BAM files (all must be sorted) samtools merge -@ 8 merged.bam lane1.bam lane2.bam lane3.bam # Merge files listed in a text file (one per line) samtools merge -b bam_list.txt -@ 8 merged.bam # Merge with read group tags from filenames samtools merge -r merged.bam sample1.bam sample2.bam # Extract specific chromosome region from merged output samtools view -h merged.bam chr1 -b -o chr1.bam
FLAGS encode read properties as a sum of bit values. Common filtering patterns:
| Common Filter | -f (require) | -F (exclude) | Selects | |---------------|----------------|----------------|---------| | Mapped reads | — | 4 | All aligned reads | | Proper pairs | 2 | — | Properly paired, both mapped | | Unique primary | — | 2308 | No secondary/supplementary/duplicate | | R1 only | 64 | — | First-in-pair reads | | Unmapped | 4 | — | Failed to align |
| Format | Size | Speed | Requires | |--------|------|-------|---------| | SAM | ~10× BAM | Slow I/O | Nothing | | BAM | 1× | Fast | .bai index for random access | | CRAM | ~0.6× BAM | Slightly slower | Reference FASTA + index |
Use CRAM for long-term storage; BAM for active analysis.
Goal: Convert aligner output to analysis-ready BAM with QC metrics.
bash#!/bin/bash SAMPLE="sample_001" REF="reference.fa" THREADS=8 # 1. Sort and index (aligner often outputs unsorted SAM/BAM) samtools sort -@ $THREADS -o ${SAMPLE}.sorted.bam ${SAMPLE}.bam samtools index ${SAMPLE}.sorted.bam # 2. QC metrics samtools flagstat ${SAMPLE}.sorted.bam > ${SAMPLE}.flagstat.txt samtools stats -r $REF ${SAMPLE}.sorted.bam > ${SAMPLE}.stats.txt samtools coverage ${SAMPLE}.sorted.bam > ${SAMPLE}.coverage.txt # 3. Per-chromosome stats samtools idxstats ${SAMPLE}.sorted.bam > ${SAMPLE}.idxstats.txt echo "QC complete: $(grep 'mapped (' ${SAMPLE}.flagstat.txt | head -1)"
Goal: Prepare BAM for GATK or other variant callers requiring deduplicated input.
bash#!/bin/bash INPUT="aligned.bam" FINAL="deduped.bam" THREADS=8 # Collate → fixmate → sort → markdup samtools collate -@ $THREADS -o collated.bam $INPUT samtools fixmate -m -@ $THREADS collated.bam fixmated.bam samtools sort -@ $THREADS -o sorted.bam fixmated.bam samtools markdup -@ $THREADS -s sorted.bam $FINAL # Clean up intermediates rm collated.bam fixmated.bam sorted.bam # Index and verify samtools index $FINAL samtools flagstat $FINAL | grep "duplic" # Expected: 3-15% duplicates (WGS); 10-30% for amplicon
| Parameter | Command | Default | Range/Options | Effect | |-----------|---------|---------|---------------|--------| | -@ | Most | 0 | 1–N cores | Additional compression/I/O threads | | -m | sort | 768M | e.g., 2G, 4G | Memory per thread for sorting | | -q | view | 0 | 0–60 | Minimum mapping quality filter | | -f | view | 0 | FLAG bits | Include reads with ALL bits set | | -F | view | 0 | FLAG bits | Exclude reads with ANY bit set | | -b | view | — | flag | Output BAM format | | -C | view | — | flag | Output CRAM (requires -T) | | -T | view | — | FASTA path | Reference for CRAM output | | -d | markdup | 0 | 0–2500 | Optical duplicate pixel distance | | -r | markdup | — | flag | Remove duplicates (vs just mark) | | -n | sort | — | flag | Sort by read name instead of position | | -c | index | — | flag | Create CSI index (needed for chr > 512 Mb) |
samtools index requires coordinate-sorted input. Attempting to index an unsorted BAM will fail or produce incorrect results.-@ for all production runs: Most samtools commands are I/O-bound. Adding -@ 8 provides near-linear speedup for compression/decompression with minimal overhead.samtools flagstat runs in seconds and catches alignment failures (low mapping rate, unexpected paired-end rates) before wasting time on downstream steps.samtools markdup directly on coordinate-sorted BAM without fixmate produces incorrect duplicate detection. The mate information added by fixmate -m is essential.-L bed_file for targeted analyses: Restricting samtools view to BED-defined target regions (WES capture, amplicons) dramatically reduces I/O for downstream steps.bash# Process all BAM files in directory for bam in *.sorted.bam; do echo "=== $bam ===" samtools flagstat $bam | grep -E "mapped|properly paired|duplicates" done
bash# Pull both unmapped reads (useful for pathogen detection) samtools view -f 4 -b input.bam -o unmapped.bam samtools fastq -@ 4 -1 unmapped_R1.fastq -2 unmapped_R2.fastq unmapped.bam echo "Unmapped pairs ready for de novo assembly"
bash# Estimate current depth, then subsample to ~30× TOTAL=$(samtools flagstat input.bam | grep "mapped (" | head -1 | awk '{print $1}') GENOME_SIZE=3100000000 # hg38 READ_LEN=150 CURRENT_COV=$(echo "scale=1; $TOTAL * $READ_LEN / $GENOME_SIZE" | bc) TARGET_FRAC=$(echo "scale=3; 30 / $CURRENT_COV" | bc) echo "Current: ${CURRENT_COV}×; subsample fraction: $TARGET_FRAC" samtools view -b -s $TARGET_FRAC input.bam -o downsampled.bam samtools index downsampled.bam
| Problem | Cause | Solution | |---------|-------|----------| | [bam_index_build2] fail to index | BAM not sorted by coordinate | Sort first: samtools sort -o sorted.bam input.bam | | BAI index too large for chromosome | Chromosome > 512 Mbp | Use CSI index: samtools index -c input.bam | | CRAM: reference not found | Missing or wrong reference FASTA | Set REF_PATH env var or use -T ref.fa | | Duplicate marking incorrect | fixmate step skipped | Run full pipeline: collate → fixmate → sort → markdup | | flagstat shows 0% properly paired | Paired-end BAM missing mate info | Run samtools fixmate to populate mate coordinates | | Very slow sorting | Low memory per thread | Increase -m 4G; reduce -@ if memory-limited | | Region query returns nothing | BAM not indexed or wrong coords | Run samtools index; use 1-based coords: chr1:1000-2000 | | [E::hts_open_format] fail to open | File path wrong or BAM corrupt | Verify path; test with samtools quickcheck file.bam |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-04 | fail→pass | 7,910 | 4,755 | -40% | 1 | 1 | 0% | 1,575 | 5,045 | +220% | 0 | 0 | — |
case-01 | pass→pass | 7,877 | 5,482 | -30% | 1 | 1 | 0% | 1,496 | 5,139 | +244% | 0 | 0 | — |
case-02 | pass→pass | 4,449 | 4,231 | -5% | 1 | 1 | 0% | 778 | 4,901 | +530% | 0 | 0 | — |
case-03 | pass→pass | 15,378 | 4,622 | -70% | 1 | 1 | 0% | 2,364 | 4,871 | +106% | 0 | 0 | — |
case-05 | pass→pass | 3,761 | 3,118 | -17% | 1 | 1 | 0% | 609 | 4,671 | +667% | 0 | 0 | — |
case-06 | pass→pass | 4,344 | 3,838 | -12% | 1 | 1 | 0% | 822 | 4,852 | +490% | 0 | 0 | — |
case-07 | pass→pass | 4,418 | 5,134 | +16% | 1 | 1 | 0% | 865 | 4,911 | +468% | 0 | 0 | — |
case-08 | pass→pass | 4,255 | 2,855 | -33% | 1 | 1 | 0% | 776 | 4,668 | +502% | 0 | 0 | — |
case-09 | pass→pass | 5,642 | 3,869 | -31% | 1 | 1 | 0% | 1,127 | 4,604 | +309% | 0 | 0 | — |
case-10 | pass→pass | 8,279 | 3,974 | -52% | 1 | 1 | 0% | 1,571 | 4,878 | +211% | 0 | 0 | — |
case-11 | pass→pass | 4,746 | 2,625 | -45% | 1 | 1 | 0% | 492 | 4,636 | +842% | 0 | 0 | — |
case-12 | pass→pass | 4,953 | 2,553 | -48% | 1 | 1 | 0% | 920 | 4,606 | +401% | 0 | 0 | — |
case-13 | pass→pass | 3,871 | 3,580 | -8% | 1 | 1 | 0% | 806 | 4,753 | +490% | 0 | 0 | — |
case-14 | pass→pass | 3,289 | 2,737 | -17% | 1 | 1 | 0% | 610 | 4,592 | +653% | 0 | 0 | — |
case-15 | pass→pass | 4,417 | 3,808 | -14% | 1 | 1 | 0% | 878 | 4,885 | +456% | 0 | 0 | — |
case-16 | pass→pass | 5,824 | 4,136 | -29% | 1 | 1 | 0% | 1,127 | 4,944 | +339% | 0 | 0 | — |
case-17 | pass→pass | 8,177 | 3,637 | -56% | 1 | 1 | 0% | 1,476 | 4,841 | +228% | 0 | 0 | — |
case-18 | pass→pass | 3,500 | 21,604 | +517% | 1 | 1 | 0% | 666 | 4,809 | +622% | 0 | 0 | — |
case-19 | pass→pass | 6,983 | 4,534 | -35% | 1 | 1 | 0% | 1,340 | 4,956 | +270% | 0 | 0 | — |
case-20 | pass→pass | 8,464 | 4,228 | -50% | 1 | 1 | 0% | 1,056 | 5,028 | +376% | 0 | 0 | — |
case-21 | pass→pass | 3,808 | 3,834 | +1% | 1 | 1 | 0% | 770 | 4,919 | +539% | 0 | 0 | — |
case-22 | pass→pass | 4,890 | 3,131 | -36% | 1 | 1 | 0% | 979 | 4,741 | +384% | 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 +5 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.