A Nextflow (DSL2) reimplementation of the seabed-symphony metagenomics pipeline for the discovery of biosynthetic gene clusters (BGCs) from Oxford Nanopore long reads.
The original pipeline is a series of 17 sequential bash scripts. This repository translates it into a portable, resumable, containerised Nextflow workflow built from nf-core modules.
| Workflow | Scope | Original steps | Status |
|---|---|---|---|
| 1 | Preprocessing & Quality Control | 1–4 | ✅ implemented |
| 2 | Metagenome Assembly & Annotation | 5–8 | ✅ implemented |
| 3 | Genome Binning & Quality Assessment | 9–11 | ⬜ planned |
| 4 | BGC Detection & Functional Analysis | 12–15 | ⬜ planned |
- Java 17 or later (Nextflow runs on the JVM)
- Nextflow ≥ 24.10 — the pipeline uses topic channels,
evaloutputs and nativeprocess.resourceLimits - One execution backend: Conda/Mamba, Docker, or Singularity/Apptainer
# macOS, via Homebrew
brew install --cask temurin@21
curl -s https://get.nextflow.io | bashRun the smoke test (downloads a small public dataset automatically):
nextflow run main.nf -profile conda,testRun on your own data:
nextflow run main.nf -profile conda --input 'data/*.fastq.gz' --outdir resultsSwap the execution backend by changing the profile:
nextflow run main.nf -profile docker --input 'data/*.fastq.gz'
nextflow run main.nf -profile singularity --input 'data/*.fastq.gz'| Parameter | Default | Description |
|---|---|---|
--input |
(required) | Glob or path to gzipped long-read FASTQ files |
--outdir |
results |
Output directory |
--max_cpus |
16 |
Ceiling on CPUs per task |
--max_memory |
128.GB |
Ceiling on memory per task |
--max_time |
240.h |
Ceiling on runtime per task |
--flye_read_type |
nano-hq |
Flye read type, without leading dashes. nano-hq needs <5 % error (R10.4/Q20+); use nano-raw for older R9 data |
--flye_iterations |
3 |
Flye polishing rounds |
--skip_assembly |
false |
Stop after Workflow 1 |
--skip_bandage |
false |
Skip graph rendering (needed for -profile conda on macOS — see caveats) |
raw FASTQ
├── NanoPlot (1a) read length / quality plots
├── SeqKit stats (1b) summary statistics
└── Filtlong (2a) --min_length 1000
└── Filtlong (2b) --keep_percent 90
└── Porechop (3) adapter removal
├── NanoPlot (4a) post-trim QC
└── SeqKit stats (4b) post-trim statistics
│
▼
clean reads → Workflow 2
| Step | Tool | Version | Purpose |
|---|---|---|---|
| 1a, 4a | NanoPlot | 1.47.0 | Read length and quality visualisation |
| 1b, 4b | SeqKit | 2.13.0 | Read statistics table |
| 2a, 2b | Filtlong | 0.2.1 | Length and quality filtering |
| 3 | Porechop | 0.2.4 | Oxford Nanopore adapter removal |
Tool arguments live in conf/modules.config — edit them
there rather than in the module files, so the nf-core modules stay updatable.
clean reads (from Workflow 1)
└── metaFlye (5) --meta assembly
├── assembly_graph.gfa ──── Bandage (6) PNG + SVG of the graph
└── assembly.fasta ──────── Whokaryote (7) prokaryote vs eukaryote
│
┌─────────────────────┴─────────────────────┐
│ prokaryote_contig_headers.txt │ eukaryote_..._headers.txt
▼ ▼
extractContigsFromWhokaryote.py (8) extractContigsFromWhokaryote.py
│ (--p) │ (--e)
▼ ▼
prokaryote contigs → Workflow 3 eukaryote contigs (by-product)
| Step | Tool | Version | Purpose |
|---|---|---|---|
| 5 | Flye (metaFlye) | 2.9.5 | Metagenome assembly of long reads |
| 6 | Bandage | 0.9.0 | Assembly-graph visualisation |
| 7 | Whokaryote | 1.1.2 | Prokaryote/eukaryote contig classification |
| 8 | extractContigsFromWhokaryote.py |
1.0 | Split assembly by domain |
Whokaryote and the extraction script have no nf-core modules, so they live in
modules/local/. The Python script is vendored from the
original repository into bin/, which Nextflow puts on PATH
automatically.
results/
├── preprocessing/
│ ├── <sample>/<sample>.clean.fastq.gz ← analysis-ready reads
│ └── logs/ ← Filtlong + Porechop logs
├── qc/
│ ├── nanoplot/raw/<sample>/ ← HTML reports, PNG plots, NanoStats.txt
│ ├── nanoplot/trimmed/<sample>/
│ └── seqkit/
│ ├── <sample>.raw.tsv
│ └── <sample>.trimmed.tsv
├── assembly/<sample>/
│ ├── <sample>.assembly.fasta.gz ← contigs
│ ├── <sample>.assembly_graph.gfa.gz ← graph (Bandage input)
│ ├── <sample>.assembly_info.txt ← per-contig length / coverage
│ ├── <sample>.flye.log
│ └── graph/ ← Bandage PNG + SVG
├── taxonomy/whokaryote/<sample>/
│ ├── prokaryote_contig_headers.txt
│ ├── eukaryote_contig_headers.txt
│ └── featuretable_predictions_T.tsv
├── contigs/
│ ├── prokaryote/<sample>.prokaryote.fasta.gz ← hand-off to Workflow 3
│ └── eukaryote/<sample>.eukaryote.fasta.gz
└── pipeline_info/
├── software_versions.yml ← every tool version used
├── execution_report.html
├── execution_timeline.html
├── execution_trace.txt
└── pipeline_dag.html
-profile test streams a Bacteroides fragilis ONT dataset from the
nf-core/test-datasets repository
(1 000 reads, ~33 kb mean read length, ~93 % of reads pass the 1 kb filter).
Nothing large is committed to this repository.
It is a technical test: it exercises every process, produces realistic long-read length distributions, and completes in minutes. It is a single bacterial isolate, so it has no community structure to bin and few BGCs to find.
One function, one tool, one image.
By default the pipeline uses the single-tool image each nf-core module already
declares. These are built from the same bioconda recipes as the conda
environments, so -profile docker or -profile singularity pulls them
automatically and nothing needs building:
| Process | Tool | Image source |
|---|---|---|
NANOPLOT |
NanoPlot 1.47.0 | BioContainers |
SEQKIT_STATS |
SeqKit 2.13.0 | Seqera Containers |
FILTLONG |
Filtlong 0.2.1 | BioContainers |
PORECHOP_PORECHOP |
Porechop 0.2.4 | Seqera Containers |
FLYE |
Flye 2.9.5 | Seqera Containers |
BANDAGE_IMAGE |
Bandage 0.9.0 | Seqera Containers |
WHOKARYOTE |
Whokaryote 1.1.2 | BioContainers (local module) |
EXTRACT_* |
Biopython 1.84 | BioContainers (local module) |
docker/ holds an equivalent one-tool-per-image Dockerfile for all
eight, pinned to the same versions, plus a local_containers profile that points
the pipeline at them:
nextflow run main.nf -profile local_containers,testBuild these only when you need something upstream
cannot provide — an institutional or air-gapped registry, a tool with no upstream
container (likely Whokaryote and GraphMB later), or an image carrying this
pipeline's own bin/ scripts:
docker build -t seabed-nanoplot:1.47.0 docker/nanoplot/See docker/README.md for all four builds and for how to
point processes at them without editing the nf-core modules.
├── main.nf entry point; input channel + version collection
├── nextflow.config params, profiles, resource ceilings, reports
├── modules.json nf-core module versions (managed by nf-core CLI)
├── conf/
│ ├── base.config CPU/memory/time per process label
│ └── modules.config tool arguments + publishing rules
├── bin/ helper scripts (auto-added to PATH)
│ └── extractContigsFromWhokaryote.py
├── workflows/
│ ├── preprocessing_qc.nf Workflow 1
│ └── assembly_annotation.nf Workflow 2
├── modules/nf-core/ unmodified nf-core modules
│ ├── bandage/image/
│ ├── filtlong/
│ ├── flye/
│ ├── nanoplot/
│ ├── porechop/porechop/
│ └── seqkit/stats/
├── modules/local/ tools with no nf-core module
│ ├── whokaryote/
│ └── extractcontigsfromwhokaryote/
└── docker/ one-tool-per-image Dockerfiles
├── filtlong/
├── nanoplot/
├── porechop/
└── seqkit/
Modules are unmodified nf-core code. To update them later, install the nf-core CLI and run:
pip install nf-core
nf-core modules update --all- Samplesheet input (CSV with sample ID, barcode, site, depth) — needed for multiplexed runs; the current glob input cannot carry per-sample metadata
- MultiQC report aggregating NanoPlot and SeqKit across samples
- Workflow 3: multi-binner ensemble + DAS Tool + CheckM
- Workflow 4: GTDB-Tk, Bakta, antiSMASH, BiG-SCAPE
- nf-test unit tests per module
- Institutional/HPC profile for cluster execution