Claude Cursor Skill

pipeline-cutandrun

Execute CUT&RUN processing pipeline from FASTQ to peaks and signal tracks. Child of pipeline-guide. Provides Nextflow execution with Docker and cloud deployment. Use when processing CUT&RUN or CUT&Tag data, an alternative to ChIP-seq with lower background. Trigger on: CUT&RUN pip

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download ammawla-encode-toolkit-plugin_skills_pipeline-cutandrun-36836c8.zip · 31 KB
Part of ammawla/encode-toolkit — 90 skills

Install

skills CLI npx skills add https://github.com/ammawla/encode-toolkit/tree/main/plugin/skills/pipeline-cutandrun
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install ammawla-encode-toolkit@llmmart
Git git clone https://github.com/ammawla/encode-toolkit.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole ammawla/encode-toolkit collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

ENCODE CUT&RUN Pipeline: FASTQ to Peaks and Signal Tracks

When to Use

  • User wants to run a CUT&RUN or CUT&Tag processing pipeline from FASTQ to peaks
  • User asks about "CUT&RUN pipeline", "CUT&Tag", "SEACR", "spike-in normalization", or "targeted chromatin"
  • User needs to process CUT&RUN/CUT&Tag data with spike-in calibration and SEACR peak calling
  • Example queries: "process my CUT&RUN FASTQs", "run SEACR on CUT&Tag data", "normalize CUT&RUN with spike-in controls"

Execute the CUT&RUN/CUT&Tag processing pipeline for targeted chromatin profiling, producing peak calls with SEACR and spike-in normalized signal tracks.

Pipeline Overview

FASTQ
  |-> FastQC (raw reads)
  +-> Trim Galore -> Bowtie2 (genome) -> {sample}.sorted.bam
        |
        |-> unmapped read pairs -> Bowtie2 (spike-in) -> counts -> scale_factors.txt
        |                                                                |
        +-> filter (MAPQ 10, proper pairs) -> Picard MarkDuplicates      |
            (removed) -> blacklist filter -> {sample}.filtered.bam       |
                 |-> fragment BED -> fragment bedGraph -> SEACR peaks    |
                 |-> MACS2 peaks (with --peak_caller macs2|both)         |
                 |-> FRiP vs every peak set -> {sample}.frip_mqc.tsv     |
                 +-> bamCoverage -> {sample}.normalized.bw <-- factor ---+

Not run by this workflow

  • Peak-level filtering: --blacklist is applied to the BAM only. Peak files are never filtered afterwards, and there is no separate suspect-list input. Pass a pre-merged blacklist + suspect-list BED as --blacklist, or filter the peak files yourself.
  • Spike-in scaling of the SEACR input: only the bigWig is scaled (bamCoverage --scaleFactor). The fragment bedGraph given to SEACR is unscaled.

ENCODE Repository

  • ENCODE does not publish an official CUT&RUN pipeline. This workflow follows the published CUT&RUN/CUT&Tag processing protocol (Bowtie2, fragment bedGraphs, SEACR) and applies ENCODE conventions for filtering, blacklisting, and QC.
  • Container: built from scripts/Dockerfile in this skill (docker build -t encode-toolkit/pipeline-cutandrun:1.0.0 scripts/); override with --container
  • This skill: Nextflow DSL2 reimplementation for portability

Core Tools and Versions

Versions are those installed by scripts/Dockerfile, which is what the workflow runs.

Tool Version Purpose Citation
Bowtie2 2.5.4 Alignment (genome + spike-in) Langmead & Salzberg 2012
SEACR 1.3 Peak calling (CUT&RUN-specific) Meers et al. 2019
MACS2 2.2.9.1 Alternative peak caller Zhang et al. 2008
Picard 3.1.1 Duplicate marking and removal Broad Institute
samtools 1.19 BAM operations Li et al. 2009
bedtools 2.31.0 Genomic arithmetic Quinlan & Hall 2010
deepTools 3.5.5 Signal track generation Ramirez et al. 2016
Trim Galore 0.6.10 Adapter trimming Krueger (Babraham)
FastQC 0.12.1 Read quality Andrews (Babraham)
MultiQC 1.21 Aggregated QC Ewels et al. 2016

The conda alternative (cutandrun-env.yml) pins the same version of every tool in the table above, but installs no SEACR (only r-base): SEACR is not a conda package, so on that route SEACR_1.3.sh and SEACR_1.3.R must be fetched separately from the SEACR repository.

Key Literature

  1. Skene & Henikoff 2017 - "An efficient targeted nuclease strategy for high-resolution mapping of DNA binding sites" (eLife, ~1,500 citations) DOI: 10.7554/eLife.21856

  2. Meers et al. 2019 - "Peak calling by Sparse Enrichment Analysis for CUT&RUN chromatin profiling" (Epigenetics & Chromatin, ~800 citations) DOI: 10.1186/s13072-019-0287-4

  3. Kaya-Okur et al. 2019 - "CUT&Tag for efficient epigenomic profiling of small samples and single cells" (Nature Communications, ~1,200 citations) DOI: 10.1038/s41467-019-09982-5

  4. Nordin et al. 2023 - "The CUT&RUN suspect list of problematic regions" (Genome Biology) DOI: 10.1186/s13059-023-02960-3

  5. Amemiya et al. 2019 - "The ENCODE Blacklist" (Scientific Reports, ~1,372 citations) DOI: 10.1038/s41598-019-45839-z

Execution

Quick Start (Local)

nextflow run scripts/main.nf \
    -profile local \
    --reads '/data/fastq/*_R{1,2}.fastq.gz' \
    --bowtie2_index '/ref/bowtie2_index/genome' \
    --spikein_index '/ref/bowtie2_ecoli/ecoli' \
    --chrom_sizes '/ref/hg38.chrom.sizes' \
    --blacklist '/ref/hg38-blacklist.v2.bed' \
    --outdir results/ \
    -resume

SLURM HPC

nextflow run scripts/main.nf \
    -profile slurm \
    --container /path/to/pipeline-cutandrun.sif \
    --reads '/data/fastq/*_R{1,2}.fastq.gz' \
    --bowtie2_index '/ref/bowtie2_index/genome' \
    --spikein_index '/ref/bowtie2_ecoli/ecoli' \
    --chrom_sizes '/ref/hg38.chrom.sizes' \
    --blacklist '/ref/hg38-blacklist.v2.bed' \
    --outdir results/ \
    -resume

Cloud (GCP / AWS)

# Google Cloud Batch
nextflow run scripts/main.nf -profile gcp \
    --container us-docker.pkg.dev/<project>/<repo>/pipeline-cutandrun:1.0.0 \
    --gcp_project <project> \
    --gcp_workdir gs://<bucket>/work \
    --reads 'gs://<bucket>/fastq/*_R{1,2}.fastq.gz' \
    --bowtie2_index gs://<bucket>/ref/bowtie2_index/genome \
    --spikein_index gs://<bucket>/ref/bowtie2_ecoli/ecoli \
    --chrom_sizes gs://<bucket>/ref/hg38.chrom.sizes \
    --blacklist gs://<bucket>/ref/hg38-blacklist.v2.bed \
    --outdir gs://<bucket>/results

# AWS Batch
nextflow run scripts/main.nf -profile aws \
    --container <account>.dkr.ecr.<region>.amazonaws.com/pipeline-cutandrun:1.0.0 \
    --aws_queue <job-queue> \
    --aws_workdir s3://<bucket>/work \
    --reads 's3://<bucket>/fastq/*_R{1,2}.fastq.gz' \
    --bowtie2_index s3://<bucket>/ref/bowtie2_index/genome \
    --spikein_index s3://<bucket>/ref/bowtie2_ecoli/ecoli \
    --chrom_sizes s3://<bucket>/ref/hg38.chrom.sizes \
    --blacklist s3://<bucket>/ref/hg38-blacklist.v2.bed \
    --outdir s3://<bucket>/results

--outdir only sets where results are published; Google Batch and AWS Batch stage every task through the work directory, and the workflow stops with an error if it or the project/queue is missing.

Resource Requirements

Step CPUs RAM Time (per sample)
Bowtie2 align (genome) 8 8 GB 30-60 min
Bowtie2 align (spike-in) 4 4 GB 10-20 min
Filter/dedup 4 8 GB 15-30 min
SEACR peaks 2 4 GB 10-20 min
Signal tracks 4 8 GB 15-30 min
Total 8 8 GB 1.5-3 hours

The RAM column is each step's first-attempt request. These processes ask for that much memory per attempt, so a task killed for exceeding it is retried with more (at most two retries, capped by --max_memory). Failures with any other exit status stop the run.

Pipeline Parameters

Parameter Default Description
--reads required Glob pattern to paired FASTQ files
--bowtie2_index required Bowtie2 genome index prefix (every file starting with this prefix is staged)
--spikein_index null Bowtie2 spike-in index prefix (E. coli by convention). When given, signal tracks are spike-in calibrated
--chrom_sizes required Chromosome sizes file
--blacklist required Blacklist BED applied to the BAM. Pass a pre-merged blacklist + CUT&RUN suspect list here if you want both
--outdir ./results Output directory
--seacr_mode stringent SEACR mode: stringent, relaxed, or both
--seacr_norm norm SEACR normalization to the control: norm or non. Only used with --control; without a control the workflow always passes non
--seacr_threshold 0.01 Top fraction of signal kept by SEACR when no --control is given
--control null IgG control BAM, already filtered and deduplicated. Converted to a fragment bedGraph for SEACR and passed as -c to MACS2
--macs2_gsize hs MACS2 effective genome size (hs, mm, or a number)
--peak_caller seacr Peak caller: seacr, macs2, or both
--skip_spikein false Skip spike-in calibration; signal tracks are then RPKM-normalized

Infrastructure parameters (nextflow.config)

Parameter Default Description
--container encode-toolkit/pipeline-cutandrun:1.0.0 Image built from scripts/Dockerfile. Pass a registry image for gcp/aws, or a .sif file for slurm
--max_cpus, --max_memory, --max_time 16, 16.GB, 12.h Upper bounds applied to every process
--slurm_queue, --slurm_account normal, none SLURM partition and account
--gcp_project, --gcp_workdir none (both required for -profile gcp) Google Cloud project and gs:// work directory
--gcp_location, --gcp_disk us-central1, 200.GB Google Batch region and per-task disk
--aws_queue, --aws_workdir none (both required for -profile aws) AWS Batch job queue and s3:// work directory
--aws_region, --aws_cli_path us-east-1, /home/ec2-user/miniconda/bin/aws AWS region, and the AWS CLI path inside the Batch AMI

Output Files

results/
  fastqc/                             # Raw read quality
  trim_galore/                        # Trimmed reads, trimming reports,
                                      #   and FastQC of the trimmed reads
  alignment/
    {sample}.filtered.bam             # Quality-filtered, deduplicated, blacklist-filtered
    {sample}.filtered.bam.bai
    {sample}.dup_metrics.txt          # Picard MarkDuplicates metrics
    {sample}.flagstat.txt             # samtools flagstat on the filtered BAM
  spikein/                            # Only with --spikein_index
    {sample}.spikein_counts.txt       # sample, spike-in read count
    scale_factors.txt                 # One file for the run: sample, spikein_count, scale_factor
  peaks/
    {sample}.seacr.stringent.bed      # SEACR stringent peaks
    {sample}.seacr.relaxed.bed        # With --seacr_mode relaxed or both
    {sample}.macs2_peaks.narrowPeak   # With --peak_caller macs2 or both
  signal/
    {sample}.normalized.bw            # Spike-in scaled, or RPKM without spike-in
    {sample}.fragments.bed            # Fragment BED (same chromosome, <1 kb)
  qc/
    {sample}.fragment_sizes.txt
    {sample}.frip_mqc.tsv             # FRiP, one row per peak set called for the sample
  multiqc/
    multiqc_report.html
  pipeline_info/
    timeline.html
    report.html
    trace.txt

The fragment bedGraph that SEACR consumes is an intermediate and is not published; the published signal/{sample}.fragments.bed is the BED it is built from.

QC Thresholds

This is the only QC threshold table for this skill; the reference files point back to it.

Metric Pass Warning Fail Computed from
Mapping rate (genome) >80% 60-80% <60% Bowtie2 log (in multiqc_report.html)
Spike-in reads 1-10% of total 0.1-1% or 10-30% <0.1% or >30% spikein/{sample}.spikein_counts.txt
Duplication rate <20% 20-40% >40% alignment/{sample}.dup_metrics.txt
FRiP (peaks) >10% 5-10% <5% qc/{sample}.frip_mqc.tsv (also a MultiQC table)
Peak count >5,000 1,000-5,000 <1,000 peaks/{sample}.seacr.*.bed
Fragment size Nucleosomal pattern Irregular No pattern qc/{sample}.fragment_sizes.txt

Fragment Size Distribution

CUT&RUN produces a characteristic nucleosomal ladder:

  • <120 bp: Sub-nucleosomal (TF binding)
  • ~150 bp: Mononucleosomal (histone marks)
  • ~300 bp: Dinucleosomal
  • Absence of nucleosomal pattern suggests protocol issues

Spike-in Normalization

Spike-in normalization is CRITICAL for CUT&RUN quantitative comparison.

How It Works

    1. coli DNA is carried over from pA-MNase/pA-Tn5 production
  1. Each sample has a different amount of spike-in reads
  2. Samples with more target cleavage have fewer spike-in reads (proportionally)
  3. Scale factor = smallest non-zero spike-in count across samples / this sample's count

Scale Factor Calculation

With three samples whose spike-in counts are 200,000, 400,000 and 100,000, the minimum is 100,000:

Sample A: 200,000 spike-in reads -> scale = 100,000 / 200,000 = 0.5
Sample B: 400,000 spike-in reads -> scale = 100,000 / 400,000 = 0.25
Sample C: 100,000 spike-in reads -> scale = 100,000 / 100,000 = 1.0 (minimum)

Higher spike-in counts = less target enrichment = lower scale factor.

All samples are written to one spikein/scale_factors.txt (columns: sample, spike-in count, scale factor). A sample with no spike-in reads cannot be calibrated and is left unscaled (factor 1). The factor is applied only to the bigWig via bamCoverage --scaleFactor; the fragment bedGraph SEACR reads is unscaled.

SEACR vs MACS2

Feature SEACR MACS2
Designed for CUT&RUN/CUT&Tag ChIP-seq
Background model Sparse enrichment Dynamic Poisson
Control required Optional (IgG) Recommended
Low background Handles well May overcall
Stringent mode Very conservative Via q-value
ENCODE recommendation Primary for CUT&RUN Alternative

SEACR is specifically designed for the sparse, low-background signal profile of CUT&RUN data. MACS2 may overcall peaks due to the low background.

Critical Pitfalls

Spike-in Calibration is CRITICAL

Without spike-in normalization, quantitative comparisons between samples are unreliable. The amount of pA-MNase (or pA-Tn5) varies between experiments, and spike-in reads provide the internal calibration standard. Without --spikein_index (or with --skip_spikein) the bigWigs fall back to RPKM, which is not quantitatively comparable across samples.

IgG Control vs No-Antibody Control

  • IgG control: Non-specific antibody, captures background binding
  • No-antibody: No antibody, captures MNase accessibility background
  • IgG is preferred but not always available
  • SEACR can work without a control: it then uses --seacr_threshold (default 0.01, the top 1% of signal) and, as SEACR v1.3 requires with a numeric threshold, the non normalization mode

SEACR Stringent vs Relaxed Mode

  • Stringent: Returns only the most enriched peaks (fewer, higher confidence)
  • Relaxed: Returns a broader set including weaker peaks
  • For initial analysis, use stringent mode (the default)
  • For comprehensive catalogs, use --seacr_mode both and filter downstream

CUT&RUN Suspect List (Nordin 2023)

The workflow applies --blacklist to the BAM only; it never filters the peak files and takes no separate suspect list. To use the CUT&RUN suspect list (Nordin et al. 2023), which identifies regions with artifactual signal specific to CUT&RUN/CUT&Tag protocols, either pass a merged BED as --blacklist or filter the peaks afterwards yourself:

# Download suspect list
wget https://github.com/Boyle-Lab/Blacklist/raw/master/lists/CUTandRUN.suspectlist.hg38.bed.gz

# Option 1: merge once and pass as --blacklist (filters the BAM)
zcat CUTandRUN.suspectlist.hg38.bed.gz | cat hg38-blacklist.v2.bed - \
    | sort -k1,1 -k2,2n | bedtools merge > combined_blacklist.bed

# Option 2: filter the published peaks afterwards (manual)
bedtools intersect \
    -a results/peaks/sample.seacr.stringent.bed \
    -b combined_blacklist.bed \
    -v \
    > sample_peaks_filtered.bed

CUT&RUN vs CUT&Tag

Both protocols are supported by this pipeline. Differences:

  • CUT&RUN: Uses pA-MNase, E. coli spike-in from MNase production
  • CUT&Tag: Uses pA-Tn5, E. coli spike-in from Tn5 production
  • CUT&Tag has higher background from Tn5 insertion preference
  • CUT&Tag may work better for histone marks; CUT&RUN for TFs

Provenance Integration

After pipeline completion, log all outputs:

encode_log_derived_file(
    file_path="/results/peaks/sample1.seacr.stringent.bed",
    source_accessions=["ENCSR...", "ENCFF..."],
    description="CUT&RUN peaks from ENCODE CUT&RUN pipeline",
    file_type="CUT&RUN_peaks",
    tool_used="Bowtie2 2.5.4 + SEACR 1.3",
    parameters="stringent mode, threshold 0.01 non, BAM blacklist-filtered (peaks unfiltered)"
)

Reference Files

Detailed step-by-step documentation is provided in the references/ directory:

  1. 01-qc-trimming.md -- Read QC and adapter trimming for CUT&RUN
  2. 02-bowtie2-alignment.md -- Bowtie2 alignment to genome and spike-in
  3. 03-filtering-spikein.md -- Filtering, dedup, and spike-in normalization
  4. 04-seacr-peaks.md -- SEACR peak calling and MACS2 alternative
  5. 05-qc-metrics.md -- Fragment sizes, FRiP, spike-in QC

Walkthrough: Processing ENCODE CUT&RUN from FASTQ to Peaks

Goal: Process CUT&RUN/CUT&Tag FASTQ files through the ENCODE-compatible pipeline to generate peak calls with spike-in normalization. Context: CUT&RUN uses targeted MNase digestion (lower background than ChIP-seq) but requires different peak calling (SEACR instead of MACS2) and spike-in normalization for quantitative comparisons.

Step 1: Find CUT&RUN experiment

encode_search_experiments(assay_title="CUT&RUN", organism="Homo sapiens")

Expected output:

{
  "results": [
    {"accession": "ENCSR900CUR", "assay_title": "CUT&RUN", "target": "H3K27me3", "biosample_summary": "K562", "assembly": ["GRCh38"], "status": "released"}
  ],
  "total": 35,
  "limit": 25,
  "offset": 0,
  "has_more": true,
  "next_offset": 25
}

Step 2: List FASTQ files

encode_list_files(experiment_accession="ENCSR900CUR", file_format="fastq")

Expected output (a JSON array of file records; fields abridged):

[
  {"accession": "ENCFF900CR1", "file_format": "fastq", "output_type": "reads", "biological_replicates": [1], "file_size": 839252000, "file_size_human": "800.4 MB", "status": "released"},
  {"accession": "ENCFF901CR2", "file_format": "fastq", "output_type": "reads", "biological_replicates": [1], "file_size": 891394000, "file_size_human": "850.1 MB", "status": "released"}
]

Interpretation: CUT&RUN yields smaller files than ChIP-seq (~800MB vs ~2.5GB) due to lower background.

Step 3: Name the files so a read-pair glob can find them

ENCODE FASTQs are named by accession, so the two mates of a pair share no prefix, and the workflow matches file pairs with a {1,2} glob. Which mate a file is comes from its page on encodeproject.org (paired_end 1 or 2, and paired_with naming the other accession), not from any tool here. Link the files into the shape the glob expects:

mkdir -p fastq
ln -s "$PWD/ENCFF900CR1.fastq.gz" fastq/ENCSR900CUR_R1.fastq.gz
ln -s "$PWD/ENCFF901CR2.fastq.gz" fastq/ENCSR900CUR_R2.fastq.gz

Step 4: Run the CUT&RUN pipeline

nextflow run scripts/main.nf \
  -profile local \
  --reads 'fastq/ENCSR900CUR_R{1,2}.fastq.gz' \
  --bowtie2_index '/ref/bowtie2_index/genome' \
  --spikein_index '/ref/bowtie2_ecoli/ecoli' \
  --chrom_sizes '/ref/hg38.chrom.sizes' \
  --blacklist '/ref/hg38-blacklist.v2.bed' \
  --peak_caller seacr \
  --outdir results/ \
  -resume

Key pipeline steps:

  1. FastQC on the raw reads, then adapter trimming (Trim Galore, --nextera)
  2. Bowtie2 alignment (--very-sensitive --no-mixed --no-discordant --dovetail -I 10 -X 700)
  3. Spike-in alignment of the read pairs that did not map to the genome
  4. Scale factor per sample (minimum spike-in count / sample count)
  5. Filter (MAPQ 10, proper pairs), remove duplicates with Picard, remove blacklist regions
  6. SEACR peak calling from the fragment bedGraph (stringent by default)
  7. Signal bigWig with bamCoverage, scaled by the spike-in factor
  8. FRiP of the filtered BAM against every peak set called for the sample, written to qc/{sample}.frip_mqc.tsv

Step 5: Validate output quality

Use the QC threshold table above with alignment/{sample}.dup_metrics.txt, spikein/{sample}.spikein_counts.txt, qc/{sample}.fragment_sizes.txt and qc/{sample}.frip_mqc.tsv.

Key difference from ChIP-seq: CUT&RUN has inherently lower background, so peak callers like MACS2 overfit. Use SEACR (Meers et al. 2019) instead.

Step 6: Compare with ChIP-seq for the same target

encode_search_experiments(assay_title="Histone ChIP-seq", biosample_term_name="K562", target="H3K27me3", organism="Homo sapiens")

Interpretation: CUT&RUN typically identifies fewer but higher-confidence peaks than ChIP-seq. Concordant peaks between both methods are the highest confidence.

Integration with downstream skills

  • SEACR peaks feed into -> histone-aggregation for cross-experiment comparison
  • Spike-in normalized signals feed into -> visualization-workflow
  • Peak regions feed into -> regulatory-elements for chromatin state classification
  • QC uses different thresholds than ChIP-seq -> quality-assessment (see suspect list)
  • Pipeline provenance logged by -> data-provenance

Code Examples

1. Survey CUT&RUN/CUT&Tag availability

encode_get_facets(assay_title="CUT&RUN", organism="Homo sapiens")

Expected output:

{
  "target.label": [
    {"term": "H3K27me3", "count": 15},
    {"term": "H3K4me3", "count": 12},
    {"term": "H3K27ac", "count": 8},
    {"term": "CTCF", "count": 5}
  ]
}

2. Find matching ChIP-seq for comparison

encode_search_experiments(assay_title="Histone ChIP-seq", biosample_term_name="K562", target="H3K27me3", organism="Homo sapiens")

Expected output:

{
  "results": [
    {"accession": "ENCSR000CHI", "assay_title": "Histone ChIP-seq", "target": "H3K27me3", "biosample_summary": "K562", "assembly": ["GRCh38"]}
  ],
  "total": 5,
  "limit": 25,
  "offset": 0,
  "has_more": false,
  "next_offset": null
}

3. Track CUT&RUN experiments

encode_track_experiment(accession="ENCSR900CUR", notes="K562 H3K27me3 CUT&RUN - SEACR peaks for comparison with ChIP-seq")

Expected output:

{
  "tracking": {
    "accession": "ENCSR900CUR",
    "action": "tracked"
  },
  "publications_found": 0,
  "publications": [],
  "pipelines_found": 0,
  "pipelines": []
}

Integration

This skill produces... Feed into... Purpose
SEACR peaks histone-aggregation Cross-experiment comparison (note: different caller than ChIP-seq)
Spike-in normalized signal visualization-workflow Quantitatively comparable browser tracks
Peak regions regulatory-elements Chromatin state classification
CUT&RUN-specific QC quality-assessment Validate with CUT&RUN-appropriate thresholds
Peak coordinates motif-analysis TF motif discovery at CUT&RUN peaks
Pipeline parameters data-provenance Record SEACR/spike-in normalization details
Peak files variant-annotation Identify variants in CUT&RUN peaks
Comparison with ChIP-seq compare-biosamples Cross-assay concordance analysis

Related Skills

  • pipeline-guide -- Parent skill with compute resource assessment and cloud setup
  • histone-aggregation -- Aggregate histone mark data across samples
  • quality-assessment -- Evaluate pipeline output quality metrics
  • data-provenance -- Track all pipeline inputs, outputs, and parameters
  • download-encode -- Download ENCODE CUT&RUN FASTQ files for pipeline input
  • publication-trust -- Verify literature claims backing analytical decisions

Presenting Results

When reporting CUT&RUN pipeline results:

  • SEACR peak counts: Report peak counts for each SEACR mode that was run (default: stringent only; both with --seacr_mode both). If MACS2 was also run, include those counts for comparison
  • Spike-in normalization factor: Report the scale factor and spike-in count per sample from spikein/scale_factors.txt and the spike-in read fraction (ideal 1-10% of total reads). Explain that higher spike-in counts indicate less target enrichment
  • FRiP: Report it from qc/{sample}.frip_mqc.tsv, which has one row per peak set called for the sample (SEACR stringent and/or relaxed, and/or MACS2), and judge each against the QC table (>10% pass, 5-10% warning, <5% fail). The value is the fraction of the filtered BAM's alignments that overlap a peak, so mates of a pair count separately; the Peak set column names the peak file each row refers to
  • Signal track paths: Provide paths to the signal/{sample}.normalized.bw files (spike-in scaled, or RPKM if spike-in was skipped) for genome browser visualization
  • Fragment size distribution: From qc/{sample}.fragment_sizes.txt, confirm the expected nucleosomal ladder pattern and note the dominant fragment class (sub-nucleosomal for TFs, mononucleosomal for histone marks)
  • Key QC metrics: Present mapping rate (>80%), duplication rate (<20%), and spike-in calibration status in a summary table
  • Blacklist filtering: State that --blacklist was applied to the BAM and that the peak files are unfiltered; note separately whether a suspect list was merged into --blacklist or applied to the peaks manually
  • Next steps: Suggest peak-annotation for gene association of peaks, or visualization-workflow for genome browser session generation

For the request: "$ARGUMENTS"

Files (encode-toolkit)
  • references
    • 01-qc-trimming.md 2.9 KB
      # QC and Trimming for CUT&RUN Data
      
      CUT&RUN produces paired-end reads with a characteristic nucleosomal fragment
      size distribution. Reads are typically shorter than ChIP-seq due to the
      MNase cleavage mechanism.
      
      ## Pre-Trimming QC with FastQC
      
      ```bash
      fastqc --threads 4 --outdir fastqc_raw/ sample_R1.fastq.gz sample_R2.fastq.gz
      ```
      
      Key checks:
      - Per-base quality (expect Phred >28)
      - Adapter content (Nextera or Illumina universal adapter)
      - Insert size (CUT&RUN fragments are often <150 bp, causing adapter read-through)
      - Sequence duplication (moderate levels expected with low input)
      
      **Note**: CUT&RUN libraries from low cell input often show higher duplication
      than ChIP-seq. This is expected and not necessarily a quality issue.
      
      ## Adapter Trimming with Trim Galore
      
      CUT&RUN fragments are often shorter than read length, causing adapter
      read-through. Aggressive adapter trimming is important.
      
      ```bash
      trim_galore \
          --paired \
          --quality 20 \
          --phred33 \
          --length 20 \
          --cores 4 \
          --fastqc \
          --nextera \
          --output_dir trim_galore/ \
          sample_R1.fastq.gz \
          sample_R2.fastq.gz
      ```
      
      ### Parameter Rationale
      
      | Parameter | Value | Reason |
      |-----------|-------|--------|
      | `--quality 20` | Phred 20 | Standard quality cutoff |
      | `--length 20` | 20 bp | Keep short sub-nucleosomal fragments |
      | `--nextera` | Flag | CUT&RUN often uses Nextera adapters (check protocol) |
      | `--cores 4` | 4 | Parallel processing |
      
      ### Adapter Type Selection
      
      Check which adapter was used in library preparation:
      - **Nextera**: Most CUT&Tag protocols (use `--nextera` flag)
      - **Illumina TruSeq**: Some CUT&RUN protocols (default Trim Galore detection)
      - If unsure, let Trim Galore auto-detect (omit `--nextera`)
      
      ## Post-Trimming Verification
      
      After trimming, verify:
      - >90% of reads pass quality filter
      - Adapter contamination removed (often 20-50% for CUT&RUN)
      - Read length distribution: 20-150 bp (many short reads are expected)
      
      High adapter contamination rate (>30%) is NORMAL for CUT&RUN because
      many fragments are shorter than the read length.
      
      ## Fragment Size Check (Post-Alignment)
      
      After alignment, verify the fragment size distribution:
      
      ```bash
      samtools view -f 2 -F 1804 sample.bam | \
          awk '{if($9 > 0) print $9}' | \
          sort -n | uniq -c | \
          awk '{print $2, $1}' > fragment_sizes.txt
      ```
      
      Expected CUT&RUN fragment distribution:
      - **TF targets**: Peak at <120 bp (sub-nucleosomal)
      - **Histone marks**: Strong peak at ~150 bp (mononucleosomal)
      - **Both**: Should show nucleosomal ladder pattern
      - Broad smear with no peaks suggests protocol failure
      
      ## CUT&Tag vs CUT&RUN Trimming
      
      CUT&Tag uses Tn5 transposase which adds 19 bp Mosaic End (ME) sequences.
      For CUT&Tag data specifically:
      
      ```bash
      trim_galore \
          --paired \
          --quality 20 \
          --length 20 \
          --cores 4 \
          --nextera \
          --fastqc \
          sample_R1.fastq.gz \
          sample_R2.fastq.gz
      ```
      
      The `--nextera` flag is especially important for CUT&Tag since Tn5 inserts
      Nextera-compatible adapters.
      
    • 02-bowtie2-alignment.md 3.9 KB
      # Bowtie2 Alignment for CUT&RUN (Genome + Spike-in)
      
      CUT&RUN uses Bowtie2 for alignment with specific settings optimized for the
      short, paired-end fragments produced by MNase or Tn5 cleavage. Two separate
      alignments are required: one to the target genome and one to the E. coli
      spike-in genome.
      
      ## Genome Index Preparation
      
      ```bash
      # Target genome (one-time)
      bowtie2-build --threads 8 genome.fa genome_index
      
      # E. coli spike-in genome (one-time)
      # Use E. coli K12 MG1655 (GenBank: U00096.3)
      bowtie2-build --threads 4 ecoli_K12.fa ecoli_index
      ```
      
      ## Target Genome Alignment
      
      ```bash
      bowtie2 \
          --very-sensitive \
          --no-mixed \
          --no-discordant \
          --dovetail \
          --phred33 \
          -I 10 -X 700 \
          --threads 8 \
          -x genome_index \
          -1 sample_R1_val_1.fq.gz \
          -2 sample_R2_val_2.fq.gz \
          2> sample_bowtie2.log \
          | samtools view -@ 4 -bS - \
          | samtools sort -@ 4 -o sample_sorted.bam
      
      samtools index sample_sorted.bam
      ```
      
      ### Bowtie2 Parameters for CUT&RUN
      
      | Parameter | Value | Reason |
      |-----------|-------|--------|
      | `--very-sensitive` | Preset | Maximum sensitivity for short fragments |
      | `--no-mixed` | Flag | Both mates must align |
      | `--no-discordant` | Flag | Mates must be properly paired |
      | `--dovetail` | Flag | Allow dovetail alignments (overlapping PE reads) |
      | `-I 10` | 10 bp | Minimum insert size (very short fragments exist) |
      | `-X 700` | 700 bp | Maximum insert size |
      
      **Critical**: The `--dovetail` flag is essential because CUT&RUN fragments
      are often shorter than read length, causing R1 and R2 to extend past each
      other (dovetailing).
      
      ## Spike-in Alignment
      
      Align reads that did NOT map to the target genome to the E. coli spike-in:
      
      ```bash
      # Extract unmapped reads from genome alignment
      samtools view -b -f 12 -F 256 sample_sorted.bam \
          | samtools sort -@ 4 -n -o unmapped_sorted.bam
      
      bedtools bamtofastq -i unmapped_sorted.bam \
          -fq unmapped_R1.fq -fq2 unmapped_R2.fq
      
      # Align to E. coli
      bowtie2 \
          --very-sensitive \
          --no-mixed \
          --no-discordant \
          --dovetail \
          --phred33 \
          -I 10 -X 700 \
          --threads 4 \
          -x ecoli_index \
          -1 unmapped_R1.fq \
          -2 unmapped_R2.fq \
          2> sample_spikein.log \
          | samtools view -@ 2 -bS -q 10 -F 1804 -f 2 - \
          | samtools sort -@ 2 -o sample_spikein.bam
      
      samtools index sample_spikein.bam
      ```
      
      ### Alternative: Direct Spike-in Alignment
      
      Some workflows align ALL reads to both genomes simultaneously using a
      concatenated index. This is simpler but less precise:
      
      ```bash
      # Concatenate genomes (one-time)
      cat genome.fa ecoli_K12.fa > combined.fa
      bowtie2-build --threads 8 combined.fa combined_index
      
      # Align to combined genome
      bowtie2 --very-sensitive --no-mixed --no-discordant --dovetail \
          -I 10 -X 700 --threads 8 \
          -x combined_index \
          -1 R1.fq.gz -2 R2.fq.gz \
          | samtools view -bS - > combined.bam
      
      # Separate by genome
      samtools view -b combined.bam chr1 chr2 ... chrX chrY > genome.bam
      samtools view -b combined.bam ecoli_chr > spikein.bam
      ```
      
      ## Spike-in Read Counts
      
      ```bash
      # Count spike-in reads
      spikein_count=$(samtools view -c -F 1804 -f 2 sample_spikein.bam)
      genome_count=$(samtools view -c -F 1804 -f 2 sample_sorted.bam)
      echo "Spike-in reads: ${spikein_count}"
      echo "Genome reads: ${genome_count}"
      echo "Spike-in fraction: $(echo "scale=4; $spikein_count / ($spikein_count + $genome_count)" | bc)"
      ```
      
      Expected spike-in fraction:
      - **1-10%**: Optimal range for normalization
      - **<0.1%**: Too few spike-in reads for reliable normalization
      - **>30%**: Excessive spike-in; may indicate poor target enrichment
      
      ## Alignment QC
      
      ```bash
      # Parse Bowtie2 log for mapping rate
      grep "overall alignment rate" sample_bowtie2.log
      ```
      
      Expected mapping rates:
      - **Target genome**: >80% for standard samples
      - **Spike-in**: spike-in reads should be 1-10% of all reads (spike-in / (spike-in + genome), as computed above)
      
      Low genome mapping rate may indicate:
      - Contamination (check FastQ Screen)
      - Wrong genome build
      - Very poor library quality
      
    • 03-filtering-spikein.md 5 KB
      # Filtering, Deduplication, and Spike-in Normalization
      
      CUT&RUN data processing requires standard quality filtering, duplicate removal,
      blacklist filtering, AND spike-in normalization for quantitative analysis.
      
      ## Quality Filtering
      
      ```bash
      samtools view -b -h \
          -q 10 \
          -F 1804 \
          -f 2 \
          sample_sorted.bam \
          | samtools sort -@ 4 -o sample_filtered.bam
      ```
      
      ### Filter Parameters
      
      | Flag | Meaning |
      |------|---------|
      | `-q 10` | MAPQ >= 10 (CUT&RUN uses lower threshold than ChIP-seq) |
      | `-F 4` | Remove unmapped |
      | `-F 256` | Remove secondary |
      | `-F 512` | Remove QC-fail |
      | `-F 1024` | Remove duplicates -- a no-op here; duplicates are removed by Picard in the next step |
      | `-f 2` | Keep properly paired only |
      
      **Note**: MAPQ 10 instead of 30 for CUT&RUN. The lower threshold retains
      more signal because CUT&RUN targets can be in repetitive regions.
      
      ## Duplicate Marking
      
      ```bash
      picard MarkDuplicates \
          INPUT=sample_filtered.bam \
          OUTPUT=sample_dedup.bam \
          METRICS_FILE=sample_dup_metrics.txt \
          REMOVE_DUPLICATES=true \
          VALIDATION_STRINGENCY=LENIENT \
          ASSUME_SORTED=true
      
      samtools index sample_dedup.bam
      ```
      
      CUT&RUN from low cell numbers may have higher duplication. Accept up to 40%.
      
      ## Blacklist Filtering
      
      The workflow filters the BAM against the single file given as `--blacklist`
      and stops there: peak files are never filtered, and there is no separate
      suspect-list parameter.
      
      ```bash
      # What the workflow runs, with --blacklist as -b
      bedtools intersect \
          -a sample_dedup.bam \
          -b hg38-blacklist.v2.bed \
          -v \
          > sample_final.bam
      
      samtools index sample_final.bam
      ```
      
      To also exclude the CUT&RUN-specific suspect list (Nordin 2023) -- ~400
      regions enriched in CUT&RUN controls that produce false positive peaks,
      independent of the ENCODE blacklist -- merge the two files once and pass the
      result as `--blacklist`:
      
      ```bash
      cat hg38-blacklist.v2.bed CUTandRUN.suspectlist.hg38.bed \
          | sort -k1,1 -k2,2n | bedtools merge > combined_blacklist.bed
      ```
      
      ## Spike-in Normalization
      
      ### Calculate Scale Factors
      
      The workflow writes one count file per sample
      (`spikein/{sample}.spikein_counts.txt`, columns sample and count) and then one
      combined `spikein/scale_factors.txt` for the whole run:
      
      ```bash
      # Per-sample counts, concatenated
      cat *.spikein_counts.txt > all_counts.txt
      
      # Scale every sample to the smallest non-zero count (factor = min / count).
      # A sample with no spike-in reads is left unscaled (factor 1).
      min_count=$(awk -F'\t' '$2 > 0 {print $2}' all_counts.txt | sort -n | head -1)
      
      awk -F'\t' -v min="${min_count:-0}" 'BEGIN {OFS="\t"} {
          factor = ($2 > 0 && min > 0) ? min / $2 : 1
          print $1, $2, factor
      }' all_counts.txt > scale_factors.txt
      ```
      
      ### Apply Spike-in Scaling to Signal
      
      The workflow scales the bigWig only, with deepTools:
      
      ```bash
      # Read scale factor for one sample
      scale=$(awk -F'\t' -v s="sample1" '$1==s {print $3}' scale_factors.txt)
      
      bamCoverage \
          --bam sample_final.bam \
          --outFileName sample_normalized.bw \
          --scaleFactor ${scale} \
          --binSize 10 \
          --normalizeUsing None \
          --extendReads \
          --numberOfProcessors 4
      ```
      
      Without a spike-in index the workflow drops `--scaleFactor` and uses
      `--normalizeUsing RPKM` instead.
      
      ### Alternative: bedGraph route (not used by the workflow)
      
      ```bash
      bedtools genomecov \
          -ibam sample_final.bam \
          -bg \
          -pc \
          -scale ${scale} \
          -g hg38.chrom.sizes \
          | sort -k1,1 -k2,2n > sample_normalized.bedGraph
      
      bedGraphToBigWig sample_normalized.bedGraph hg38.chrom.sizes sample_normalized.bw
      ```
      
      ## Generate Fragment BED File
      
      SEACR takes a fragment bedGraph, built from a fragment BED. `bedtools
      bamtobed -bedpe` needs mates on adjacent lines, so name-sort the BAM first --
      on a coordinate-sorted BAM it warns per read that the mate does not occur next
      to it and emits a near-empty BED:
      
      ```bash
      # Name-sort first
      samtools sort -n -@ 2 -o namesorted.bam sample_final.bam
      
      # Keep properly paired fragments on one chromosome and shorter than 1 kb
      bedtools bamtobed -bedpe -i namesorted.bam \
          | awk 'BEGIN {OFS="\t"} $1 == $4 && $6 - $2 < 1000 {print $1, $2, $6}' \
          | sort -k1,1 -k2,2n -k3,3n \
          > sample.fragments.bed
      
      # Fragment bedGraph for SEACR -- deliberately unscaled
      bedtools genomecov \
          -i sample.fragments.bed \
          -g hg38.chrom.sizes \
          -bg \
          > sample_fragments.bedGraph
      ```
      
      The workflow does not apply the spike-in factor here: SEACR sees unscaled
      fragment coverage, and only the bigWig is calibrated. The BED is published as
      `signal/{sample}.fragments.bed`; the bedGraph is an intermediate.
      
      ## QC Statistics
      
      ```bash
      # Final read count
      echo "Final reads: $(samtools view -c sample_final.bam)"
      
      # Flagstat (the workflow publishes this as alignment/{sample}.flagstat.txt)
      samtools flagstat sample_final.bam > sample_flagstat.txt
      
      # Spike-in fraction; the spike-in BAM is an intermediate, so read the
      # published count file instead
      genome=$(samtools view -c -F 1804 -f 2 sample_final.bam)
      spikein=$(cut -f2 spikein/sample.spikein_counts.txt)
      echo "Spike-in fraction: $(echo "scale=4; $spikein / ($genome + $spikein)" | bc)"
      ```
      
    • 04-seacr-peaks.md 5 KB
      # SEACR Peak Calling for CUT&RUN
      
      SEACR (Sparse Enrichment Analysis for CUT&RUN) is specifically designed for
      the sparse, low-background signal profile of CUT&RUN data. It outperforms
      MACS2 on CUT&RUN data because it does not assume a Poisson background model.
      
      ## SEACR with IgG Control
      
      When an IgG control is available:
      
      ```bash
      SEACR_1.3.sh \
          sample_fragments.bedGraph \
          control_IgG_fragments.bedGraph \
          norm \
          stringent \
          sample_seacr
      ```
      
      ### Parameters
      
      | Argument | Value | Description |
      |----------|-------|-------------|
      | Arg 1 | sample bedGraph | Treatment signal (fragment coverage) |
      | Arg 2 | control bedGraph | IgG/no-antibody control signal |
      | Arg 3 | `norm` | Normalize control to treatment depth |
      | Arg 4 | `stringent` | Stringent mode (conservative peaks) |
      | Arg 5 | output prefix | Output file prefix |
      
      ## SEACR without Control (Top %)
      
      When no control is available, SEACR uses a numeric threshold:
      
      ```bash
      SEACR_1.3.sh \
          sample_fragments.bedGraph \
          0.01 \
          non \
          stringent \
          sample_seacr_noctrl
      ```
      
      `non` is required here: the SEACR v1.3 README states that a numeric threshold
      must be paired with `non`. The v1.3 script does not error on `norm` -- it
      silently skips normalization -- so the mistake is invisible. The workflow
      always passes `non` when there is no `--control`.
      
      The `0.01` value means the top 1% of signal is used as the enrichment threshold.
      Adjust based on expected peak count:
      - `0.01` (1%): Conservative, fewer peaks
      - `0.05` (5%): Moderate
      - `0.10` (10%): Permissive, more peaks
      
      ## SEACR Stringent vs Relaxed
      
      Run both modes to compare:
      
      ```bash
      # Stringent: Only peaks that pass both global and local enrichment
      SEACR_1.3.sh sample.bedGraph control.bedGraph norm stringent sample_stringent
      
      # Relaxed: Peaks passing global enrichment threshold only
      SEACR_1.3.sh sample.bedGraph control.bedGraph norm relaxed sample_relaxed
      ```
      
      | Mode | Description | Typical Peak Count |
      |------|-------------|-------------------|
      | Stringent | Global AND local enrichment | 5,000-20,000 |
      | Relaxed | Global enrichment only | 10,000-50,000 |
      
      ## SEACR Output Format
      
      SEACR v1.3 outputs a 6-column BED-like file:
      
      ```
      chr1  1000  2000  500.5  8.2  chr1:1450-1480
      ```
      
      Columns:
      1. Chromosome
      2. Peak start
      3. Peak end
      4. Total signal in the peak (AUC)
      5. Max signal in the peak
      6. Region of maximum signal, as `chr:start-end`
      
      The workflow names these files `{sample}.seacr.stringent.bed` and, with
      `--seacr_mode relaxed` or `both`, `{sample}.seacr.relaxed.bed`, published to
      `peaks/`.
      
      ## Alternative: MACS2 Peak Calling
      
      MACS2 can be used as an alternative or validation:
      
      ```bash
      macs2 callpeak \
          -t sample_final.bam \
          -c control_IgG.bam \
          -f BAMPE \
          -g hs \
          -n sample_macs2 \
          --nomodel \
          --keep-dup all \
          -q 0.05 \
          --outdir macs2_peaks/
      ```
      
      ### MACS2 Parameters for CUT&RUN
      
      | Parameter | Value | Reason |
      |-----------|-------|--------|
      | `-f BAMPE` | Paired-end | Use fragment information |
      | `--nomodel` | Skip model | CUT&RUN fragments don't follow ChIP model |
      | `--keep-dup all` | Keep all | Duplicates already removed |
      | `-q 0.05` | FDR 0.05 | Standard threshold |
      
      **Caution**: MACS2 may overcall peaks on CUT&RUN data due to the low
      background. Compare with SEACR results and use the intersection for
      high-confidence peaks.
      
      ## Blacklist + Suspect List Filtering (manual, not run by this workflow)
      
      The workflow applies `--blacklist` to the BAM only and never filters peak
      files. To filter the published peaks against both the blacklist and the
      CUT&RUN suspect list, run this yourself:
      
      ```bash
      bedtools intersect \
          -a results/peaks/sample.seacr.stringent.bed \
          -b hg38-blacklist.v2.bed CUTandRUN.suspectlist.hg38.bed \
          -v \
          > sample_peaks_filtered.bed
      ```
      
      ## Peak Overlap Between Callers
      
      When using both SEACR and MACS2, assess concordance:
      
      ```bash
      # Convert SEACR to 3-column BED
      cut -f1-3 results/peaks/sample.seacr.stringent.bed > seacr_peaks.bed
      cut -f1-3 results/peaks/sample.macs2_peaks.narrowPeak > macs2_peaks.bed
      
      # Overlap
      bedtools intersect -a seacr_peaks.bed -b macs2_peaks.bed -u | wc -l
      total_seacr=$(wc -l < seacr_peaks.bed)
      total_macs2=$(wc -l < macs2_peaks.bed)
      echo "SEACR peaks: $total_seacr"
      echo "MACS2 peaks: $total_macs2"
      ```
      
      Typical overlap: 60-80% of SEACR peaks overlap MACS2 peaks.
      High-confidence set: intersection of both callers.
      
      ## FRiP Calculation
      
      The FRIP process runs this for every peak set called for a sample and writes
      the results to `qc/{sample}.frip_mqc.tsv`:
      
      ```bash
      total_reads=$(samtools view -c results/alignment/sample.filtered.bam)
      reads_in_peaks=$(bedtools intersect \
          -u \
          -a results/alignment/sample.filtered.bam \
          -b results/peaks/sample.seacr.stringent.bed \
          | samtools view -c -)
      awk -v a="$reads_in_peaks" -v b="$total_reads" 'BEGIN { printf "FRiP: %.4f\n", a / b }'
      ```
      
      Both counts are alignments, with no flag filter, so mates count separately.
      Judge the result against the QC table in `SKILL.md`; see
      `05-qc-metrics.md` for the published file's columns.
      
    • 05-qc-metrics.md 4.6 KB
      # CUT&RUN QC Metrics
      
      Quality assessment for CUT&RUN data includes standard alignment metrics,
      CUT&RUN-specific fragment analysis, spike-in validation, and peak quality.
      
      Pass/warn/fail thresholds live in one place: the QC table in `SKILL.md`. The
      commands below show how to derive each value, including the ones the workflow
      does not compute (spike-in fraction, peak statistics).
      
      ## Fragment Size Distribution
      
      The fragment size distribution is the most informative CUT&RUN QC metric:
      
      ```bash
      # Extract fragment sizes from properly paired reads
      samtools view -f 2 -F 1804 sample_final.bam | \
          awk '{if($9 > 0 && $9 < 1000) print $9}' | \
          sort -n | uniq -c | \
          awk '{print $2, $1}' > fragment_sizes.txt
      ```
      
      The workflow runs exactly this and publishes
      `qc/{sample}.fragment_sizes.txt`.
      
      ### Expected Patterns by Target
      
      | Target Type | Fragment Pattern | Example |
      |-------------|-----------------|---------|
      | TF (CTCF, etc.) | Peak <120 bp, some at 150 bp | Sharp sub-nucleosomal |
      | Active histone (H3K4me3) | Strong 150 bp peak | Mononucleosomal |
      | Repressive histone (H3K27me3) | 150 bp + 300 bp | Mono + dinucleosomal |
      | IgG control | Flat distribution | No enrichment pattern |
      
      ### Red Flags in Fragment Distribution
      
      - No nucleosomal periodicity: Protocol may have failed
      - Only large fragments (>300 bp): Over-digestion or poor tagmentation
      - Spike at exact read length: Adapter trimming incomplete
      - Identical to IgG: No target enrichment
      
      ## Spike-in QC
      
      ### Spike-in Fraction
      
      The spike-in BAM is an intermediate; the published per-sample count file is
      `spikein/{sample}.spikein_counts.txt` (columns sample and count):
      
      ```bash
      genome=$(samtools view -c -F 1804 -f 2 results/alignment/sample.filtered.bam)
      spikein=$(cut -f2 results/spikein/sample.spikein_counts.txt)
      fraction=$(echo "scale=4; $spikein / ($genome + $spikein)" | bc)
      echo "Spike-in fraction: $fraction"
      ```
      
      Interpretation of the fraction (thresholds: see the QC table in `SKILL.md`):
      too little spike-in makes the normalization imprecise, too much indicates
      poor target enrichment.
      
      ### Spike-in Consistency Across Samples
      
      For reliable normalization, spike-in counts should vary across samples
      (reflecting different amounts of target material), but not be zero. The
      workflow already collects them:
      
      ```bash
      sort -k2 -n results/spikein/scale_factors.txt
      ```
      
      Columns: sample, spike-in count, scale factor.
      
      ## Alignment Statistics
      
      The workflow publishes `alignment/{sample}.flagstat.txt` and
      `alignment/{sample}.dup_metrics.txt`, and the Bowtie2 logs reach
      `multiqc/multiqc_report.html`. To recompute:
      
      ```bash
      samtools flagstat results/alignment/sample.filtered.bam > flagstat.txt
      ```
      
      Mapping rate, properly paired fraction and duplication rate are judged against
      the QC table in `SKILL.md`.
      
      ## FRiP (Fraction of Reads in Peaks)
      
      The FRIP process computes this and publishes `qc/{sample}.frip_mqc.tsv`, one
      row per peak set called for the sample (SEACR stringent and/or relaxed, and/or
      MACS2). Columns: `Peak set` (the peak file), `FRiP`, `reads_in_peaks`,
      `total_reads`. MultiQC shows the same table as "Fraction of reads in peaks".
      
      This is what it runs for each peak set:
      
      ```bash
      total=$(samtools view -c results/alignment/sample.filtered.bam)
      in_peaks=$(bedtools intersect \
          -u \
          -a results/alignment/sample.filtered.bam \
          -b results/peaks/sample.seacr.stringent.bed \
          | samtools view -c -)
      awk -v a="$in_peaks" -v b="$total" 'BEGIN { printf "FRiP: %.4f\n", a / b }'
      ```
      
      Both counts are alignments of the filtered BAM with no further flag filter, so
      the two mates of a fragment count separately. Counting differently (for
      example with `-F 1804 -f 2`) gives a number that does not match the published
      one.
      
      CUT&RUN typically has higher FRiP than ChIP-seq because of lower background.
      Use the FRiP row of the QC table in `SKILL.md` for the thresholds.
      
      ## Peak Count and Size
      
      ```bash
      # Peak statistics
      total_peaks=$(wc -l < results/peaks/sample.seacr.stringent.bed)
      echo "Total peaks: $total_peaks"
      
      # Peak size distribution
      awk '{print $3-$2}' results/peaks/sample.seacr.stringent.bed | \
          awk '{sum+=$1; n++; a[n]=$1} END {
              asort(a);
              print "Median peak size:", a[int(n/2)];
              print "Mean peak size:", sum/n;
              print "Min:", a[1];
              print "Max:", a[n]
          }'
      ```
      
      ## MultiQC Aggregation
      
      ```bash
      multiqc \
          --title "CUT&RUN Pipeline QC" \
          --filename multiqc_report \
          --outdir multiqc/ \
          fastqc/ trim_galore/ alignment/ qc/
      ```
      
      ## Summary QC Table
      
      Generate a per-sample summary:
      
      ```bash
      echo -e "Sample\tReads\tMap_Rate\tDedup_Rate\tSpikein_Frac\tPeaks\tFRiP\tFrag_Peak"
      echo -e "${SAMPLE}\t${TOTAL}\t${MAP_RATE}\t${DUP_RATE}\t${SPIKEIN}\t${PEAKS}\t${FRIP}\t${FRAG}"
      ```
      
    • literature.md 10.9 KB
      # CUT&RUN Pipeline — Literature References
      
      **Last updated:** 2026-03-07
      **Purpose:** Reference catalog for the pipeline-cutandrun skill — papers defining CUT&RUN and CUT&Tag methods, SEACR peak calling, spike-in normalization, and the CUT&RUN suspect list for artifact filtering.
      
      ---
      
      ## CUT&RUN / CUT&Tag Method Development
      
      ---
      
      ### Skene & Henikoff 2017 — CUT&RUN: targeted nuclease strategy
      
      - **Citation:** Skene PJ, Henikoff S. An efficient targeted nuclease strategy for high-resolution mapping of DNA binding sites. eLife, 6:e21856, 2017.
      - **DOI:** [10.7554/eLife.21856](https://doi.org/10.7554/eLife.21856)
      - **PMID:** 28079019 | **PMC:** PMC5310842
      - **Citations:** ~1,500
      - **Key findings:** Introduced Cleavage Under Targets and Release Using Nuclease (CUT&RUN), which tethers protein A-Micrococcal Nuclease (pA-MNase) to an antibody bound to a target protein in situ, then activates cleavage by calcium addition. Released chromatin fragments diffuse out of the nucleus and are collected from the supernatant, eliminating the need for chromatin solubilization or immunoprecipitation. Produces extremely low background compared to ChIP-seq because only targeted fragments are released, while bulk chromatin remains in the nucleus. Requires as few as 100 cells and generates high-quality profiles for both histone marks and transcription factors with minimal sequencing depth (~5M reads vs 20-40M for ChIP-seq). The E. coli DNA carried over from pA-MNase production serves as an internal spike-in for normalization.
      
      ---
      
      ### Kaya-Okur et al. 2019 — CUT&Tag: efficient epigenomic profiling
      
      - **Citation:** Kaya-Okur HS, Wu SJ, Codomo CA, Pledger ES, Bryson TD, Henikoff JG, Ahmad K, Henikoff S. CUT&Tag for efficient epigenomic profiling of small samples and single cells. Nature Communications, 10(1):1930, 2019.
      - **DOI:** [10.1038/s41467-019-09982-5](https://doi.org/10.1038/s41467-019-09982-5)
      - **PMID:** 31036827 | **PMC:** PMC6488672
      - **Citations:** ~1,200
      - **Key findings:** Introduced Cleavage Under Targets and Tagmentation (CUT&Tag), which replaces pA-MNase with protein A-Tn5 transposase (pA-Tn5). After antibody tethering, Tn5 simultaneously fragments and tags target chromatin with sequencing adapters. Key advantages over CUT&RUN: streamlined single-tube workflow, compatible with single-cell applications, and no separate library preparation step needed. However, CUT&Tag has higher background than CUT&RUN due to Tn5 insertion preferences in accessible chromatin. Both methods are supported by this pipeline with the same alignment and peak calling workflow, differing only in spike-in source (E. coli from Tn5 vs MNase production).
      
      ---
      
      ### Skene & Henikoff 2018 — CUT&RUN protocol optimization
      
      - **Citation:** Skene PJ, Henikoff JG, Henikoff S. Targeted in situ genome-wide profiling with high efficiency for low cell numbers. Nature Protocols, 13(5):1006-1019, 2018.
      - **DOI:** [10.1038/nprot.2018.015](https://doi.org/10.1038/nprot.2018.015)
      - **PMID:** 29651053
      - **Citations:** ~500
      - **Key findings:** Detailed step-by-step CUT&RUN protocol with optimization guidelines for different targets (histone marks vs TFs). Established the standard experimental parameters: ConA bead binding for cell immobilization, 0°C calcium-activated cleavage for 30 minutes, fragment release at 37°C, and library preparation with NEBNext reagents. Provided troubleshooting guidance for common issues including low yield, high background, and incomplete cleavage. This protocol forms the basis for most published CUT&RUN experiments and informs the QC expectations in this pipeline.
      
      ---
      
      ## Peak Calling
      
      ---
      
      ### Meers et al. 2019 — SEACR: peak calling for CUT&RUN
      
      - **Citation:** Meers MP, Tenenbaum D, Henikoff S. Peak calling by Sparse Enrichment Analysis for CUT&RUN chromatin profiling. Epigenetics & Chromatin, 12(1):42, 2019.
      - **DOI:** [10.1186/s13072-019-0287-4](https://doi.org/10.1186/s13072-019-0287-4)
      - **PMID:** 31300027 | **PMC:** PMC6626385
      - **Citations:** ~800
      - **Key findings:** Introduced SEACR (Sparse Enrichment Analysis for CUT&RUN), a peak caller specifically designed for the sparse, low-background signal profile of CUT&RUN data. Unlike MACS2 (which models background as a Poisson distribution), SEACR uses the empirical distribution of signal in control (IgG) or target data to identify enriched regions without parametric assumptions. Offers two modes: stringent (peaks must exceed both the global threshold and a local enrichment test) and relaxed (global threshold only). When no IgG control is available, SEACR uses the top 1% of target signal as a threshold. Benchmarking showed SEACR produces fewer false positives than MACS2 on CUT&RUN data, particularly in regions with low but genuine enrichment.
      
      ---
      
      ## Quality Control
      
      ---
      
      ### Nordin et al. 2023 — CUT&RUN suspect list
      
      - **Citation:** Nordin A, Zambanini G, Pagella P, Bhatt DK, Bjork P, Nilsson J, Mead P, Boyle AP. The CUT&RUN suspect list of problematic regions of the genome. Genome Biology, 24:185, 2023.
      - **DOI:** [10.1186/s13059-023-02960-3](https://doi.org/10.1186/s13059-023-02960-3)
      - **PMID:** 37580722 | **PMC:** PMC10424377
      - **Citations:** ~50
      - **Key findings:** Identified genomic regions that produce artifactual signal in CUT&RUN and CUT&Tag experiments, distinct from the standard ENCODE blacklist. These "suspect" regions include areas with high MNase/Tn5 accessibility, specific repeat families, and regions prone to antibody-independent cleavage. The suspect list should be applied in addition to the ENCODE blacklist v2 (Amemiya et al. 2019) when filtering CUT&RUN/CUT&Tag peaks. Without suspect list filtering, up to 20% of called peaks may be artifacts, particularly for targets with moderate enrichment. This workflow applies only the single BED given as `--blacklist`, to the BAM; pass a merged blacklist + suspect list there, or filter the peaks manually.
      
      ---
      
      ### Meers et al. 2019 — Spike-in normalization for CUT&RUN/CUT&Tag
      
      - **Citation:** Meers MP, Bryson TD, Henikoff JG, Henikoff S. Improved CUT&RUN chromatin profiling tools. eLife, 8:e46314, 2019.
      - **DOI:** [10.7554/eLife.46314](https://doi.org/10.7554/eLife.46314)
      - **PMID:** 31232687 | **PMC:** PMC6632061
      - **Citations:** ~400
      - **Key findings:** Established the spike-in calibration framework for quantitative CUT&RUN. E. coli DNA carried over from pA-MNase production provides an internal standard: the ratio of spike-in reads between samples inversely correlates with target enrichment efficiency. Scale factors computed from spike-in counts enable quantitative comparison of signal intensity across samples and conditions. Demonstrated that spike-in normalization is essential for detecting global changes in histone modifications (e.g., drug treatments that globally increase or decrease a mark), which would be invisible with standard library-size normalization. This calibration approach is implemented in the pipeline's spike-in normalization step.
      
      ---
      
      ## Supplementary Tools (Non-CUT&RUN-Specific)
      
      See pipeline-chipseq/references/literature.md for detailed descriptions of shared tools, and pipeline-atacseq/references/literature.md for Bowtie2.
      
      ---
      
      ### Langmead & Salzberg 2012 — Bowtie 2
      
      - **DOI:** [10.1038/nmeth.1923](https://doi.org/10.1038/nmeth.1923) | **PMID:** 22388286 | **Citations:** ~47,300
      - **CUT&RUN role:** Alignment of CUT&RUN/CUT&Tag reads to both the target genome and the E. coli spike-in genome. Bowtie2 is preferred over BWA-MEM for CUT&RUN because the short fragments typical of CUT&RUN (~150 bp mononucleosomal, <120 bp sub-nucleosomal) are well-suited to Bowtie2's alignment algorithm. Run with --very-sensitive and --dovetail flags.
      
      ---
      
      ### Zhang et al. 2008 — MACS2
      
      - **DOI:** [10.1186/gb-2008-9-9-r137](https://doi.org/10.1186/gb-2008-9-9-r137) | **PMID:** 18798982 | **Citations:** ~7,000
      - **CUT&RUN role:** Alternative peak caller for CUT&RUN data. MACS2 can be used instead of or alongside SEACR, but tends to overcall peaks due to CUT&RUN's low background. When using MACS2 on CUT&RUN data, use --nomodel and set appropriate --shift/--extsize parameters. Useful for comparison with ChIP-seq results processed with the same peak caller.
      
      ---
      
      ### Li et al. 2009 — SAMtools
      
      - **DOI:** [10.1093/bioinformatics/btp352](https://doi.org/10.1093/bioinformatics/btp352) | **PMID:** 19505943 | **Citations:** ~53,700
      - **CUT&RUN role:** BAM sorting, filtering, indexing, and alignment statistics.
      
      ---
      
      ### Broad Institute — Picard MarkDuplicates
      
      - **URL:** [https://broadinstitute.github.io/picard/](https://broadinstitute.github.io/picard/)
      - **CUT&RUN role:** PCR duplicate marking. CUT&RUN typically has lower duplication rates than ChIP-seq because it requires less input material and fewer PCR cycles. Duplication rates >20% suggest overamplification.
      
      ---
      
      ### Quinlan & Hall 2010 — BEDTools
      
      - **DOI:** [10.1093/bioinformatics/btq033](https://doi.org/10.1093/bioinformatics/btq033) | **PMID:** 20110278 | **Citations:** ~12,000
      - **CUT&RUN role:** Used by the workflow to filter the BAM against `--blacklist`, to build the fragment BED and bedGraph, and to count reads in peaks for FRiP (`bedtools intersect -u`); used manually for peak filtering, which the workflow does not run.
      
      ---
      
      ### Ramírez et al. 2016 — deepTools2
      
      - **DOI:** [10.1093/nar/gkw257](https://doi.org/10.1093/nar/gkw257) | **PMID:** 27079975 | **Citations:** ~6,100
      - **CUT&RUN role:** Generates spike-in normalized signal tracks (bigWig) using bamCoverage with the --scaleFactor parameter computed from spike-in read counts. Also used for fingerprint plots and heatmaps.
      
      ---
      
      ### Amemiya et al. 2019 — ENCODE Blacklist
      
      - **DOI:** [10.1038/s41598-019-45839-z](https://doi.org/10.1038/s41598-019-45839-z) | **PMID:** 31249361 | **Citations:** ~1,372
      - **CUT&RUN role:** The file normally passed as `--blacklist`, which the workflow applies to the BAM. Both filters are worth applying: the blacklist addresses general sequencing/alignment artifacts while the CUT&RUN suspect list (Nordin 2023) addresses CUT&RUN-specific enzyme cleavage artifacts. Merge the two into one BED and pass it as `--blacklist`, or filter the peaks manually.
      
      ---
      
      ### Ewels et al. 2016 — MultiQC
      
      - **DOI:** [10.1093/bioinformatics/btw354](https://doi.org/10.1093/bioinformatics/btw354) | **PMID:** 27312411 | **Citations:** ~6,800
      - **CUT&RUN role:** Aggregates QC metrics from FastQC, Bowtie2, Picard, SEACR, and spike-in statistics into a unified HTML report.
      
      ---
      
      ### Andrews 2010 — FastQC
      
      - **URL:** [https://www.bioinformatics.babraham.ac.uk/projects/fastqc/](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)
      - **CUT&RUN role:** Raw read quality assessment. CUT&RUN libraries typically show high-quality bases and characteristic nucleosomal fragment sizes.
      
      ---
      
      ### Martin 2011 — Cutadapt (basis for Trim Galore)
      
      - **DOI:** [10.14806/ej.17.1.200](https://doi.org/10.14806/ej.17.1.200) | **Citations:** ~13,000
      - **CUT&RUN role:** Adapter trimming. CUT&RUN sub-nucleosomal fragments frequently read through into adapters, making trimming important for accurate alignment.
      
  • scripts
    • Dockerfile 2.9 KB · in bundle
    • main.nf 16.1 KB · in bundle
    • nextflow.config 4.3 KB · in bundle
  • SKILL.md 25.3 KB
    ---
    name: pipeline-cutandrun
    description: "Execute CUT&RUN processing pipeline from FASTQ to peaks and signal tracks. Child of pipeline-guide. Provides Nextflow execution with Docker and cloud deployment. Use when processing CUT&RUN or CUT&Tag data, an alternative to ChIP-seq with lower background. Trigger on: CUT&RUN pipeline, CUT&Tag, SEACR, Henikoff, targeted chromatin, pA-MNase, process CUT&RUN."
    ---
    
    # ENCODE CUT&RUN Pipeline: FASTQ to Peaks and Signal Tracks
    
    ## When to Use
    
    - User wants to run a CUT&RUN or CUT&Tag processing pipeline from FASTQ to peaks
    - User asks about "CUT&RUN pipeline", "CUT&Tag", "SEACR", "spike-in normalization", or "targeted chromatin"
    - User needs to process CUT&RUN/CUT&Tag data with spike-in calibration and SEACR peak calling
    - Example queries: "process my CUT&RUN FASTQs", "run SEACR on CUT&Tag data", "normalize CUT&RUN with spike-in controls"
    
    Execute the CUT&RUN/CUT&Tag processing pipeline for targeted chromatin profiling,
    producing peak calls with SEACR and spike-in normalized signal tracks.
    
    ## Pipeline Overview
    
    ```
    FASTQ
      |-> FastQC (raw reads)
      +-> Trim Galore -> Bowtie2 (genome) -> {sample}.sorted.bam
            |
            |-> unmapped read pairs -> Bowtie2 (spike-in) -> counts -> scale_factors.txt
            |                                                                |
            +-> filter (MAPQ 10, proper pairs) -> Picard MarkDuplicates      |
                (removed) -> blacklist filter -> {sample}.filtered.bam       |
                     |-> fragment BED -> fragment bedGraph -> SEACR peaks    |
                     |-> MACS2 peaks (with --peak_caller macs2|both)         |
                     |-> FRiP vs every peak set -> {sample}.frip_mqc.tsv     |
                     +-> bamCoverage -> {sample}.normalized.bw <-- factor ---+
    ```
    
    ### Not run by this workflow
    
    - **Peak-level filtering**: `--blacklist` is applied to the BAM only. Peak
      files are never filtered afterwards, and there is no separate suspect-list
      input. Pass a pre-merged blacklist + suspect-list BED as `--blacklist`, or
      filter the peak files yourself.
    - **Spike-in scaling of the SEACR input**: only the bigWig is scaled
      (`bamCoverage --scaleFactor`). The fragment bedGraph given to SEACR is
      unscaled.
    
    ### ENCODE Repository
    
    - ENCODE does not publish an official CUT&RUN pipeline. This workflow follows the published
      CUT&RUN/CUT&Tag processing protocol (Bowtie2, fragment bedGraphs, SEACR) and applies
      ENCODE conventions for filtering, blacklisting, and QC.
    - **Container**: built from `scripts/Dockerfile` in this skill (`docker build -t encode-toolkit/pipeline-cutandrun:1.0.0 scripts/`); override with `--container`
    - **This skill**: Nextflow DSL2 reimplementation for portability
    
    ## Core Tools and Versions
    
    Versions are those installed by `scripts/Dockerfile`, which is what the
    workflow runs.
    
    | Tool | Version | Purpose | Citation |
    |------|---------|---------|----------|
    | Bowtie2 | 2.5.4 | Alignment (genome + spike-in) | Langmead & Salzberg 2012 |
    | SEACR | 1.3 | Peak calling (CUT&RUN-specific) | Meers et al. 2019 |
    | MACS2 | 2.2.9.1 | Alternative peak caller | Zhang et al. 2008 |
    | Picard | 3.1.1 | Duplicate marking and removal | Broad Institute |
    | samtools | 1.19 | BAM operations | Li et al. 2009 |
    | bedtools | 2.31.0 | Genomic arithmetic | Quinlan & Hall 2010 |
    | deepTools | 3.5.5 | Signal track generation | Ramirez et al. 2016 |
    | Trim Galore | 0.6.10 | Adapter trimming | Krueger (Babraham) |
    | FastQC | 0.12.1 | Read quality | Andrews (Babraham) |
    | MultiQC | 1.21 | Aggregated QC | Ewels et al. 2016 |
    
    The conda alternative (`cutandrun-env.yml`) pins the same version of every tool
    in the table above, but installs no SEACR (only `r-base`): SEACR is not a conda
    package, so on that route `SEACR_1.3.sh` and `SEACR_1.3.R` must be fetched
    separately from the SEACR repository.
    
    ## Key Literature
    
    1. **Skene & Henikoff 2017** - "An efficient targeted nuclease strategy for
       high-resolution mapping of DNA binding sites" (eLife, ~1,500 citations)
       DOI: 10.7554/eLife.21856
    
    2. **Meers et al. 2019** - "Peak calling by Sparse Enrichment Analysis for
       CUT&RUN chromatin profiling" (Epigenetics & Chromatin, ~800 citations)
       DOI: 10.1186/s13072-019-0287-4
    
    3. **Kaya-Okur et al. 2019** - "CUT&Tag for efficient epigenomic profiling
       of small samples and single cells" (Nature Communications, ~1,200 citations)
       DOI: 10.1038/s41467-019-09982-5
    
    4. **Nordin et al. 2023** - "The CUT&RUN suspect list of problematic regions"
       (Genome Biology)
       DOI: 10.1186/s13059-023-02960-3
    
    5. **Amemiya et al. 2019** - "The ENCODE Blacklist" (Scientific Reports, ~1,372 citations)
       DOI: 10.1038/s41598-019-45839-z
    
    ## Execution
    
    ### Quick Start (Local)
    
    ```bash
    nextflow run scripts/main.nf \
        -profile local \
        --reads '/data/fastq/*_R{1,2}.fastq.gz' \
        --bowtie2_index '/ref/bowtie2_index/genome' \
        --spikein_index '/ref/bowtie2_ecoli/ecoli' \
        --chrom_sizes '/ref/hg38.chrom.sizes' \
        --blacklist '/ref/hg38-blacklist.v2.bed' \
        --outdir results/ \
        -resume
    ```
    
    ### SLURM HPC
    
    ```bash
    nextflow run scripts/main.nf \
        -profile slurm \
        --container /path/to/pipeline-cutandrun.sif \
        --reads '/data/fastq/*_R{1,2}.fastq.gz' \
        --bowtie2_index '/ref/bowtie2_index/genome' \
        --spikein_index '/ref/bowtie2_ecoli/ecoli' \
        --chrom_sizes '/ref/hg38.chrom.sizes' \
        --blacklist '/ref/hg38-blacklist.v2.bed' \
        --outdir results/ \
        -resume
    ```
    
    ### Cloud (GCP / AWS)
    
    ```bash
    # Google Cloud Batch
    nextflow run scripts/main.nf -profile gcp \
        --container us-docker.pkg.dev/<project>/<repo>/pipeline-cutandrun:1.0.0 \
        --gcp_project <project> \
        --gcp_workdir gs://<bucket>/work \
        --reads 'gs://<bucket>/fastq/*_R{1,2}.fastq.gz' \
        --bowtie2_index gs://<bucket>/ref/bowtie2_index/genome \
        --spikein_index gs://<bucket>/ref/bowtie2_ecoli/ecoli \
        --chrom_sizes gs://<bucket>/ref/hg38.chrom.sizes \
        --blacklist gs://<bucket>/ref/hg38-blacklist.v2.bed \
        --outdir gs://<bucket>/results
    
    # AWS Batch
    nextflow run scripts/main.nf -profile aws \
        --container <account>.dkr.ecr.<region>.amazonaws.com/pipeline-cutandrun:1.0.0 \
        --aws_queue <job-queue> \
        --aws_workdir s3://<bucket>/work \
        --reads 's3://<bucket>/fastq/*_R{1,2}.fastq.gz' \
        --bowtie2_index s3://<bucket>/ref/bowtie2_index/genome \
        --spikein_index s3://<bucket>/ref/bowtie2_ecoli/ecoli \
        --chrom_sizes s3://<bucket>/ref/hg38.chrom.sizes \
        --blacklist s3://<bucket>/ref/hg38-blacklist.v2.bed \
        --outdir s3://<bucket>/results
    ```
    
    `--outdir` only sets where results are published; Google Batch and AWS Batch
    stage every task through the work directory, and the workflow stops with an
    error if it or the project/queue is missing.
    
    ## Resource Requirements
    
    | Step | CPUs | RAM | Time (per sample) |
    |------|------|-----|-------------------|
    | Bowtie2 align (genome) | 8 | 8 GB | 30-60 min |
    | Bowtie2 align (spike-in) | 4 | 4 GB | 10-20 min |
    | Filter/dedup | 4 | 8 GB | 15-30 min |
    | SEACR peaks | 2 | 4 GB | 10-20 min |
    | Signal tracks | 4 | 8 GB | 15-30 min |
    | **Total** | **8** | **8 GB** | **1.5-3 hours** |
    
    The RAM column is each step's first-attempt request. These processes ask for
    that much memory per attempt, so a task killed for exceeding it is retried with
    more (at most two retries, capped by `--max_memory`). Failures with any other
    exit status stop the run.
    
    ## Pipeline Parameters
    
    | Parameter | Default | Description |
    |-----------|---------|-------------|
    | `--reads` | required | Glob pattern to paired FASTQ files |
    | `--bowtie2_index` | required | Bowtie2 genome index prefix (every file starting with this prefix is staged) |
    | `--spikein_index` | `null` | Bowtie2 spike-in index prefix (E. coli by convention). When given, signal tracks are spike-in calibrated |
    | `--chrom_sizes` | required | Chromosome sizes file |
    | `--blacklist` | required | Blacklist BED applied to the BAM. Pass a pre-merged blacklist + CUT&RUN suspect list here if you want both |
    | `--outdir` | `./results` | Output directory |
    | `--seacr_mode` | `stringent` | SEACR mode: `stringent`, `relaxed`, or `both` |
    | `--seacr_norm` | `norm` | SEACR normalization to the control: `norm` or `non`. Only used with `--control`; without a control the workflow always passes `non` |
    | `--seacr_threshold` | `0.01` | Top fraction of signal kept by SEACR when no `--control` is given |
    | `--control` | `null` | IgG control BAM, already filtered and deduplicated. Converted to a fragment bedGraph for SEACR and passed as `-c` to MACS2 |
    | `--macs2_gsize` | `hs` | MACS2 effective genome size (`hs`, `mm`, or a number) |
    | `--peak_caller` | `seacr` | Peak caller: `seacr`, `macs2`, or `both` |
    | `--skip_spikein` | `false` | Skip spike-in calibration; signal tracks are then RPKM-normalized |
    
    ### Infrastructure parameters (`nextflow.config`)
    
    | Parameter | Default | Description |
    |-----------|---------|-------------|
    | `--container` | `encode-toolkit/pipeline-cutandrun:1.0.0` | Image built from `scripts/Dockerfile`. Pass a registry image for `gcp`/`aws`, or a `.sif` file for `slurm` |
    | `--max_cpus`, `--max_memory`, `--max_time` | `16`, `16.GB`, `12.h` | Upper bounds applied to every process |
    | `--slurm_queue`, `--slurm_account` | `normal`, none | SLURM partition and account |
    | `--gcp_project`, `--gcp_workdir` | none (both required for `-profile gcp`) | Google Cloud project and `gs://` work directory |
    | `--gcp_location`, `--gcp_disk` | `us-central1`, `200.GB` | Google Batch region and per-task disk |
    | `--aws_queue`, `--aws_workdir` | none (both required for `-profile aws`) | AWS Batch job queue and `s3://` work directory |
    | `--aws_region`, `--aws_cli_path` | `us-east-1`, `/home/ec2-user/miniconda/bin/aws` | AWS region, and the AWS CLI path inside the Batch AMI |
    
    ## Output Files
    
    ```
    results/
      fastqc/                             # Raw read quality
      trim_galore/                        # Trimmed reads, trimming reports,
                                          #   and FastQC of the trimmed reads
      alignment/
        {sample}.filtered.bam             # Quality-filtered, deduplicated, blacklist-filtered
        {sample}.filtered.bam.bai
        {sample}.dup_metrics.txt          # Picard MarkDuplicates metrics
        {sample}.flagstat.txt             # samtools flagstat on the filtered BAM
      spikein/                            # Only with --spikein_index
        {sample}.spikein_counts.txt       # sample, spike-in read count
        scale_factors.txt                 # One file for the run: sample, spikein_count, scale_factor
      peaks/
        {sample}.seacr.stringent.bed      # SEACR stringent peaks
        {sample}.seacr.relaxed.bed        # With --seacr_mode relaxed or both
        {sample}.macs2_peaks.narrowPeak   # With --peak_caller macs2 or both
      signal/
        {sample}.normalized.bw            # Spike-in scaled, or RPKM without spike-in
        {sample}.fragments.bed            # Fragment BED (same chromosome, <1 kb)
      qc/
        {sample}.fragment_sizes.txt
        {sample}.frip_mqc.tsv             # FRiP, one row per peak set called for the sample
      multiqc/
        multiqc_report.html
      pipeline_info/
        timeline.html
        report.html
        trace.txt
    ```
    
    The fragment bedGraph that SEACR consumes is an intermediate and is not
    published; the published `signal/{sample}.fragments.bed` is the BED it is
    built from.
    
    ## QC Thresholds
    
    This is the only QC threshold table for this skill; the reference files point
    back to it.
    
    | Metric | Pass | Warning | Fail | Computed from |
    |--------|------|---------|------|---------------|
    | Mapping rate (genome) | >80% | 60-80% | <60% | Bowtie2 log (in `multiqc_report.html`) |
    | Spike-in reads | 1-10% of total | 0.1-1% or 10-30% | <0.1% or >30% | `spikein/{sample}.spikein_counts.txt` |
    | Duplication rate | <20% | 20-40% | >40% | `alignment/{sample}.dup_metrics.txt` |
    | FRiP (peaks) | >10% | 5-10% | <5% | `qc/{sample}.frip_mqc.tsv` (also a MultiQC table) |
    | Peak count | >5,000 | 1,000-5,000 | <1,000 | `peaks/{sample}.seacr.*.bed` |
    | Fragment size | Nucleosomal pattern | Irregular | No pattern | `qc/{sample}.fragment_sizes.txt` |
    
    ### Fragment Size Distribution
    
    CUT&RUN produces a characteristic nucleosomal ladder:
    - **<120 bp**: Sub-nucleosomal (TF binding)
    - **~150 bp**: Mononucleosomal (histone marks)
    - **~300 bp**: Dinucleosomal
    - Absence of nucleosomal pattern suggests protocol issues
    
    ## Spike-in Normalization
    
    Spike-in normalization is CRITICAL for CUT&RUN quantitative comparison.
    
    ### How It Works
    
    1. E. coli DNA is carried over from pA-MNase/pA-Tn5 production
    2. Each sample has a different amount of spike-in reads
    3. Samples with more target cleavage have fewer spike-in reads (proportionally)
    4. Scale factor = smallest non-zero spike-in count across samples / this sample's count
    
    ### Scale Factor Calculation
    
    With three samples whose spike-in counts are 200,000, 400,000 and 100,000, the
    minimum is 100,000:
    
    ```
    Sample A: 200,000 spike-in reads -> scale = 100,000 / 200,000 = 0.5
    Sample B: 400,000 spike-in reads -> scale = 100,000 / 400,000 = 0.25
    Sample C: 100,000 spike-in reads -> scale = 100,000 / 100,000 = 1.0 (minimum)
    ```
    
    Higher spike-in counts = less target enrichment = lower scale factor.
    
    All samples are written to one `spikein/scale_factors.txt` (columns: sample,
    spike-in count, scale factor). A sample with no spike-in reads cannot be
    calibrated and is left unscaled (factor 1). The factor is applied only to the
    bigWig via `bamCoverage --scaleFactor`; the fragment bedGraph SEACR reads is
    unscaled.
    
    ## SEACR vs MACS2
    
    | Feature | SEACR | MACS2 |
    |---------|-------|-------|
    | Designed for | CUT&RUN/CUT&Tag | ChIP-seq |
    | Background model | Sparse enrichment | Dynamic Poisson |
    | Control required | Optional (IgG) | Recommended |
    | Low background | Handles well | May overcall |
    | Stringent mode | Very conservative | Via q-value |
    | ENCODE recommendation | Primary for CUT&RUN | Alternative |
    
    SEACR is specifically designed for the sparse, low-background signal
    profile of CUT&RUN data. MACS2 may overcall peaks due to the low background.
    
    ## Critical Pitfalls
    
    ### Spike-in Calibration is CRITICAL
    Without spike-in normalization, quantitative comparisons between samples are
    unreliable. The amount of pA-MNase (or pA-Tn5) varies between experiments,
    and spike-in reads provide the internal calibration standard. Without
    `--spikein_index` (or with `--skip_spikein`) the bigWigs fall back to RPKM,
    which is not quantitatively comparable across samples.
    
    ### IgG Control vs No-Antibody Control
    - **IgG control**: Non-specific antibody, captures background binding
    - **No-antibody**: No antibody, captures MNase accessibility background
    - IgG is preferred but not always available
    - SEACR can work without a control: it then uses `--seacr_threshold` (default
      0.01, the top 1% of signal) and, as SEACR v1.3 requires with a numeric
      threshold, the `non` normalization mode
    
    ### SEACR Stringent vs Relaxed Mode
    - **Stringent**: Returns only the most enriched peaks (fewer, higher confidence)
    - **Relaxed**: Returns a broader set including weaker peaks
    - For initial analysis, use stringent mode (the default)
    - For comprehensive catalogs, use `--seacr_mode both` and filter downstream
    
    ### CUT&RUN Suspect List (Nordin 2023)
    The workflow applies `--blacklist` to the BAM only; it never filters the peak
    files and takes no separate suspect list. To use the CUT&RUN suspect list
    (Nordin et al. 2023), which identifies regions with artifactual signal
    specific to CUT&RUN/CUT&Tag protocols, either pass a merged BED as
    `--blacklist` or filter the peaks afterwards yourself:
    
    ```bash
    # Download suspect list
    wget https://github.com/Boyle-Lab/Blacklist/raw/master/lists/CUTandRUN.suspectlist.hg38.bed.gz
    
    # Option 1: merge once and pass as --blacklist (filters the BAM)
    zcat CUTandRUN.suspectlist.hg38.bed.gz | cat hg38-blacklist.v2.bed - \
        | sort -k1,1 -k2,2n | bedtools merge > combined_blacklist.bed
    
    # Option 2: filter the published peaks afterwards (manual)
    bedtools intersect \
        -a results/peaks/sample.seacr.stringent.bed \
        -b combined_blacklist.bed \
        -v \
        > sample_peaks_filtered.bed
    ```
    
    ### CUT&RUN vs CUT&Tag
    Both protocols are supported by this pipeline. Differences:
    - **CUT&RUN**: Uses pA-MNase, E. coli spike-in from MNase production
    - **CUT&Tag**: Uses pA-Tn5, E. coli spike-in from Tn5 production
    - CUT&Tag has higher background from Tn5 insertion preference
    - CUT&Tag may work better for histone marks; CUT&RUN for TFs
    
    ## Provenance Integration
    
    After pipeline completion, log all outputs:
    
    ```python
    encode_log_derived_file(
        file_path="/results/peaks/sample1.seacr.stringent.bed",
        source_accessions=["ENCSR...", "ENCFF..."],
        description="CUT&RUN peaks from ENCODE CUT&RUN pipeline",
        file_type="CUT&RUN_peaks",
        tool_used="Bowtie2 2.5.4 + SEACR 1.3",
        parameters="stringent mode, threshold 0.01 non, BAM blacklist-filtered (peaks unfiltered)"
    )
    ```
    
    ## Reference Files
    
    Detailed step-by-step documentation is provided in the `references/` directory:
    
    1. `01-qc-trimming.md` -- Read QC and adapter trimming for CUT&RUN
    2. `02-bowtie2-alignment.md` -- Bowtie2 alignment to genome and spike-in
    3. `03-filtering-spikein.md` -- Filtering, dedup, and spike-in normalization
    4. `04-seacr-peaks.md` -- SEACR peak calling and MACS2 alternative
    5. `05-qc-metrics.md` -- Fragment sizes, FRiP, spike-in QC
    
    ## Walkthrough: Processing ENCODE CUT&RUN from FASTQ to Peaks
    
    **Goal**: Process CUT&RUN/CUT&Tag FASTQ files through the ENCODE-compatible pipeline to generate peak calls with spike-in normalization.
    **Context**: CUT&RUN uses targeted MNase digestion (lower background than ChIP-seq) but requires different peak calling (SEACR instead of MACS2) and spike-in normalization for quantitative comparisons.
    
    ### Step 1: Find CUT&RUN experiment
    
    ```
    encode_search_experiments(assay_title="CUT&RUN", organism="Homo sapiens")
    ```
    
    Expected output:
    ```json
    {
      "results": [
        {"accession": "ENCSR900CUR", "assay_title": "CUT&RUN", "target": "H3K27me3", "biosample_summary": "K562", "assembly": ["GRCh38"], "status": "released"}
      ],
      "total": 35,
      "limit": 25,
      "offset": 0,
      "has_more": true,
      "next_offset": 25
    }
    ```
    
    ### Step 2: List FASTQ files
    
    ```
    encode_list_files(experiment_accession="ENCSR900CUR", file_format="fastq")
    ```
    
    Expected output (a JSON array of file records; fields abridged):
    ```json
    [
      {"accession": "ENCFF900CR1", "file_format": "fastq", "output_type": "reads", "biological_replicates": [1], "file_size": 839252000, "file_size_human": "800.4 MB", "status": "released"},
      {"accession": "ENCFF901CR2", "file_format": "fastq", "output_type": "reads", "biological_replicates": [1], "file_size": 891394000, "file_size_human": "850.1 MB", "status": "released"}
    ]
    ```
    
    **Interpretation**: CUT&RUN yields smaller files than ChIP-seq (~800MB vs ~2.5GB) due to lower background.
    
    ### Step 3: Name the files so a read-pair glob can find them
    
    ENCODE FASTQs are named by accession, so the two mates of a pair share no
    prefix, and the workflow matches file pairs with a `{1,2}` glob. Which mate a
    file is comes from its page on encodeproject.org (`paired_end` 1 or 2, and
    `paired_with` naming the other accession), not from any tool here. Link the
    files into the shape the glob expects:
    
    ```bash
    mkdir -p fastq
    ln -s "$PWD/ENCFF900CR1.fastq.gz" fastq/ENCSR900CUR_R1.fastq.gz
    ln -s "$PWD/ENCFF901CR2.fastq.gz" fastq/ENCSR900CUR_R2.fastq.gz
    ```
    
    ### Step 4: Run the CUT&RUN pipeline
    
    ```bash
    nextflow run scripts/main.nf \
      -profile local \
      --reads 'fastq/ENCSR900CUR_R{1,2}.fastq.gz' \
      --bowtie2_index '/ref/bowtie2_index/genome' \
      --spikein_index '/ref/bowtie2_ecoli/ecoli' \
      --chrom_sizes '/ref/hg38.chrom.sizes' \
      --blacklist '/ref/hg38-blacklist.v2.bed' \
      --peak_caller seacr \
      --outdir results/ \
      -resume
    ```
    
    Key pipeline steps:
    1. FastQC on the raw reads, then adapter trimming (Trim Galore, `--nextera`)
    2. Bowtie2 alignment (`--very-sensitive --no-mixed --no-discordant --dovetail -I 10 -X 700`)
    3. Spike-in alignment of the read pairs that did not map to the genome
    4. Scale factor per sample (minimum spike-in count / sample count)
    5. Filter (MAPQ 10, proper pairs), remove duplicates with Picard, remove blacklist regions
    6. SEACR peak calling from the fragment bedGraph (stringent by default)
    7. Signal bigWig with `bamCoverage`, scaled by the spike-in factor
    8. FRiP of the filtered BAM against every peak set called for the sample,
       written to `qc/{sample}.frip_mqc.tsv`
    
    ### Step 5: Validate output quality
    
    Use the QC threshold table above with `alignment/{sample}.dup_metrics.txt`,
    `spikein/{sample}.spikein_counts.txt`, `qc/{sample}.fragment_sizes.txt` and
    `qc/{sample}.frip_mqc.tsv`.
    
    **Key difference from ChIP-seq**: CUT&RUN has inherently lower background, so peak callers like MACS2 overfit. Use SEACR (Meers et al. 2019) instead.
    
    ### Step 6: Compare with ChIP-seq for the same target
    
    ```
    encode_search_experiments(assay_title="Histone ChIP-seq", biosample_term_name="K562", target="H3K27me3", organism="Homo sapiens")
    ```
    
    **Interpretation**: CUT&RUN typically identifies fewer but higher-confidence peaks than ChIP-seq. Concordant peaks between both methods are the highest confidence.
    
    ### Integration with downstream skills
    - SEACR peaks feed into -> **histone-aggregation** for cross-experiment comparison
    - Spike-in normalized signals feed into -> **visualization-workflow**
    - Peak regions feed into -> **regulatory-elements** for chromatin state classification
    - QC uses different thresholds than ChIP-seq -> **quality-assessment** (see suspect list)
    - Pipeline provenance logged by -> **data-provenance**
    
    ## Code Examples
    
    ### 1. Survey CUT&RUN/CUT&Tag availability
    
    ```
    encode_get_facets(assay_title="CUT&RUN", organism="Homo sapiens")
    ```
    
    Expected output:
    ```json
    {
      "target.label": [
        {"term": "H3K27me3", "count": 15},
        {"term": "H3K4me3", "count": 12},
        {"term": "H3K27ac", "count": 8},
        {"term": "CTCF", "count": 5}
      ]
    }
    ```
    
    ### 2. Find matching ChIP-seq for comparison
    
    ```
    encode_search_experiments(assay_title="Histone ChIP-seq", biosample_term_name="K562", target="H3K27me3", organism="Homo sapiens")
    ```
    
    Expected output:
    ```json
    {
      "results": [
        {"accession": "ENCSR000CHI", "assay_title": "Histone ChIP-seq", "target": "H3K27me3", "biosample_summary": "K562", "assembly": ["GRCh38"]}
      ],
      "total": 5,
      "limit": 25,
      "offset": 0,
      "has_more": false,
      "next_offset": null
    }
    ```
    
    ### 3. Track CUT&RUN experiments
    
    ```
    encode_track_experiment(accession="ENCSR900CUR", notes="K562 H3K27me3 CUT&RUN - SEACR peaks for comparison with ChIP-seq")
    ```
    
    Expected output:
    ```json
    {
      "tracking": {
        "accession": "ENCSR900CUR",
        "action": "tracked"
      },
      "publications_found": 0,
      "publications": [],
      "pipelines_found": 0,
      "pipelines": []
    }
    ```
    
    ## Integration
    
    | This skill produces... | Feed into... | Purpose |
    |---|---|---|
    | SEACR peaks | **histone-aggregation** | Cross-experiment comparison (note: different caller than ChIP-seq) |
    | Spike-in normalized signal | **visualization-workflow** | Quantitatively comparable browser tracks |
    | Peak regions | **regulatory-elements** | Chromatin state classification |
    | CUT&RUN-specific QC | **quality-assessment** | Validate with CUT&RUN-appropriate thresholds |
    | Peak coordinates | **motif-analysis** | TF motif discovery at CUT&RUN peaks |
    | Pipeline parameters | **data-provenance** | Record SEACR/spike-in normalization details |
    | Peak files | **variant-annotation** | Identify variants in CUT&RUN peaks |
    | Comparison with ChIP-seq | **compare-biosamples** | Cross-assay concordance analysis |
    
    ## Related Skills
    
    - `pipeline-guide` -- Parent skill with compute resource assessment and cloud setup
    - `histone-aggregation` -- Aggregate histone mark data across samples
    - `quality-assessment` -- Evaluate pipeline output quality metrics
    - `data-provenance` -- Track all pipeline inputs, outputs, and parameters
    - `download-encode` -- Download ENCODE CUT&RUN FASTQ files for pipeline input
    - `publication-trust` -- Verify literature claims backing analytical decisions
    
    ## Presenting Results
    
    When reporting CUT&RUN pipeline results:
    
    - **SEACR peak counts**: Report peak counts for each SEACR mode that was run (default: stringent only; both with `--seacr_mode both`). If MACS2 was also run, include those counts for comparison
    - **Spike-in normalization factor**: Report the scale factor and spike-in count per sample from `spikein/scale_factors.txt` and the spike-in read fraction (ideal 1-10% of total reads). Explain that higher spike-in counts indicate less target enrichment
    - **FRiP**: Report it from `qc/{sample}.frip_mqc.tsv`, which has one row per peak set called for the sample (SEACR stringent and/or relaxed, and/or MACS2), and judge each against the QC table (>10% pass, 5-10% warning, <5% fail). The value is the fraction of the filtered BAM's alignments that overlap a peak, so mates of a pair count separately; the `Peak set` column names the peak file each row refers to
    - **Signal track paths**: Provide paths to the `signal/{sample}.normalized.bw` files (spike-in scaled, or RPKM if spike-in was skipped) for genome browser visualization
    - **Fragment size distribution**: From `qc/{sample}.fragment_sizes.txt`, confirm the expected nucleosomal ladder pattern and note the dominant fragment class (sub-nucleosomal for TFs, mononucleosomal for histone marks)
    - **Key QC metrics**: Present mapping rate (>80%), duplication rate (<20%), and spike-in calibration status in a summary table
    - **Blacklist filtering**: State that `--blacklist` was applied to the BAM and that the peak files are unfiltered; note separately whether a suspect list was merged into `--blacklist` or applied to the peaks manually
    - **Next steps**: Suggest `peak-annotation` for gene association of peaks, or `visualization-workflow` for genome browser session generation
    
    ## For the request: "$ARGUMENTS"
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related