Changelog
Unreleased
Section titled “Unreleased”Changes
Section titled “Changes”- New
--clump_onlyspecialty mode — lossless reorder-only mode requested in #353. Reorders FASTQ records by canonical 16-mer minimizer for gzip-friendly compression, without any trimming, filtering, or adapter detection. Output records are byte-identical to input records (header, sequence, quality); only file-level order changes. Composes with--compression,--memory,--cores,--paired,--fastqc,--dont_gzip, and--basename. Trim/filter flags (-a,--length,--rrbs,--polyA,--polyG,--rename,--discard_untrimmed, other specialty modes,--passthrough,--retain_unpaired,--output-format ubam) are rejected at CLI validation. Produces*_clumped.fq(.gz)outputs and a short*_clumping_report.txt(deliberately distinct from*_trimming_report.*so downstream nf-core/MultiQC pipelines don't scan an empty-of-trim-stats file). Byte-identity + cross-run determinism are enforced by CI (record- multiset diff + md5 cross-run check). FASTQ in/out only in v1; uBAM in/out is a natural follow-up. Contract-scope note: the byte-identity claim covers the three semantic fields — the plus-line (line 3) is normalized to bare+on output, and CRLF line endings are normalized to LF, matching existing codebase-wideFastqReader/FastqWriterbehaviour. trim_galorewith no arguments now prints the full help and exits 0, instead of the terseerror: the following required arguments were not provided: <INPUT>...usage error on stderr with a non-zero status. This matches the convention of most modern CLIs (help to stdout, success exit code). Explicit--help/--versionare unchanged, and genuine usage errors (e.g. an unknown flag, or--pairedwith no input files) still fail loudly on stderr with a non-zero status.- Tidied the
--helptext: removed developer-internal references (legacy Perlv0.6.xversion notes and internalPLAN.md/§pointers) that had leaked into user-facing flag descriptions. No behaviour change.
--fastqcnow runs on--output-format ubamoutput for both single-end and paired-end runs. The uBAM-output path previously silently skipped the bundled FastQC pass even when--fastqc(or--fastqc_args) was requested; the FASTQ-output path already honoured it.fastqc-rustreads BAM natively, so the report is generated directly from the trimmed*_trimmed.bam(SE) or the single interleaved*_val.bam(PE) — one FastQC report per output BAM, covering both mates in the PE case.
Version 2.3.0 (Release on 27 June 2026)
Section titled “Version 2.3.0 (Release on 27 June 2026)”The Formats Edition. Both directions of unaligned BAM (uBAM) now ship: TrimGalore reads uBAM transparently (auto-detected by content, paired-interleaved supported via a bounded de-interleaver, BAM aux tags fold into FASTQ headers via --preserve-tags) and emits uBAM via --output-format ubam (SE → *_trimmed.bam, PE → ONE interleaved *_val.bam matching samtools/Picard/fgbio convention, aux tags round-trip A/Z/i/f scalars). Pairs with Bismark's uBAM input support (Bismark#1026 + #1027) — the cross-tool TrimGalore-emits → Bismark-reads handshake is now first-class, and Bismark's test suite confirms byte-identity between TrimGalore's uBAM output and samtools fastq on real BS-seq data (SE + PE), so the transcoder is hermetically guarded at the byte level.
Also ships --passthrough for 10X Multiome cell-barcode carrier reads (paired-end + a third inline FASTQ kept in lockstep), and a corrected R2 poly-G trimming behaviour for 2-colour instruments (the artifact is sequencer-side and appears at the 3' end of both reads — was incorrectly trimming 5' poly-C on R2 before; reported by @K81ta in #321).
-
--poly_gnow correctly trims the 3' end of Read 2 (was trimming the 5' end as poly-C — wrong location for the 2-colour artifact). Reported by @K81ta in #321. The 2-colour poly-G artifact is sequencer-induced (the instrument calls "no signal" as a high-quality G when it overruns the template), which happens at the 3' end of every read regardless of strand orientation — unlike poly-A, which is a template feature (mRNA tail on the forward strand) and presents at opposite ends of R1 vs R2 in the reverse-complement orientation. The original code copied the poly-Arevcomp = is_r2pattern, addressing the wrong location on R2. Stat labels and reports also updated from "R2 poly-C" to "R2 poly-G".Behaviour change: R2 records with 3' poly-G tails are now trimmed (previously untouched); R2 records that happened to start with a poly-C run on their 5' end are no longer trimmed by
--poly_g(that was the bug). No effect on--poly_a/ poly-T handling. No effect on R1 / single-end (only the R2 path changed). v0.6.x Perl byte-identity unaffected (--poly_gis a v2.x-only feature, no Perl baseline).
New input formats
Section titled “New input formats”-
uBAM (unaligned BAM) input support (#316). Trim Galore now accepts unaligned BAM (uBAM) alongside FASTQ. Auto-detection is content- based — first byte for plain FASTQ, decompressed-payload
BAM\1magic for uBAM (sobgzip x.fqBGZF-framed FASTQ is correctly classified as FASTQ, not BAM). Works at single-end (trim_galore sample.bam) and paired-end with a single interleaved BAM file (trim_galore --paired interleaved.bam); the paired-end de-interleaver streams the BAM through a bounded-buffer (per-side cap of 1024 records) and errors loudly with asamtools collateremediation pointer on grouped (non-mate-adjacent) input. All standard uBAM-emitting tools — samtools sort-n/ collate, PicardFastqToSam, fgbioFastqToBam— produce mate-adjacent output and work transparently.Aligned BAM is rejected per-record (not only at the first record) so mixed-aligned inputs cannot silently produce wrong output. The implementation uses the pure-Rust
noodles0.88 umbrella crate (exact-pinned, BAM feature only — no async, no tokio) sharing the version already pulled transitively viafastqc-rust 1.0.1, so the release-binary size delta is zero. Output defaults to FASTQ; opt-in uBAM output is available via--output-format ubam(see below).
New output formats
Section titled “New output formats”-
uBAM (unaligned BAM) output via
--output-format ubam(#315). Single-threaded in v1;--cores Nis silently ignored on this path (uBAM-in → uBAM-out is bottlenecked by single-threaded BGZF decompression anyway). Single-end output is<stem>_trimmed.bam; paired output is ONE interleaved BAM (<stem>_val.bam) withFREAD1/FREAD2flag bits per record, matching samtools/Picard/fgbio/CellRanger convention and TrimGalore's own paired-uBAM-input de-interleaver expectation.The input SAM header (
@HD/@PG/@CO/@RG) is propagated as-is and atrim_galore @PG VN:<version> CL:<command-line> PP:<prev-pg-id>line is appended on every run — output is NOT byte-identical to input, but provenance is preserved by adding to history. For FASTQ input, a minimal@HD VN:1.6+ trim_galore@PGheader is synthesised.Aux tags from uBAM input round-trip through trimming when
--preserve-tagsis set: BamReader folds the tag-list into a textual\tTAG:TYPE:VALUEtail on the FastqRecord id; BamWriter parses it back into typed BAM aux fields. Only A (char), Z (string), i (i32), and f (f32) scalar types round-trip; B (array) and H (hex) types are rejected at the writer with an explicit error. BAMi:tags originally stored as int8/int16/int64 are re-emitted as int32 (lossless for all biologically meaningful tag values).Specialty modes
--hardtrim5/3are supported with--output-format ubam(output:<stem>.<N>bp_{5,3}prime.bam). The following are rejected at the CLI layer in v1:--clumpify,--passthrough,--clock,--implicon,--demux,--retain_unpaired— each produces multiple output files or encodes metadata in FASTQ headers in ways that don't translate cleanly to BAM in v1.
New flags
Section titled “New flags”-
--preserve-tags TAG1,TAG2,…— fold BAM aux tags into the FASTQ header (#316). Tab-separated, samtools-T-compatible. Each tag must be a valid 2-character SAM tag name ([A-Za-z][A-Za-z0-9]); the reservedALLkeyword is rejected in v1. Tag order in the output header matches the user-specified order, NOT the BAM file's aux-field order. Missing per-record tags are silently skipped. Ignored for FASTQ input (emits a stderr warning). -
--passthrough <FILE>— Multiome / scATAC cell-barcode carrier mode (#305). Adds a third FASTQ input that is carried through unchanged but kept in lockstep with R1 and R2 — any pair dropped by length / quality / N filters also drops the matching record from the passthrough output. Designed for 10X Multiome ATAC-seq workflows where the modified ATAC adapter is opaque to Cellranger Arc; users can now trim R1 / R2 against their own-a/-a2while the cell-barcode (I1 / I2 / R3) read stays aligned to the survivors in a single invocation. Per-record three-way header sync check across the three streams (handles both modern Illumina@HEADER 1:N:0:CGATCGand legacy@read/1@read/2@read/3styles), with a row-numbered hard-error on any mid-stream desync. Works at--cores 1(serial) and--cores N(parallel worker pool). Adds a=== Passthrough file ===block to the R2 trimming report and a"passthrough"object to the JSON report. Requires--paired+ exactly one R1/R2 pair; incompatible in v1 with--retain_unpaired,--clumpify, and all specialty modes (--clock,--implicon,--hardtrim5/3,--demux). See Multiome passthrough for the full guide.
Version 2.2.0 (Release on 7 May 2026)
Section titled “Version 2.2.0 (Release on 7 May 2026)”The Clumpify Edition. Opt-in read-reordering for tighter .fq.gz output via canonical 16-mer minimizer sort, with empirically-validated guidance on which data types benefit and which are hurt. Ships alongside a new --compression knob that decouples gzip level from reordering, and a new tool-wide --memory budget. Co-developed with Phil Ewels (PR #282) — see Clumpy compression for the full benchmark table and use-case guidance, and docs/perf_data/clumpify-{buckberry,rrbs}-2026-05-07/ for the WGBS-vs-RRBS contrast that motivated the per-data-type recommendations.
The headline rule of thumb (in clumpy.md's When-to-use section): clumpify helps on low-complexity paired-end data where biology produces fragment-level clustering (ATAC, Ribo, RRBS, RNA-seq, WES, MiSeq amplicons — savings ~15–55%), and hurts on high-complexity coverage-diverse paired-end data (WGBS PE, scRNA-seq R2 — output grows because R2 follows R1's minimizer order and loses its natural flowcell-cluster locality). The split is driven by the same R2-disruption mechanism that affects 10x scRNA-seq.
New flags
Section titled “New flags”--clumpifyopt-in compression mode. Boolean flag that reorders reads inside each gzip member of the trimmed output by canonical 16-mer minimizer so reads sharing similar sequence land adjacent on disk; gzip's 32 KB dictionary then finds long redundant runs and shrinks the.fq.gzby 15–55% depending on data type (see Clumpy compression for the full benchmark table). No information loss — only the on-disk order of records changes; trimming reports are byte-identical.--compression <N>(1–9, default 1). New flag that controls the output gzip level independently of--clumpify. Use--compression 6or--compression 9for smaller files at higher CPU cost; combine with--clumpifyfor maximum compression. Replaces the earlier--clumpy=<LEVEL>optional-value form, which conflated reordering with level selection.--memory <SIZE>global memory budget (default1G). Currently used only by--clumpifyfor bin buffer sizing. The layout formula now targets predicted peak RSS ≤--memory(bin pool + worker batches + static overhead all accounted), so the budget is honest rather than notional — measured peak matches predicted peak within 1% on 31 M-record paired-end runs. A fixed 512 MiB is reserved up front for FastQC + allocator + runtime; the rest funds the bin pool and worker batches. Bigger budgets give bigger per-gzip-member sort runs and better compression. Diminishing returns are sharp — going from 1G to 8G adds only ~4 percentage points of saving on typical short-read data. If--memoryis below the floor (~552 MiB at--cores 6), Trim Galore prints a loud warning and falls back to plain mode rather than refusing the job. Replaces the--clumpy_memoryflag from earlier development branches.--high_compressionremoved. Subsumed by the new--compression <N>flag. Users who previously passed--high_compressionfor level-6 archival output should switch to--compression 6(or--clumpify --compression 6to also benefit from reordering).--high_compressionshipped in v2.1.0 GA — this is a real removal, not a pre-release shim. Existing pipelines that pass it will need to swap; the rewrite is a one-line CLI change.
Other changes
Section titled “Other changes”- Integer-arithmetic
max_errorsin adapter alignment (#287, #262 Item A). Replaced four call sites of(max_error_rate * len as f64).floor() as usizeinfind_3prime_adapterandmyers_proves_no_matchwith integer math, eliminating a per-read libmfloor()call that pprof attributed at 0.21% leaf self-time on the Buckberry fixture. Byte-identical to the float form for any non-negative integer length; determinism is better (no f64 rounding-mode dependency). Win: ~0.2% wall — small but it's free, and the parity matrix confirms byte-identity across all 19 flag paths. - Memory & I/O reference data added to the Threading model docs page (#287). Memory profile section now contextualises TG v2's <100 MB peak vs Cutadapt 100–300 MB / fastp 100+ MB / BBDuk 1–4 GB, plus a new "I/O and cache behaviour" subsection covering disk-bandwidth-comfortable I/O and the L3-cache-pressure mechanism behind the
--cores ≥ 16diminishing-returns plateau. Audit-trail data captured by @an-altosian's #263 and #264 characterization reports.
Version 2.1.0 (Release on 4 May 2026)
Section titled “Version 2.1.0 (Release on 4 May 2026)”First stable release of the Oxidized Edition — a complete Rust rewrite of the original Perl Trim Galore. Drop-in compatible with v0.6.x scripts and pipelines (same CLI, same output filenames, same report format). Single static binary, zero external runtime dependencies — no Python, Perl, Cutadapt, Java, igzip, or pigz required.
Highlights
Section titled “Highlights”- Built-in FastQC via the bundled
fastqc-rustlibrary. Pass--fastqcand it just works (no externalfastqcbinary, no Java runtime). - Adapter auto-detection for Illumina, Nextera, Small RNA, and BGI/DNBSEQ on the first 1M reads. Per-pair detection in paired-end mode (intentional improvement over Perl v0.6.x's once-per-run detection).
- Multi-adapter support via repeatable
-a/-a2or-a "file:adapters.fa"to load adapter sets from FASTA. Optional multi-round trimming (-n N). - Poly-G trimming for 2-colour instruments (NovaSeq, NextSeq,
NovaSeq X), auto-detected from the data; opt-out with
--no_poly_g. - Generic poly-A trimming for mRNA-seq libraries (
--poly_a). - Worker-pool parallelism via
--cores N— near-linear speedup up to ~8 cores on Buckberry-scale data; saturation point depends on per-thread compute vs gzip-output I/O bandwidth on your storage. - Reproducible builds via
SOURCE_DATE_EPOCH; release binaries are bit-identical when built twice with the same input. CI verifies this. - Byte-identity to Perl v0.6.11 asserted by the CI validation matrix across SE, PE, RRBS, hardtrim5, Clock, and demux flag paths.
Performance vs Trim Galore 0.6.11 + Cutadapt 5.2
Section titled “Performance vs Trim Galore 0.6.11 + Cutadapt 5.2”Headline numbers from the Buckberry-scale benchmarks on 84M paired-end reads (Intel Xeon 6975P-C, Granite Rapids):
- 5.93× less CPU time at
--cores 8(the nf-coreprocess_highdefault) — ~$7 vs ~$41 per 1000-sample cohort at AWS $0.05/vCPU-hour - 13.49× less CPU time at single-thread
- 4.54× faster wall time at
--cores 8: 57s vs 257s on the 84M paired-end fixture
Opt-in flags
Section titled “Opt-in flags”--high_compression— gzip output level 6 instead of the default level 1 (~75% smaller files, ~2× slower trimming). For archival workflows where trimmed reads are deliberately retained downstream; the dominant nf-core / Snakemake / CWL use case keeps trimmed FASTQs ephemeral and benefits from the faster default level 1.
Migration from v0.6.x
Section titled “Migration from v0.6.x”The CLI surface is unchanged from v0.6.x for the dominant workflows.
Most users will see no behavioural changes — the biggest visible change
is performance. A few minor differences (mostly improvements: brace
expansion -a A{N}, -r1/-r2 short flags now parse cleanly,
multi-pair specialty modes) are documented in the
v2 migration notes.
Cumulative changes from the v2.1.0 beta arc
Section titled “Cumulative changes from the v2.1.0 beta arc”This GA release ships the cumulative changes from v2.1.0-beta.1 through v2.1.0-beta.8. The Buckberry-scale performance audit (#248, co-authored with @an-altosian — Dongze He, Altos Labs) drove the headline performance wins:
- beta.6: gzip output level 6 → 1 (~−23% wall, ~−43% CPU at saturation; output bytes ~75% larger; decompressed bytes byte-identical)
- beta.6: single buffered write per FASTQ record (~−10% wall)
- beta.7: Myers' bit-parallel adapter alignment prefilter (~−13% wall, byte-identity-preserving by construction)
- beta.8:
--high_compressionopt-in flag for storage-bound users
See the per-beta release notes below for full per-step detail.
Version 2.1.0-beta.8 (Release on 30 Apr 2026)
Section titled “Version 2.1.0-beta.8 (Release on 30 Apr 2026)”New feature
Section titled “New feature”--high_compressionopt-in flag. Sets gzip output level to 6 (smaller files, slower trimming) instead of the default level 1 (faster trimming, ~75% larger output bytes). Useful when storage cost or transfer bandwidth matters more than runtime — archival workflows, shared object stores. Decompressed output is byte-identical regardless of level (gzip levels 1 and 6 are both lossless; only the framing differs). The flag flows throughTrimConfig, the worker pool's per-batchGzEncodercallsites, the sequential output writer, every specialty mode (--hardtrim5/--hardtrim3/--clock/--implicon), and--demux. Counter-lever to the v2.1.0-beta.6 default of level 1. Trade quantified by the v2.1.0-beta.7 Buckberry benchmark: at saturation (cores=8) on the 84M-read fixture, lowering level 6 → level 1 saved ~−23% wall and ~−43% CPU;--high_compressionreverses that trade for users who want the smaller files back.
Version 2.1.0-beta.7 (Release on 29 Apr 2026)
Section titled “Version 2.1.0-beta.7 (Release on 29 Apr 2026)”Performance (since v2.1.0-beta.6) — third Buckberry-scale win (#248 #4)
Section titled “Performance (since v2.1.0-beta.6) — third Buckberry-scale win (#248 #4)”- Myers' bit-parallel adapter alignment prefilter. Wraps an O(n)
bit-vector approximate-matching pass (Hyyrö 2001 formulation) in
front of the existing scalar DP in
find_3prime_adapter. The prefilter is conservative by design — it short-circuits ONLY when it can rigorously prove that no adapter match exists, considering both the full-match (last DP row) and partial-match (last DP column) cases. False positives fall through to the unchanged scalar DP, keeping the byte-identity invariant intact by construction. Limited to adapters ≤ 64 bp (single u64 bit-vector; the project's adapters are all ≤ 32 bp). End-to-end byte-identity verified locally and by the CI validation matrix; Dongze's Buckberry-scale measurement (84M reads, 38% adapter rate, cores=8) was −13.6% wall on his prototype, so this lands the third and final perf win from the #248 audit. Co-authored with @an-altosian (Dongze He). (#258)
Documentation (since v2.1.0-beta.6)
Section titled “Documentation (since v2.1.0-beta.6)”- Migration guide note on
-a 'A{N}'poly-A divergence. Closes #245 item B as intentional / not-pursued: brace expansion is byte-identical between Perl and Rust, but the alignment DP's tie-break behaviour on highly-repetitive adapter patterns differs between Cutadapt and our reimplementation. Both produce valid global-best alignments. The dedicated--poly_aflag is the right v2 path for poly-A trimming; the-a 'A{N}'form remains supported as a v0.6.x compat shim. (#257) - GHCR tag prefix correction. Docker images carry the
vprefix (:v2.1.0-beta.6), not bare semver — verified against/v2/.../tags/list. Docs install table fixed; the prior:2.1.0-beta.6example was 404. README Docker example switched from implicit:latest(which doesn't exist during prerelease) to:beta, with the full tag set documented inline. (#256)
Version 2.1.0-beta.6 (Release on 29 Apr 2026)
Section titled “Version 2.1.0-beta.6 (Release on 29 Apr 2026)”Performance (since v2.1.0-beta.5) — Buckberry-scale audit (#248)
Section titled “Performance (since v2.1.0-beta.5) — Buckberry-scale audit (#248)”Profiled, prototyped, and benchmarked by @an-altosian against an
84M-read single-end Bisulfite-Seq fixture (Buckberry et al. 2023,
SRR24827373, 2.1 GiB gzipped, 38% adapter rate) using hyperfine
with 10 trials per condition. Two of the three confirmed wins from
that audit landed here; item #4 (Myers' bit-parallel adapter
alignment, ~13% additional reduction) is queued for a separate PR
from @an-altosian.
- Output gzip compression level lowered 6 → 1. Compression CPU
was the dominant wall-time consumer on saturated workers
(cores=8) — at level 6, gzip output dwarfed actual trimming work.
Lowering to level 1 (fastest) measured −23.3% wall-clock
(69.693 ± 0.200 s → 53.471 ± 2.135 s) and −43% user-CPU
(593.9 s → 338.7 s) at Buckberry scale. Trade: output
.fq.gzfiles are roughly 75% larger (273 KB → 479 KB on the local BS-seq_10K_R1 smoke). Decompressed content is byte-identical to the previous output — the CI validation matrix'sgzip -dc | md5sumcomparisons against Perl v0.6.11 still pass on every flag path. Newpub const OUTPUT_GZIP_LEVELinsrc/fastq.rscentralises the level so a future--high-compressionopt-in flag is a one-line change for storage-conscious users. (#248 #1) - Single buffered write per FASTQ record. Pre-format the
4-line record into a
Vec<u8>, then issue onewrite_allinstead of four separatewriteln!calls. Byte-identical output (md5 match verified end-to-end on BS-seq_10K_R1). At Buckberry scale this measured 9.8% wall-clock reduction (69.693 ± 0.200 s → 62.862 ± 0.352 s) by amortising the per-call Write-trait overhead. (#248 #2)
Bug fixes (since v2.1.0-beta.5) — Perl-parity regressions (contributor-reported)
Section titled “Bug fixes (since v2.1.0-beta.5) — Perl-parity regressions (contributor-reported)”-
--basename foo --pairednow producesfoo_val_1.fq.gz/foo_val_2.fq.gz, notfoo_R1_val_1.fq.gz/foo_R2_val_2.fq.gz. The_R{1,2}segment was interpolated between the basename and the_val_{1,2}suffix inio::paired_end_output_namesandio::unpaired_output_names, breaking the documented Perl v0.6.5+ filename contract — every nf-core / Snakemake pipeline globbing the documented${basename}_val_*path silently missed outputs under v2.1.0-beta.5. Trimmed read content was unaffected, only the filenames differed. Two regression tests added covering the basename branches of both functions. Reported by @an-altosian during the Phase-1C parity hunt. (#244) -
Lowercase clip-flag spellings (
--clip_r1,--clip_r2,--three_prime_clip_r1,--three_prime_clip_r2) are now accepted. Perltrim_galoreaccepted both lowercase and uppercase spellings; the Rust port matched the uppercase canonical only and rejected the lowercase forms with a clap parse error (exit 2). Every Perl-era pipeline using the documented lowercase spelling broke under v2.x. Added lowercase aliases on all four flags. Reported and diagnosed by @an-altosian during a Phase-1B Perl-parity hunt. (#242) -
Output gzip compression now mirrors input compression by default. Plain
.fastqinput → plain.fqoutput;.fastq.gz→.fq.gz. Restores Perl v0.6.x behaviour. Rust v2.1.0-beta.5 always emitted gzipped output regardless of input, breaking pipelines that globbed*.fq(no.gz) for outputs from plain-text inputs.--dont_gzipstill works as the explicit "always plain" override. The first input determines the mode for the whole run; mixing plain and gzipped inputs in one invocation isn't a supported configuration. Reported by @an-altosian via #245 (item A). -
--retain_unpairednow routes both mates independently to their unpaired files when both mates fail the discard--lengthcutoff, if each is individually long enough for the per-side--length_{1,2}threshold. Rust v2.1.0-beta.5 had an extra!r{1,2}_shortclause infilters::filter_paired_endthat gated unpaired rescue on the read itself passing the discard cutoff, which silently dropped reads when both mates failed--lengthtogether but were individually long enough. Matches Perlmaster:trim_galore:2325-2343. Slight caveat: Perl's behaviour diverges from its own user-guide wording ("rescue the surviving mate"); we match the implementation, not the docs, to preserve byte-identity for the documented byte-identity flag paths. Regression test added. Reported by @an-altosian via #245 (item C).
Behavioural notes (v2.x intentional widenings, since v2.1.0-beta.5)
Section titled “Behavioural notes (v2.x intentional widenings, since v2.1.0-beta.5)”--clockand--impliconnow imply--paired— passing either flag without--pairedis no longer rejected. Both modes are inherently paired-end specialty modes; requiring users to pass--pairedredundantly was noise. Pipelines using the explicit Perl form (--clock --paired/--implicon --paired) continue to work unchanged. Consistent with the multi-pair widening pattern documented for these specialty modes in beta.4. Surfaced by @an-altosian via #245 (item D).
Bug fixes (since v2.1.0-beta.5) — Perl-parity regressions (contributor-reported, continued)
Section titled “Bug fixes (since v2.1.0-beta.5) — Perl-parity regressions (contributor-reported, continued)”--max_nfraction-mode now logs the Perl-style notice on entry ("--max_n will be interpreted as a fraction of the read length (0.5)"). Investigating @an-altosian's #243 confirmed the dispatch and filter chain behave correctly: values in(0.0, 1.0)already buildMaxNFilter::Fractionandn_count/length > thresholdfiltering matches Perl v0.6.8+ behaviour byte-for-byte. The reproducer-fixture's max-N fraction (3/153 ≈ 0.02) just doesn't exceed the 0.5 threshold, so neither implementation filters anything — not a bug. Adding the same warning Perl prints (master:trim_galore:3328) makes the selected mode visible at runtime so users don't have to derive it from output statistics. (#243)
Bug fixes (since v2.1.0-beta.5)
Section titled “Bug fixes (since v2.1.0-beta.5)”-o/--output_dir DIRno longer hangs whenDIRdoesn't exist. The parallel paired-end path opened output files via rawFile::create, which fails immediately on a missing parent — but by then reader and worker threads were already spawned, the?exit dropped the receiver channel, and the process deadlocked at near-zero CPU (workers stuck producing into a queue with no consumers). Reported via beta.5 user feedback (24h wall / 4s CPU on a SLURM cluster). Fix: hoistcreate_dir_allintomain()immediately after CLI parse, covering every downstream code path (parallel, single-threaded, paired, single-end, every specialty mode) in one place. Restores Perl v0.6.x behaviour ("If an output directory which was specified with -o output_directory did not exist, it will be created for you", v0.6.0 changelog).
Tests (since v2.1.0-beta.5) — coverage gaps closed (#246)
Section titled “Tests (since v2.1.0-beta.5) — coverage gaps closed (#246)”Five new unit tests landed across report.rs, demux.rs, fastq.rs,
and adapter.rs. Closes 5 of the 6 §5.x items from the test-coverage
audit. Total test count: 171 → 177. Items still open from #246:
parallel/serial stat-tracking parity (§5.2), comprehensive
parallel.rs coverage, optional upstreaming of @an-altosian's
proptest harness — tracked as separate followups.
-
§5.4 PE param-summary
removed-end:regression guard (report.rs::tests). Beta.3 fixed a stray-endsuffix in the paired-end parameter-summary line (...sequence pair gets removed-end: 20 bp→...removed: 20 bp); MultiQC parsers grep for the literalremoved:form. Test renders the PE header and asserts both!contains("removed-end")and the canonical phrase — any reintroduction of the typo class fails the assertion. -
§5.5 Demux CRLF samplesheet handling (
demux.rs::tests). Windows-authored barcode sheets use\r\nline endings; without thetrim_end_matches('\r')strip inread_barcode_file, the trailing\rwould pollute the parsed barcode and fail the ACGTN-only validator with a confusing "barcode must contain only A, C, T, G, N" error. Test writes a CRLF samplesheet and asserts no stray\rsurvives on any parsed entry. -
§5.6 Demux short-read NoCode routing (
demux.rs::tests). When a trimmed read is shorter than the barcode length,demultiplex(src/demux.rs:178-187) routes it to the NoCode bucket instead of slicing past the read end. End-to-end test: fixture with one 5 bp read, one non-matching 16 bp read, and one matching 16 bp read; asserts both NoCode-bound reads land in*_NoCode.fq(with cleared seq+qual for the too-short one) and the matching read lands in the per-sample bucket. Together with §5.5 closes thedemux.rszero-tests module gap. -
§5.1 Multi-member gzip reader round-trip (
fastq.rs::tests). The parallel writer (--cores N) emits each worker's chunk as its own gzip member; the concatenated stream is a valid RFC 1952 multi-member gzip file. Test crafts a 2-member buffer withGzEncoder::finishtwice, concatenates, and assertsFastqReader(usingMultiGzDecoder) yields records from BOTH members in order. Originally fixed in9dcf519(pre-beta.1) but never had a unit-level regression test. -
§5.3 Adapter auto-detect
MAX_SCAN_READSboundary (adapter.rs::tests). The 1M-read scan cap was unverified at the unit level; generating a >1M-read fixture per test run is too slow. Refactored: extractedautodetect_adapter_with_max_scan(crate-private) so tests can exercise the sameincrement-then- breakcontrol flow at scale 7. Two paired tests: cap-bounded (input has 100 records, max_scan=7, assertsreads_scanned == 7and matches < 100) and cap-unbounded (input has 50 records, max_scan=1M, asserts full-file scan). Publicautodetect_adapterAPI unchanged.
Tests (since v2.1.0-beta.5) — parallel/serial stats parity (#246 §5.2)
Section titled “Tests (since v2.1.0-beta.5) — parallel/serial stats parity (#246 §5.2)”parallel::run_single_end_parallelandtrimmer::run_single_endmust yield field-identicalTrimStatson the same input. First unit test insrc/parallel.rs(closes the zero-tests module gap noted in #246). Beta.0/1 had per-field stat drift between the two paths (commits 82d1e34, 3996fc5 fixedtotal_bp_after_trim/rrbs_r2_clipped_5prime); this test locks the invariant down at the unit level.TrimStatsgained aPartialEqderive so a singleassert_eq!covers every field — any future field added to the struct is automatically covered without test edits. Closes #246 §5.2.
Infrastructure (contributor-facing, since v2.1.0-beta.5) — CI hardening (#247)
Section titled “Infrastructure (contributor-facing, since v2.1.0-beta.5) — CI hardening (#247)”The five remaining deferred items from the original CI audit landed
in this round (items 2, 3, 4, 7 — item 8 cargo-nextest deferred
pending a focused per-test-isolation audit since some existing tests
share std::env::temp_dir().join(...) paths):
- #247 item 2 — macOS matrix on
rust-tests. Job now runs on bothubuntu-latestandmacos-latest(Apple Silicon hosted runner). Catches Apple-Silicon-specific regressions before release-tag time.fail-fast: falseso an OS-specific failure on one entry doesn't kill the other. - #247 item 3 — release-profile test step. New
Run tests (release)step alongside the existing debug-profile run. Catches LTO +codegen-units=1interactions that the default debug build doesn't see. Cheap because the next step (cargo build --release) was already populating the same target dir. - #247 item 4 — line/branch coverage reporting via
cargo-llvm-cov. Newcoveragejob emits an LCOV file as a CI artifact (downloadable from the Actions run UI) plus a text summary in the job log. No third-party uploader integration — Codecov / Coveralls is a separate decision. - #247 item 7 —
justfilefor local CI parity. New top-leveljustfilewith targetsfmt,clippy,test,test-release,ci,reproduce,validate-paired-end,logos,docs. Runjust(orjust ci) to execute the same portable checks CI runs on every push. Pairs cleanly with the contributor docs flow.
Three CI improvements landed from @an-altosian's audit (#247). Touches
only .github/workflows/ci.yml; no runtime change.
- Validation outputs uploaded on failure. When any md5 oracle
step fails, the
/tmp/tg,/tmp/op*, and/tmp/*.logpaths that triggered the mismatch were previously lost when the runner cleaned up. Newif: failure()step uploads them as a 7-day artifact undervalidation-outputs-<run_id>-<attempt>. Especially useful for reviewing perf PRs that intentionally change output bytes (e.g. a default gzip-level change) — the new artefacts can be diffed against the Perl baseline directly. - Perl Trim Galore source fetched from local
masterinstead ofraw.githubusercontent. The Perl v0.6.x release line lives atmaster:trim_galorein this repo; replacing the curl withgit fetch --depth=1 origin master && git show origin/master:trim_galoregives byte-identical content with zero external network dependency, eliminating a class of CI flake. - Cutadapt bioconda revision pinned (
cutadapt=5.2=*_0). The validation matrix uses Cutadapt's output as the Perl-side oracle, so an unannounced bioconda revision bump (5.2-1, etc.) could silently shift the md5 baseline. Pin to the first build of 5.2 so any rev bump becomes a visible CI failure rather than invisible drift.
Bug fixes (since v2.1.0-beta.5) — surfaced by the nf-core pre-GA validation review
Section titled “Bug fixes (since v2.1.0-beta.5) — surfaced by the nf-core pre-GA validation review”- RRBS samples:
Total written (filtered)cutadapt-section line now matches Perl v0.6.x byte-for-byte. Beta.4'seedbc66MultiQC-parity fix introducedtotal_bp_after_trim(incremented after the full per-read trimming pipeline) but didn't account for the--rrbs2 bp 3' truncation. The reported value drifted from v0.6.x byRRBS-trimmed-reads × 2 bp.TrimResultnow carries abp_after_cutadaptfield captured immediately after quality + adapter trimming and before RRBS / poly-A/G / N-trim / clipping, and that's what drivestotal_bp_after_trimin both single-end and paired-end pipelines. Trimmed FASTQ output is unchanged — this fix only affects the reported count. (#232) RUN STATISTICSfilter-removed lines are now always emitted, even when the count is 0. Theif stats.too_short > 0/too_long/too_many_nguards (and the PE counterpartpairs_removed_nline) caused MultiQC's canonical fallback parser to break on samples that pass 100% of reads through length / max-N filters — the parser greps for the exact line and treats absence as a parse failure. v0.6.x always emits the line. Now we do too, with zero-protected percentage display. (#233)
Documentation (since v2.1.0-beta.5)
Section titled “Documentation (since v2.1.0-beta.5)”- Migration notes: trimming-report behaviour changes vs Perl v0.6.x. The
pre-GA review surfaced four intentional report-text changes that were not
filed because they match the v2.x reference report attached to MultiQC #3529.
Documented for users / parsers expecting the v0.6.x shape:
- RRBS quality-trim line shape changed from
Sequences were truncated to a varying degree because of deteriorating qualities …: N (P%)(counts reads, v0.6.x RRBS only) to the cutadapt-styleQuality-trimmed: N bp (P%)(counts bp, v2.x both modes). Non-RRBS mode is unchanged in both implementations. v2.x is more consistent across modes, but a regex tuned to one shape won't match the other. (#234) - Adapter family-name annotation dropped — v2.x emits the bare
sequence (e.g.
'AGATCGGAAGAGC') where v0.6.x emitted family names (Illumina TruSeq, Nextera, smallRNA). The family is still tracked internally but not rendered in the report. - "Bases preceding removed adapters" histogram omitted from the
=== Adapter N ===block. - Per-adapter "Minimum overlap" line not repeated under each adapter block (the same datum is in the parameter summary at the top).
- Length-distribution
max.errcolumn uses the modern Cutadapt formulafloor(L × error_rate). v0.6.x's display capped this at 1 in many positions. Thecountcolumn is unchanged byte-for-byte.
- RRBS quality-trim line shape changed from
Version 2.1.0-beta.5 (Release on 27 Apr 2026)
Section titled “Version 2.1.0-beta.5 (Release on 27 Apr 2026)”Bug fixes (since v2.1.0-beta.4)
Section titled “Bug fixes (since v2.1.0-beta.4)”- Bundled FastQC: percentage precision in
>>Overrepresented sequences. Bumpsfastqc-rustdep from v1.0.0 to v1.0.1, which restores Java FastQC 0.12.1 byte-identity in that section. v1.0.0 rounded the percentage column to 2 decimals (7.16) instead of emitting Java's fullDouble.toString()precision (7.160449112640348). Detected during thenf-core/rnaseq#1789integration matrix on NF 25.04.3, where the older pinned MultiQC preserves the literal percentage string when aggregating intofastqc_trimmed_overrepresented_sequences_plot.txt, so the truncated value cascaded into a downstream MD5 mismatch. Fix filed and merged upstream as ewels/FastQC-Rust#2. Detected sequences, counts, and source classification were always correct — this was a cosmetic formatting deviation, not a scientific one.
Version 2.1.0-beta.4 (Release on 26 Apr 2026)
Section titled “Version 2.1.0-beta.4 (Release on 26 Apr 2026)”New features (since v2.1.0-beta.3)
Section titled “New features (since v2.1.0-beta.3)”- Bundled FastQC.
--fastqcnow uses the fastqc-rust library directly instead of shelling out to an externalfastqcbinary. Removes Java and the FastQC tarball as runtime dependencies — completes the "single static binary, zero external runtime deps" story for v2.x. Output files (*_fastqc.html,*_fastqc.zip) are FastQC 0.12.1- compatible (the same version we previously bundled in the Docker image), so MultiQC parsers and downstream pipelines see identical structure. The Docker image is correspondingly slimmer (nodefault-jre-headless, noperl, no FastQC tarball; saves approximately 350 MB at the runtime layer). (#226)--fastqc_argscontinues to accept the common subset (--nogroup,--expgroup,--quiet,--svg,--nano,--nofilter,--casava,-t/--threads,-o/--outdir); other flags emit a warning and are ignored — forward-compat with future fastqc-rust additions.--helptext for--fastqcand--fastqc_argsrefreshed to describe the bundled integration and enumerate the translated flag set;docs/SUMMARY.mdarchitecture-shift paragraph and parity table updated accordingly. (#227)
Bug fixes (since v2.1.0-beta.3)
Section titled “Bug fixes (since v2.1.0-beta.3)”--clockand--impliconnow accept multi-pair input (an even number of files as consecutive R1/R2 pairs), restoring v0.6.x semantics that the v2.x rewrite had narrowed to "exactly 2 input files". Same widening as the--pairedfix in beta.2 — the two specialty run-and-exit modes had their own validation that wasn't updated at the time. Each pair gets a per-pair header (=== Clock pair N of M ===/=== IMPLICON pair N of M ===) and the same output-collision pre-flight (case-insensitive on full path) that--pairedruns. (#224)
Infrastructure (contributor-facing)
Section titled “Infrastructure (contributor-facing)”rust-versionbumped from 1.85 → 1.88 (required by fastqc-rust)..gitattributesadded so the GitHub repo language bar reflects the actual Rust content rather than HTML indocs/. (#225, contributed by @ewels)
Version 2.1.0-beta.3 (Release on 24 Apr 2026)
Section titled “Version 2.1.0-beta.3 (Release on 24 Apr 2026)”New features (since v2.1.0-beta.2)
Section titled “New features (since v2.1.0-beta.2)”- BGI/DNBSEQ added to adapter auto-detection. Users running
BGI/MGI/DNBSEQ data no longer need to pass
--bgiseqexplicitly; the 32 bp BGI adapter is now probed alongside Illumina, Nextera, and smallRNA on the first 1 M reads. Stranded Illumina stays explicit-only (--stranded_illumina) because its sequence differs from Nextera by a single A-tail base and would produce constant ambiguous ties if probed. Tie-break semantics unchanged — the zero-count fallback is still Illumina. - Repeatable
-a/-a2multi-adapter syntax.-a SEQ1 -a SEQ2now works directly — no need for the v0.6.x embedded-string (-a " SEQ -a SEQ") or FASTA file workaround. Embedded-string andfile:adapters.faforms still work and can be mixed with repeated flags in a single invocation (e.g.-a " SEQ1 -a SEQ2" -a SEQ3). - Perl-style
A{N}single-base expansion for-a/-a2— e.g.-a A{10}expands to-a AAAAAAAAAA, matching Perl v0.6.x syntax. Only applied to the single-adapter case (not to multi-adapter or FASTA entries), mirroring Perl behaviour. - Perl-era
-r1/-r2/-a2short-flag forms are accepted. Clap's single-character short-flag rule meant-r1 40previously parsed as-r=1with40becoming a stray positional (producing a confusing "odd count" error). A small pre-parse hook now transparently rewrites the exact tokens-r1,-r2,-a2(and their=VALUEvariants) to the existing--r1,--r2,--a2long-alias forms so Perl-era scripts keep working.
Bug fixes (since v2.1.0-beta.2)
Section titled “Bug fixes (since v2.1.0-beta.2)”--trim-nis now suppressed under--rrbs, restoring Perl v0.6.x byte-identical output for users who combine both flags. Perl's RRBS code path omitted$trim_nfrom its Cutadapt invocations; beta.2 was applying N-trimming unconditionally, which narrowly violated the byte-identity guarantee for that specific flag combination.- The paired-end parameter-summary line in the text trimming report
previously emitted a stray
-endsuffix (...before a sequence pair gets removed-end: 20 bp). Now correctly emits...before a sequence pair gets removed: 20 bp. Single-end output (...length single-end: 20 bp) is unchanged.
Documentation
Section titled “Documentation”- Flag-by-flag help-text polish (#221). 25 docstring edits across
src/cli.rs. Most notable:--pairedno longer claims "exactly 2 input files" (the multi-pair fix from beta.2 made this stale);--rrbshelp now warns against Tecan Ovation kit incompatibility;--small_rnasurfaces its length auto-lowering side-effect;--bgiseqnotes it is also probed by auto-detection. - Positioning reframed from "byte-identical" to "faithful rewrite
with useful additions" (#222). The original framing no longer held
given new capabilities (poly-G handling, generic poly-A trimmer,
per-pair adapter detection, the above BGI auto-detect, etc.).
Updated in README, SUMMARY, User Guide, CHANGELOG, and the
--helppreamble. Benchmarks' "byte-identical across core counts" claims (which are about--coresdeterminism, not Perl equivalence) are retained where accurate. - User guide refreshed (#223). 534 → 325 lines. Dropped a ~220-line
duplicate of
--helpthat had been drifting out of sync on every polish cut; replaced with a curated "Flag reference" section on cross-flag interactions, RRBS-specific guidance (Tecan, MseI), and adapter-specification recap. Added IMPLICON coverage (missing from the original guide). Modernised the intro/framing, removed the floating Babraham logo (project now maintained solo outside Babraham), dropped the hand-maintained "Last update" line, and renamed theVersion 0.6.11section heading toIntroduction. Historical attribution preserved as a footer credit.
Infrastructure
Section titled “Infrastructure”- Test count grew from 106 → 147 across the beta.2→beta.3 window.
New coverage: multi-pair validation branches, specialty modes
(
--clock,--impliconend-to-end), adapter brace expansion, four-probe auto-detection set, Perl-era flag rewriting,--trim-n/--rrbsinteraction,parse_adapter_specsmixed-form path.
Version 2.1.0-beta.2 (Release on 20 Apr 2026)
Section titled “Version 2.1.0-beta.2 (Release on 20 Apr 2026)”New features (since v2.1.0-beta.1)
Section titled “New features (since v2.1.0-beta.1)”--versionnow prints build provenance on a second line:<git-hash> — <target> — built <ISO-8601 UTC timestamp>. The short form-Vremains unchanged (one line, matches the original terse format). Useful for bug reports — users can pastetrim_galore --versionto pinpoint the exact build.- Builds are now reproducible: setting
SOURCE_DATE_EPOCHto a fixed Unix timestamp (Debian reproducible-builds spec) produces a bit-identical binary across runs. Unset, the build stamps the current wall-clock time as before. Malformed values hard-fail the build rather than silently falling back.
Infrastructure (contributor-facing, no runtime effect)
Section titled “Infrastructure (contributor-facing, no runtime effect)”- New CI gates on every PR:
cargo fmt --check+cargo clippy -D warnings(lint), a dedicated reproducibility job that builds the release binary twice under a fixedSOURCE_DATE_EPOCHand asserts bit-identity, and a weeklyrustsec/audit-checkfor dependency advisories. - Dependabot enabled for cargo + github-actions ecosystems (weekly, Monday,
limit 5, routed to
@FelixKrueger).
Bug fixes (since v2.1.0-beta.1)
Section titled “Bug fixes (since v2.1.0-beta.1)”--pairednow accepts any even number of input files and processes them as consecutive R1/R2 pairs, restoring v0.6.x Perl behaviour. Beta 1 rejected more than 2 files with "Paired-end mode requires exactly 2 input files". Common shell-glob invocations liketrim_galore --paired *fastq.gznow work again. Adapter auto-detection and poly-G scanning run per pair (intentional deviation from Perl v0.6.x, which detected once on the first input file). This is safer for shell-glob invocations that mix library types or 2-colour/4-colour chemistries across samples, at negligible cost (header-only peek, dominated by FASTQ I/O). The paired-end loop is now symmetrical with the single-end loop, which has always detected per file.- Paired-end validation catches when R1 and R2 are the exact same filename (byte-equal path comparison; does not follow symlinks or canonicalise — matches v0.6.x behaviour).
- Paired-end invocations pre-flight-check for output-path collisions across
pairs and abort before writing rather than silently overwriting. Comparison
is case-insensitive (ASCII) so filenames differing only in letter-case are
caught on APFS/NTFS (macOS/Windows default) as well as ext4 (Linux). Fixes
issue #216.
- On opt-in case-sensitive APFS/ZFS volumes, filenames differing only in
letter-case are legitimately distinct; the pre-flight will still reject
them. Use distinct base names or
--basenameper sample to work around this. - On partial failure at pair K, pairs 1..K−1 retain their complete outputs on disk and pair K may have a partial output file; pairs K+1..N are not attempted. Inspect and re-run only the failing pair — matches v0.6.x Perl behaviour (no rollback across pairs).
- On opt-in case-sensitive APFS/ZFS volumes, filenames differing only in
letter-case are legitimately distinct; the pre-flight will still reject
them. Use distinct base names or
Version 2.1.0 (Beta, Release on 18 Apr 2026)
Section titled “Version 2.1.0 (Beta, Release on 18 Apr 2026)”Major release — Rust rewrite (Oxidized Edition). Faithful Rust rewrite of Trim Galore, delivered as a single binary with zero external dependencies and designed as a drop-in replacement for v0.6.x workflows. Outputs match v0.6.x for the core feature set; new capabilities beyond the Perl version include poly-G auto-detection and trimming, a generic poly-A trimmer, per-pair adapter auto-detection, cleaner multi-adapter invocation, a JSON MultiQC-native report, and other extensions. Built from src/main.rs (Cargo crate at repo root); the historical Perl script will be preserved at legacy/trim_galore once v2.1.0 GA ships (retained in the 0.6.11 tag during the beta window).
Note on v2.0.0: v2.0.0 was a pre-release cut inadvertently published to crates.io on 13 Apr 2026. It will be yanked when v2.1.0 GA ships. Users should install v2.1.0 or later.
Features (since v2.0.0)
Section titled “Features (since v2.0.0)”- Multi-adapter support for both R1 and R2 via repeated
-a/-a2flags andfile:adapters.fa(c36b7fe) --discard-untrimmedflag (b0db3db)- Multi-file single-end input (b0db3db)
- JSON trimming report for MultiQC native parsing (efedb95)
- MultiQC-compatible Cutadapt section in text trimming reports (121b821)
Bug fixes (since v2.0.0)
Section titled “Bug fixes (since v2.0.0)”- Parallel-path
total_bp_after_trimandr2_clipped_5primestats now tracked correctly (82d1e34, 3996fc5) - Cutadapt-section report values match v0.6.x MultiQC-parsed values (eedbc66)
--fastqc_argsaccepts hyphenated values like--nogroup(def0344)- Multi-member gzip FASTQ files decode correctly (9dcf519)
- Adapter auto-detection scans exactly 1M reads (9129650)
Version 0.6.11 (Release on 24 Feb 2026)
Section titled “Version 0.6.11 (Release on 24 Feb 2026)”-
Added option
--renameto write clipped bases to the read ID. Works in all modes with options--clip_(r1/r2)and--three_prime_clip_(r1/r2), as well as--hardtrim5and--hardtrim3. Requested in this issue. -
Added option
--bgiseqto trim BGISEQ/DNBSEQ/MGISEQ adapters instead of the default auto-detection. UsesAAGTCGGAGGCCAAGCGGTCTTAGGAAGACAAfor Read 1 (BGI/MGI forward), andAAGTCGGATCGTAGCCATGTCGTTCTGTGAGCCAAGGAGTTGfor Read 2 (BGI/MGI reverse). Requested in issue#196 -
Added option
--demux <barcode_file>to demultiplex files from a 3'-end barcode after trimming is completed. Requested in #199 -
Added option
--cutadapt_args "<ARGS>"to pass extra arguments to Cutadapt, enabling use of advanced Cutadapt options without modifying Trim Galore. -
Changed
--clockEpigenetic Clock processing behaviour for the 5' end of Read 2. -
Fixed
--demuxhandling of CR (carriage return) characters in barcode files; fixed barcode length issue with NoCode; added barcode description to demux summary output. -
Fixed RRBS-specific trimming being silently bypassed when
--nextseqand--rrbsare used together (#210).
Version 0.6.10 (Release on 02 Feb 2023)
Section titled “Version 0.6.10 (Release on 02 Feb 2023)”- Fixed a missing default value of
gzipas the default decompression path (see here).
Version 0.6.9 (Release on 29 Jan 2023)
Section titled “Version 0.6.9 (Release on 29 Jan 2023)”- Fixed a declaration bug for
maxn_fractionwhich had crept in during merging of different branches (see here).
Version 0.6.8 (Release on 28 Jan 2023)
Section titled “Version 0.6.8 (Release on 28 Jan 2023)”-
Added new option
--stranded_illuminato allow trimming of the adapter sequenceACTGTCTCTTATA(whick looks like the Nextera sequence but with an additional A from A-tailing). See also here: https://github.com/FelixKrueger/TrimGalore/issues/127. -
Trim Galore will now preferentially use
igzipfor decompression, if installed. More info here -
finally dropped the option
--trim1entirely. It wasn't useful beyond Bowtie 1 paire-end mode, and hence people should cease using it -
the option
--max_n COUNTnow interprets value between 0 and 1 as fraction of the read length (see here) -
enabled the option
--max_lengthalso for paired-end trimming (of small RNAs)
Version 0.6.7 (Release on 23 Jul 2021)
Section titled “Version 0.6.7 (Release on 23 Jul 2021)”- just to get a DOI via Zenodo
Version 0.6.6 (Release on 04 Sep 2020)
Section titled “Version 0.6.6 (Release on 04 Sep 2020)”-
Changed the way in which we test for the version of Cutadapt, more here: https://github.com/FelixKrueger/TrimGalore/issues/85
-
Allowed specifying of multiple adapters for special cases. Works either via the command line, e.g.:
-a " AGCTCCCG -a TTTCATTATAT -a TTTATTCGGATTTAT"or via a FastA file, like so:-a "file:multiple_adapters.fa"More info here: https://github.com/FelixKrueger/TrimGalore/issues/86. -
Added new special trimming mode for UMIs for the IMPLICON method (
--implicon). In this mode, an 8bp UMI (unique molecular identifier) sequence is transferred from the start of Read 2 to the readID of both reads to allow UMI-aware deduplication (e.g. withdeduplicate_bismark --barcodeor UmiBam. Following this, Trim Galore will exit.
Version 0.6.5 (Release on 19 Nov 2019)
Section titled “Version 0.6.5 (Release on 19 Nov 2019)”-
Added checks for whitespace(s) within input filenames, or a potential output folder name (supplied with
-o).[FATAL ERROR]messages will advise users to use_instead. -
In a
--paired --basename BASEscenario, the output files will now be calledBASE_val_1.fq.gz BASE_val_2.fq.gzas described in the documentation (we previously also added_R1and_R2). This had to be addressed twice (0f631e5f979281fd4f18faef39818399a068a4b3 and 9ad019635a8a7f1aebb56f309889a7841a0ae42e) as the first approach was generating the Read 1 twice. -
removed a superflous warning statement for directional RRBS mode
Version 0.6.4 (Release on 01 Aug 2019)
Section titled “Version 0.6.4 (Release on 01 Aug 2019)”-
Changed the adapter auto-detection procedure so that inconclusive detection always defaults to
--illumina, unless none of the top 2, equal contaminants was 'Illumina', in which case it now defaults to--nextera. A warning message about this is now printed to the screen as well as to the trimming report. -
In addition to that, added the option
--consider_already_trimmed INT. If no specific adapter exceeds this limit during the adapter auto-detection, the file is considered 'already adapter-trimmed' and will not be adapter trimmed again. Quality trimming is carried out as usual (technically, the adapter sequence is set to-a X). This option was added so that pipelines that are being fed either already-trimmed or untrimmed data will do the right thing in both cases. -
Changed the trimming mode for paired-end
--rrbsin conjunction with--non_directional: previously, Read 2 was only trimmed forCGAorCAAat the 5' end, but not trimmed for read-through contamination at the 3' end if no 5' contamination had been removed. This problem had been introduced in v0.4.3, but since non-directional RRBS is not very common it had not been spotted so far. -
File names for single-end trimming are now changed correctly when both
--output_dirand--basenamewere specified together (was working correctly for PE mode already)
Version 0.6.3 (Release on 27 06 2019)
Section titled “Version 0.6.3 (Release on 27 06 2019)”- Also added the number of PolyA trimmed bases to the start of the read in the format
trimmed_bases:A:
So an example trimmed read would look like this:
@READ-ID:1:1102:22039:36996 1:N:0:CCTAATCCGCCTAAGGAAACAAGTACACTCCACACATGCATAAAGGAAATCAAATGTTATTTTTAAGAAAATGGAAAATAAAAACTTTATAAACACCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@32:A:READ-ID:1:1102:22039:36996_1:N:0:CCTAATCC_PolyA:32GCCTAAGGAAACAAGTACACTCCACACATGCATAAAGGAAATCAAATGTTATTTTTAAGAAAATGGAAAATAAAAACTTTATAAACACCVersion 0.6.2 (Release on 08 05 2019)
Section titled “Version 0.6.2 (Release on 08 05 2019)”-
Changed the version checking mechanism so that Trim Galore even works in single-core mode if the version of Cutadapt was 7 years old...
-
Fixed setting
-j $coresfor Cutadapt versions 2.X or above.
Version 0.6.1 (Release on 20 Mar 2019)
Section titled “Version 0.6.1 (Release on 20 Mar 2019)”- Added a check for very old versions Cutadapt, so that single-core trimming still works with Cutadapt versions prior to 1.15.
-
Fixed the way single-core trimming was dealt with in paired-end mode (which was introduced by the above 'fix')
-
the option
--basename preferred_nameshould now correctly work when specified in conjunction with--output_dir
Version 0.6.0 (Release on 1 Mar 2019)
Section titled “Version 0.6.0 (Release on 1 Mar 2019)”- Added option
--hardtrim3 INT,which allows you to hard-clip sequences from their 5' end. This option processes one or more files (plain FastQ or gzip compressed files) and produces hard-trimmed FastQ files ending in .{INT}bp_3prime.fq(.gz). We found this quite useful in a number of scenarios where we wanted to remove biased residues from the start of sequences. Here is an example :
before: CCTAAGGAAACAAGTACACTCCACACATGCATAAAGGAAATCAAATGTTATTTTTAAGAAAATGGAAAAT--hardtrim3 20: TTTTTAAGAAAATGGAAAAT-
Added new option
--basename <PREFERRED_NAME>to usePREFERRED_NAMEas the basename for output files, instead of deriving the filenames from the input files. Single-end data would be calledPREFERRED_NAME_trimmed.fq(.gz), orPREFERRED_NAME_val_1.fq(.gz)andPREFERRED_NAME_val_2.fq(.gz)for paired-end data.--basenameonly works when 1 file (single-end) or 2 files (paired-end) are specified, but not for longer lists (see #43). -
Added option
--2colour/--nextseq INTwhereby INT selects the quality cutoff that is normally set with-q, only that qualities of G bases are ignored.-qand--2colour/--nextseq INTare mutually exclusive (see #41) -
Added check to see if Read 1 and Read 2 files were given as the very same file.
-
If an output directory which was specified with
-o output_directorydid not exist, it will be created for you. -
The option
--max_n INTnow also works in single-end RRBS mode. -
Added multi-threading support with the new option
-j/--cores INT; many thanks to Frankie James for initiating this. Multi-threading support works effectively if Cutadapt is run with Python 3, and if parallel gzip (pigz) is installed:
For Cutadapt to work with multiple cores, it requires Python 3 as well as parallel gzip (pigz) installed on the system. The version of Python used is detected from the shebang line of the Cutadapt executable (either 'cutadapt', or a specified path). If Python 2 is detected, --cores is set to 1 and multi-core processing will be disabled. If pigz cannot be detected on your system, Trim Galore reverts to using gzip compression. Please note however, that gzip compression will slow down multi-core processes so much that it is hardly worthwhile, please see: here for more info).
Actual core usage: It should be mentioned that the actual number of cores used is a little convoluted. Assuming that Python 3 is used and pigz is installed, --cores 2 would use:
- 2 cores to read the input (probably not at a high usage though)
- 2 cores to write to the output (at moderately high usage)
- 2 cores for Cutadapt itself
- 2 additional cores for Cutadapt (not sure what they are used for)
- 1 core for Trim Galore itself
So this can be up to 9 cores, even though most of them won't be used at 100% for most of the time. Paired-end processing uses twice as many cores for the validation (= writing out) step as Trim Galore reads and writes from and to two files at the same time, respectively.
--cores 4 would then be: 4 (read) + 4 (write) + 4 (Cutadapt) + 2 (extra Cutadapt) + 1 (Trim Galore) = ~15 cores in total.
From the graph above it seems that --cores 4 could be a sweet spot, anything above appear to have diminishing returns.
28-06-18: Version 0.5.0
Section titled “28-06-18: Version 0.5.0”-
Adapters can now be specified as single bases with a multiplier in squiggly brackets, e.g. -a "A{10}" to trim poly-A tails
-
Added option
--hardtrim5 INTto enable hard-clipping from the 5' end. This option processes one or more files (plain FastQ or gzip compressed files) and produce hard-trimmed FastQ files ending in.{INT}bp.fq(.gz). -
Added option
--clockto trim reads in a specific way that is currently used for the Mouse Epigenetic Clock (see here: Multi-tissue DNA methylation age predictor in mouse, Stubbs et al., Genome Biology, 2017 18:68). Following the trimming, Trim Galore exits.
In it's current implementation, the dual-UMI RRBS reads come in the following format:
Read 1 5' UUUUUUUU CAGTA FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF TACTG UUUUUUUU 3'Read 2 3' UUUUUUUU GTCAT FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ATGAC UUUUUUUU 5'Where UUUUUUUU is a random 8-mer unique molecular identifier (UMI), CAGTA is a constant region, and FFFFFFF... is the actual RRBS-Fragment to be sequenced. The UMIs for Read 1 (R1) and Read 2 (R2), as well as the fixed sequences (F1 or F2), are written into the read ID and removed from the actual sequence. Here is an example:
R1: @HWI-D00436:407:CCAETANXX:1:1101:4105:1905 1:N:0: CGATGTTT ATCTAGTTCAGTACGGTGTTTTCGAATTAGAAAAATATGTATAGAGGAAATAGATATAAAGGCGTATTCGTTATTGR2: @HWI-D00436:407:CCAETANXX:1:1101:4105:1905 3:N:0: CGATGTTT CAATTTTGCAGTACAAAAATAATACCTCCTCTATTTATCCAAAATCACAAAAAACCACCCACTTAACTTTCCCTAA
R1: @HWI-D00436:407:CCAETANXX:1:1101:4105:1905 1:N:0: CGATGTTT:R1:ATCTAGTT:R2:CAATTTTG:F1:CAGT:F2:CAGT CGGTGTTTTCGAATTAGAAAAATATGTATAGAGGAAATAGATATAAAGGCGTATTCGTTATTGR2: @HWI-D00436:407:CCAETANXX:1:1101:4105:1905 3:N:0: CGATGTTT:R1:ATCTAGTT:R2:CAATTTTG:F1:CAGT:F2:CAGT CAAAAATAATACCTCCTCTATTTATCCAAAATCACAAAAAACCACCCACTTAACTTTCCCTAAFollowing clock trimming, the resulting files (.clock_UMI.R1.fq(.gz) and .clock_UMI.R2.fq(.gz)) should be adapter- and quality trimmed with Trim Galore as usual. In addition, reads need to be trimmed by 15bp from their 3' end to get rid of potential UMI and fixed sequences. The command is:
trim_galore --paired --three_prime_clip_R1 15 --three_prime_clip_R2 15 *.clock_UMI.R1.fq.gz *.clock_UMI.R2.fq.gz
Following this, reads should be aligned with Bismark and deduplicated with UmiBam in --dual_index mode (see here: https://github.com/FelixKrueger/Umi-Grinder). UmiBam recognises the UMIs within this pattern: R1:(ATCTAGTT):R2:(CAATTTTG): as (UMI R1=ATCTAGTT) and (UMI R2=CAATTTTG).
13-11-17: Version 0.4.5 released
Section titled “13-11-17: Version 0.4.5 released”- Trim Galore now dies during the validation step when it encounters paired-end files that are not equal in length
28-03-17: Version 0.4.4 released
Section titled “28-03-17: Version 0.4.4 released”-
Reinstated functionality of option
--rrbsfor single-end RRBS reads which had gone amiss in the previous release. What happened in detail was that RRBS trimming was de facto skipped if there was only a single file specified. -
Updated User Guide and Readme documents, added Installation instruction and Travis functionality - thanks Phil!
25-01-17: Version 0.4.3 released
Section titled “25-01-17: Version 0.4.3 released”-
Changed the option
--rrbsfor paired-end libraries from removing 2 additional base pairs from the 3' end of both reads to trim 2 bp from the 3' end only for Read 1 and set--clip_r2 2for Read 2 instead. This is because Read 2 does not technically need 3' trimming since the end of Read 2 is not affected by the artificial methylation states introduced by the [end-repair] fill-in reaction. Instead, the first couple of positions of Read 2 suffer from the same fill-in problems as standard paired-end libraries. Also see this issue. -
Added a closing statement for the REPORT filehandle since it occasionally swallowed the last line...
-
Setting
--lengthnow takes priority over the smallRNA adapter (which would set the length cutoff to 18 bp).
07-09-16: Version 0.4.2 released
Section titled “07-09-16: Version 0.4.2 released”- Replaced
zcatwithgunzip -cso that older versions of Mac OSX do not append a .Z to the end of the file and subsequently fail because the file is not present. Dah... - Added option
--max_n COUNTto remove all reads (or read pairs) exceeding this limit of tolerated Ns. In a paired-end setting it is sufficient if one read exceeds this limit. Reads (or read pairs) are removed altogether and are not further trimmed or written to the unpaired output - Enabled option
--trim-nto remove Ns from both end of the reads. Does currently not work for RRBS-mode - Added new option
--max_length INTwhich removes reads that are longer than INT bp after trimming. This is only advised for smallRNA sequencing to remove non-small RNA sequences
12-11-15: Version 0.4.1 released: Essential update for smallRNA libraries!
Section titled “12-11-15: Version 0.4.1 released: Essential update for smallRNA libraries!”- Changed the Illumina small RNA sequence used for auto-detection to
TGGAATTCTCGG(from formerlyATGGAATTCTCG). The reason for this is that smallRNA libraries have ssRNA adapters ligated to their -OH end, a signature of dicer cleavage, so there is no A-tailing involved. Thanks to Q. Gouil for bringing this to our attention - Changed the length cutoff for sequences to 16bp (down from 20bp) for smallRNA libraries before sequences get removed entirely. This is because some 20-23bp long smallRNAs species that had removed T, TG, or TGG etc. might just about pass the 20bp cutoff
- Added a small description to the
--helpmessage for users of the NuGEN Ovation RRBS kit as to NOT use the--rrbsoption (see--help)
06-05-15: Version 0.4.0 released
Section titled “06-05-15: Version 0.4.0 released”- Unless instructed otherwise Trim Galore will now attempt to auto-detect the adapter which had been used for library construction (choosing from the Illumina universal, Nextera transposase and Illumina small RNA adapters). For this the first 1 million sequences of the first file specified are analysed. If no adapter can be detected within the first 1 million sequences Trim Galore defaults to --illumina. The auto-detection behaviour can be overruled by specifying an adapter sequence or using
--illumina,--nexteraor--small_rna - Added the new options
--illumina,--nexteraand--small_rnato use different default sequences for trimming (instead of-a): Illumina:AGATCGGAAGAGC; Small RNA:TGGAATTCTCGG; Nextera:CTGTCTCTTATA - Added a sanity check to the start of a Trim Galore run to see if the (first) FastQ file in question does contain information at all or appears to be in SOLiD colorspace format, and bails if either is true. Trim Galore does not support colorspace trimming, but users wishing to do this are kindly referred to using Cutadapt as a standalone program
- Added a new option
--path_to_cutadapt /path/to/cudapt. Unless this option is specified it is assumed that Cutadapt is in the PATH (equivalent to--path_to_cutadapt cutadapt). Also added a test to see if Cutadapt seems to be working before the actual trimming is launched - Fixed an open command for a certain type of RRBS processing (was open() instead of open3())
16-07-14: Version 0.3.7 released
Section titled “16-07-14: Version 0.3.7 released”- Applied small change that makes paired-end mode work again (it was accidentally broken by changing @ARGV for @filenames when looping through the filenames...)
11-07-14: Version 0.3.6 released
Section titled “11-07-14: Version 0.3.6 released”- Added the new options
--three_prime_clip_r1and--three_prime_clip_r2to clip any number of bases from the 3' end after adapter/quality trimming has completed - Added a check to see if Cutadapt exits fine. Else, Trim Galore will bail a well
- The option
--stringencyneeds to be spelled out now since using-swas ambiguous because of--suppress_warn
late 2013: Version 0.3.5 released
Section titled “late 2013: Version 0.3.5 released”- Added the Trim Galore version number to the summary report
19-09-13: Version 0.3.4 released
Section titled “19-09-13: Version 0.3.4 released”- Added single-end or paired-end mode to the summary report
- In paired-end mode, the Read 1 summary report will no longer state that no sequence have been discarded due to trimming. This will be stated in the trimming report of Read 2 once the validation step has been completed
10-09-13: Version 0.3.3 released
Section titled “10-09-13: Version 0.3.3 released”- Fixed a bug what was accidentally introduced which would add an additional empty line in single-end trimming mode
03-09-13: Version 0.3.2 released
Section titled “03-09-13: Version 0.3.2 released”- Specifying
--clip_R1or--clip_R2will no longer attempt to clip sequences that have been adapter- or quality-trimmed below the clipping threshold - Specifying an output directory with
--rrbsmode should now correctly create temporary files
15-07-13: Version 0.3.1 released
Section titled “15-07-13: Version 0.3.1 released”- The default length cutoff is now set at an earlier timepoint to avoid a clash in paired-end mode when
--retain_unpairedand individual read lengths for read 1 and read 2 had been defined
15-07-13: Version 0.3.0 released
Section titled “15-07-13: Version 0.3.0 released”- Added the options
--clip_R1and--clip_R2to trim off a fixed amount of bases at from the 5' end of reads. This can be useful if the quality is unusually low at the start, or whenever there is an undesired bias at the start of reads. An example for this could be PBAT-Seq in general, or the start of read 2 for every bisulfite-Seq paired-end library where end repair procedure introduces unmethylated cytosines. For more information on this see the M-bias section of the Bismark User Guide.
10-04-13: Version 0.2.8 released
Section titled “10-04-13: Version 0.2.8 released”- Trim Galore will now compress output files with GZIP on the fly instead of compressing the trimmed file once trimming has completed. In the interest of time temporary files are not being compressed
- Added a small sanity check to exit if no files were supplied for trimming. Thanks to P. for 'bringing this to my attention'
01-03-13: Version 0.2.7 released
Section titled “01-03-13: Version 0.2.7 released”- Added a new option
--dont_gzipthat will force the output files not to be gzip compressed. This overrides both the--gzipoption or a .gz line ending of the input file(s)
07-02-13: Version 0.2.6 released
Section titled “07-02-13: Version 0.2.6 released”- Fixes some bugs which would not gzip or run FastQC correctly when the option
-ohad been specified - When
--fastqcis specified in paired-end mode the intermediate files '_trimmed.fq' are no longer analysed (only files '_val_1' and '_val_2')
19-10-12: Version 0.2.5 released
Section titled “19-10-12: Version 0.2.5 released”- Added option
-o/--output_directoryto redirect all output (including temporary files) to another folder (required for implementation into Galaxy) - Added option
--no_report_fileto suppress a report file - Added option
--suppress_warnto suppress any output to STDOUT or STDERR
02-10-12: Version 0.2.4 released
Section titled “02-10-12: Version 0.2.4 released”- Removed the shorthand
-lfrom the description as it might conflict with the paired-end options-r1/--length1or-r2/--length2. Please use--lengthinstead - Changed the reporting to show the true Phred score quality cutoff
- Corrected a typo in stringency...
31-07-12: Version 0.2.3 released
Section titled “31-07-12: Version 0.2.3 released”- Added an option
-e ERROR RATEthat allows one to specify the maximum error rate for trimming manually (the default is 0.1)
09-05-12: Version 0.2.2 released
Section titled “09-05-12: Version 0.2.2 released”- Added an option
-a2/--adapter2so that one can specify individual adapter sequences for the two reads of paired-end files; hereby the sequence provided as-a/--adapteris used to trim read 1, and the sequence provided as-a2/--adapter2is used to trim read 2. This option requires--pairedto be specified as well
20-04-12: Version 0.2.1 released
Section titled “20-04-12: Version 0.2.1 released”- Trim Galore! now has an option
--pairedwhich has the same functionality as the validate_paired_ends script we offered previously. This option discards read pairs if one (or both) reads of a read pair became shorter than a given length cutoff - Reads of a read-pair that are longer than a given threshold but for which the partner read has become too short can optionally be written out to single-end files. This ensures that the information of a read pair is not lost entirely if only one read is of good quality
- Paired-end reads may be truncated by a further 1 bp from their 3' end to avoid problems with invalid alignments with Bowtie 1 (which regards alignments that contain each other as invalid...)
- The output may be gzip compressed (this happens automatically if the input files were gzipped (i.e. end in .gz))
- The documentation was extended substantially. We also added some recommendations for RRBS libraries for MseI digested material (recognition motif TTAA)
21-03-12: Version 0.1.4 released
Section titled “21-03-12: Version 0.1.4 released”- Phred33 (Sanger) encoding is now the default quality scheme
- Fixed a bug for Phred64 encoding that would occur if several files were specified at once
14-03-12: Version 0.1.3 released
Section titled “14-03-12: Version 0.1.3 released”- Initial stand-alone release; all basic functions working
- Added the option
--fastqc_argsto pass extra options to FastQC