Claude Skill

alterlab-qiime2-amplicon

Runs 16S/ITS amplicon (microbiome) analysis with the QIIME 2 distribution (2026.7; the "amplicon" distribution was renamed "qiime2" in 2026.4) in the correct order: manifest import, cutadapt trim-paired primer removal BEFORE dada2 denoise-paired (trunc-len chosen from the demux q

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

Full trust report

Download alterlab-ieu-alterlab-academic-skills-skills_bioinformatics_alterlab-qiime2-amplicon-e4836c0.zip · 19 KB
Part of alterlab-ieu/alterlab-academic-skills — 94 skills

Install

skills CLI npx skills add https://github.com/AlterLab-IEU/AlterLab-Academic-Skills/tree/main/skills/bioinformatics/alterlab-qiime2-amplicon
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install alterlab-ieu-alterlab-academic-skills@llmmart
Git git clone https://github.com/AlterLab-IEU/AlterLab-Academic-Skills.git

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

Skill manifest

QIIME 2 Amplicon — 16S/ITS Microbiome Pipeline (FASTQ → Feature Table → Taxonomy → Diversity)

The command-line, workflow-runner entry point for marker-gene (amplicon) microbiome analysis. Given raw demultiplexed paired-end reads, it walks the canonical QIIME 2 order — import → primer trim → denoise → classify → diversity — and teaches the two things people get wrong most: trimming primers BEFORE DADA2, and the .qza/.qzv provenance model. It is the raw-data-to-result pipeline that hands a feature table off to in-memory analysis skills (see routing below).

Written against QIIME 2 2026.7 (released 2026-07-22), the current release. The distribution formerly called amplicon was renamed qiime2 in 2026.4, and its conda env files carry a rachis- prefix (the framework package was renamed qiime2 -> rachis in 2026.1). Only the env name, channel path, and file names moved: every plugin command below is unchanged across those releases.

When to Use This Skill

Use this skill when the request involves running an amplicon / microbiome pipeline from sequencing reads:

  • "Run a QIIME 2 16S pipeline on my paired-end reads."
  • "I have ITS amplicon FASTQs — denoise with DADA2 and assign taxonomy."
  • "Build a feature table / ASV table and classify against SILVA."
  • "Pick truncation lengths from my quality plot and run core-metrics diversity."
  • "How do I trim primers before DADA2 in QIIME 2?"
  • "What's the right order of QIIME 2 commands?"

Does NOT Trigger — route these elsewhere

The request is really about… Route to
Alpha/beta diversity, UniFrac, PCoA ordination, PERMANOVA on an already-exported feature/distance table (in-memory, Python) alterlab-scikit-bio
Building / manipulating a phylogenetic tree, tree visualization, or comparative phylogenetics outside QIIME 2 alterlab-phylogenetics / alterlab-etetoolkit
Shotgun metagenomics taxonomic profiling, MAG assembly, functional genes (not marker-gene amplicons) not in this skill — amplicon only; flag the gap
RNA-seq transcript quantification (salmon/kallisto), differential expression alterlab-rnaseq-quantalterlab-pydeseq2
Variant calling FASTQ → VCF (germline/somatic) alterlab-nf-core-sarek
Protein/nucleotide sequence similarity search (BLAST+/DIAMOND) alterlab-blast
Spatial transcriptomics neighborhood/enrichment analysis alterlab-squidpy-spatial
Quick one-off gene/sequence/database lookups alterlab-gget
Reading/writing BAM/SAM/VCF, alignment file surgery alterlab-pysam

This skill is amplicon (marker-gene) only. If the data is shotgun metagenomic, single-cell, or anything other than 16S/18S/ITS marker-gene sequencing, say so and stop.

The Artifact Model (.qza / .qzv) — read this first

Everything in QIIME 2 is a typed, zipped artifact that records its own provenance:

  • .qza — a QIIME 2 Artifact: data (a feature table, sequences, a classifier) plus an embedded semantic type (e.g. SampleData[PairedEndSequencesWithQuality], FeatureTable[Frequency]) and a full provenance graph of every action that produced it.
  • .qzv — a Visualization: a human-viewable report (quality plots, summaries, diversity emperor plots). Drag it into https://view.qiime2.org (offline, in-browser) or run qiime tools view file.qzv.
  • Provenance is the reproducibility win: any .qza/.qzv carries the exact commands, parameters, and plugin versions that made it. Keep artifacts, not just exports.

Treat semantic types as the contract: an action only accepts artifacts of the type it declares, which is why import (step 1) matters so much.

The Canonical Order (do not reorder)

manifest import → cutadapt trim-paired (primers) → dada2 denoise-paired
   → feature-table summarize → feature-classifier classify-sklearn
   → phylogeny → diversity core-metrics-phylogenetic

Primer trimming comes BEFORE DADA2. DADA2 models per-base error rates; leftover primer/adapter bases corrupt that error model and inflate spurious ASVs. Trim with cutadapt trim-paired first, then denoise. (If your reads are already primer-free — e.g. EMP-style — you can skip cutadapt, but verify, don't assume.)

0. Install / activate the environment (conda only — no pip)

QIIME 2 cannot be pip-installed; it ships as a conda environment. For 2026.7 (env files verified in qiime2/distributions):

# Linux — 2026.7 qiime2 distribution
conda env create \
  --name rachis-qiime2-2026.7 \
  --file https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/2026.7/qiime2/released/rachis-qiime2-linux-64-conda.yml
# macOS: swap the filename for rachis-qiime2-osx-64-conda.yml
conda activate rachis-qiime2-2026.7
qiime info   # confirm version + installed plugins

The env file names encode the platform (linux-64, osx-64), not the OS-runner names used before 2026.4. Give each release its own environment — the classifier must match the running version, so parallel envs are the norm, not clutter.

For other releases the same pattern applies with the version swapped in both the env name and the URL path; see the QIIME 2 Library quickstart. Full install detail and the env-file matrix: references/installation.md.

Bulk DADA2 denoising and classifier training are CPU/RAM heavy. On Cem's M4 Max these run fine locally — keep them off the API and run them in a conda activated shell.

1. Import demultiplexed paired-end reads (manifest)

Use a manifest (a TSV mapping sample IDs → absolute FASTQ paths) so you control exactly which files map to which sample. Format: PairedEndFastqManifestPhred33V2 (verified in q2-types).

qiime tools import \
  --type 'SampleData[PairedEndSequencesWithQuality]' \
  --input-format PairedEndFastqManifestPhred33V2 \
  --input-path manifest.tsv \
  --output-path demux.qza

qiime demux summarize \
  --i-data demux.qza \
  --o-visualization demux.qzv     # ← READ THIS to choose trunc-len

Manifest schema, single-end and EMP variants, and ITS notes: references/import_and_manifest.md. Generate a manifest from a folder of FASTQs with scripts/make_manifest.py.

2. Trim primers with cutadapt (BEFORE DADA2)

qiime cutadapt trim-paired \
  --i-demultiplexed-sequences demux.qza \
  --p-front-f GTGYCAGCMGCCGCGGTAA \   # forward primer (example: 515F)
  --p-front-r GGACTACNVGGGTWTCTAAT \  # reverse primer (example: 806R)
  --p-discard-untrimmed \
  --o-trimmed-sequences demux-trimmed.qza
qiime demux summarize --i-data demux-trimmed.qza --o-visualization demux-trimmed.qzv

--p-discard-untrimmed drops reads where the primer was not found (usually what you want for targeted amplicons). Action and flag names verified from the q2-cutadapt source. Primer choice by region (515F/806R, ITS1F/ITS2, etc.): references/pipeline_steps.md.

3. Denoise with DADA2 → ASVs + feature table

Open demux-trimmed.qzv, read the interactive quality plot, and pick truncation lengths where median quality drops (forward and reverse independently). Truncated read length must still leave enough overlap to merge pairs.

qiime dada2 denoise-paired \
  --i-demultiplexed-seqs demux-trimmed.qza \
  --p-trunc-len-f 0 --p-trunc-len-r 0 \   # ← set from the quality .qzv (0 = no truncation)
  --p-trim-left-f 0 --p-trim-left-r 0 \
  --o-representative-sequences rep-seqs.qza \
  --o-table table.qza \
  --o-denoising-stats denoising-stats.qza
qiime metadata tabulate \
  --m-input-file denoising-stats.qza --o-visualization denoising-stats.qzv

Always inspect denoising-stats.qzv: low merge or chimera-survival rates usually mean trunc-len was too aggressive (no overlap) or primers were not trimmed.

4. Summarize the feature table — note the 2026.1 change

qiime feature-table summarize \
  --i-table table.qza \
  --m-sample-metadata-file sample-metadata.tsv \
  --o-summary table.qzv

2026.1 breaking change (verified in the release notes): the old summarize visualizer was renamed _summarize, and the former summarize_plus pipeline is now summarize — so today's feature-table summarize is the enhanced summary (it also emits feature/sample frequency artifacts). Older tutorials calling summarize_plus must switch to summarize. Details: references/version_notes.md.

5. Assign taxonomy — VERSION-MATCHED classifier

qiime feature-classifier classify-sklearn \
  --i-classifier silva-138-99-nb-classifier.qza \   # MUST match your QIIME 2 version
  --i-reads rep-seqs.qza \
  --o-classification taxonomy.qza
qiime metadata tabulate --m-input-file taxonomy.qza --o-visualization taxonomy.qzv

A pretrained naive-Bayes classifier is pickled scikit-learn — it only loads under the QIIME 2 release it was trained on. Download the classifier built for your version from the QIIME 2 Library (SILVA 138 for 16S/18S, Greengenes2 for 16S, UNITE for ITS). Version-match traps and the train-your-own path: references/classifiers.md.

6. Phylogeny + core diversity

qiime phylogeny align-to-tree-mafft-fasttree \
  --i-sequences rep-seqs.qza \
  --o-alignment aligned.qza --o-masked-alignment masked.qza \
  --o-tree unrooted-tree.qza --o-rooted-tree rooted-tree.qza

qiime diversity core-metrics-phylogenetic \
  --i-phylogeny rooted-tree.qza \
  --i-table table.qza \
  --p-sampling-depth 1103 \           # ← choose from table.qzv rarefaction; see below
  --m-metadata-file sample-metadata.tsv \
  --output-dir core-metrics

Sampling depth is a rarefaction floor: every sample is subsampled to this many reads, and samples below it are dropped. Pick it from table.qzv to balance depth against sample retention — never guess. core-metrics-phylogenetic produces Faith's PD, Shannon, observed features, Bray-Curtis / Jaccard / weighted+unweighted UniFrac distance matrices, and Emperor PCoA .qzvs in one shot.

For stats and ordination off the exported table (PERMANOVA, custom PCoA, alpha/beta metrics in Python), export and hand off to alterlab-scikit-bio — that is the in-memory companion to this pipeline.

Export to hand off downstream

qiime tools export --input-path table.qza --output-path exported/   # → feature-table.biom
qiime tools export --input-path taxonomy.qza --output-path exported/ # → taxonomy.tsv

scripts/check_artifact.py reads a .qza/.qzv (it is just a zip) and prints its semantic type, UUID, and the provenance action list without a QIIME 2 install — handy for sanity-checking that an artifact is what a downstream step expects.

Self-Check Before Reporting

  • Did primers get trimmed before DADA2? If --p-discard-untrimmed dropped almost everything, the primer sequences are likely wrong.
  • Were trunc-lens chosen from the quality .qzv, and does denoising-stats.qzv show reasonable merge + non-chimeric retention?
  • Is the classifier version-matched to the running QIIME 2 release?
  • Is --p-sampling-depth justified from table.qzv, not guessed?
  • Did you call feature-table summarize (since 2026.1 this is the former summarize_plus), not a removed action name?

References

Part of the AlterLab Academic Skills suite.

Files (alterlab-academic-skills)
  • evals
    • evals.json 5.3 KB
      {
        "skill": "alterlab-qiime2-amplicon",
        "evals": [
          {
            "id": "full-16s-pipeline",
            "prompt": "I have demultiplexed paired-end 16S V4 (515F/806R) reads from 30 gut samples in a folder of .fastq.gz files. Walk me through a full QIIME 2 pipeline from raw FASTQs to a feature table, taxonomy against SILVA, and core diversity metrics.",
            "expected_output": "Invokes alterlab-qiime2-amplicon and runs the canonical order: build a PairedEndFastqManifestPhred33V2 manifest and qiime tools import to demux.qza, qiime demux summarize, qiime cutadapt trim-paired with --p-front-f/--p-front-r to remove the 515F/806R primers BEFORE denoising, qiime dada2 denoise-paired (trunc-len-f/-r chosen from the quality .qzv), qiime feature-table summarize, qiime feature-classifier classify-sklearn against a version-matched SILVA 138 classifier, phylogeny align-to-tree-mafft-fasttree, then qiime diversity core-metrics-phylogenetic with --p-sampling-depth chosen from table.qzv. Explains the .qza/.qzv artifact and provenance model and notes the env is conda-only.",
            "assertions": [
              {
                "type": "should_trigger",
                "value": true
              },
              {
                "type": "behavior",
                "value": "Trims primers with cutadapt BEFORE running DADA2, and chooses trunc-len and sampling-depth from the relevant .qzv visualizations rather than guessing."
              }
            ]
          },
          {
            "id": "primer-trim-order",
            "prompt": "In my QIIME 2 16S workflow, should I run cutadapt to remove primers before or after DADA2 denoising? My ASV counts look inflated and a lot of reads are being flagged as chimeric.",
            "expected_output": "Invokes alterlab-qiime2-amplicon and states that primer trimming with qiime cutadapt trim-paired must come BEFORE dada2 denoise-paired, because leftover primer/adapter bases corrupt DADA2's per-base error model and inflate spurious ASVs and chimeras. Recommends inspecting denoising-stats.qzv (merged and non-chimeric retention) and confirms the primers/--p-discard-untrimmed are set correctly.",
            "assertions": [
              {
                "type": "should_trigger",
                "value": true
              },
              {
                "type": "output_contains",
                "value": "cutadapt"
              },
              {
                "type": "behavior",
                "value": "Says primers must be removed before DADA2 and connects leftover primers to inflated ASVs/chimeras."
              }
            ]
          },
          {
            "id": "its-denoise-classify",
            "prompt": "I'm processing fungal ITS amplicon FASTQs in QIIME 2 2026.7 and want to denoise with DADA2 and assign taxonomy. What's the right way, and has the summarize command changed in this version?",
            "expected_output": "Invokes alterlab-qiime2-amplicon: for ITS it warns against aggressive fixed truncation (variable amplicon length) and suggests --p-trunc-len 0 after cutadapt primer trimming, denoise with dada2, then classify-sklearn against a UNITE classifier matched to the QIIME 2 version (not SILVA). Notes that since 2026.1 the former summarize_plus pipeline is 'feature-table summarize' (the old summarize was renamed _summarize), and that the distribution was renamed from 'amplicon' to 'qiime2' in 2026.4 (env files now rachis-qiime2-*). Emphasizes the classifier must be version-matched.",
            "assertions": [
              {
                "type": "should_trigger",
                "value": true
              },
              {
                "type": "behavior",
                "value": "Routes ITS to a UNITE classifier (not SILVA) and explains the feature-table summarize / former summarize_plus change."
              }
            ]
          },
          {
            "id": "near-miss-scikit-bio-permanova",
            "prompt": "I already exported my feature table and a Bray-Curtis distance matrix from QIIME 2. Now I just want to run a PERMANOVA in Python testing whether community composition differs by treatment group, and make a PCoA ordination plot.",
            "expected_output": "Does NOT invoke this skill; defers to alterlab-scikit-bio. The user has already produced the feature/distance artifacts and now wants in-memory statistics (PERMANOVA) and ordination (PCoA) in Python — that is scikit-bio's territory, not running the QIIME 2 pipeline. alterlab-qiime2-amplicon is the raw-data-to-feature-table pipeline; downstream alpha/beta diversity stats on an exported table belong to alterlab-scikit-bio.",
            "assertions": [
              {
                "type": "should_not_trigger",
                "value": true
              },
              {
                "type": "output_contains",
                "value": "alterlab-scikit-bio"
              }
            ]
          },
          {
            "id": "near-miss-nf-core-sarek-variants",
            "prompt": "I have whole-genome paired-end FASTQs and want to call germline SNVs and indels to produce a VCF with a proper FASTQ-to-VCF variant-calling workflow. Which pipeline should I run?",
            "expected_output": "Does NOT invoke this skill; defers to alterlab-nf-core-sarek. The user wants germline variant calling (FASTQ to VCF) on whole-genome sequencing, which is a DNA variant-calling pipeline, not marker-gene amplicon/microbiome analysis. alterlab-qiime2-amplicon only handles 16S/18S/ITS amplicon data and does not call variants.",
            "assertions": [
              {
                "type": "should_not_trigger",
                "value": true
              },
              {
                "type": "output_contains",
                "value": "alterlab-nf-core-sarek"
              }
            ]
          }
        ]
      }
      
  • references
    • classifiers.md 3.3 KB
      # Taxonomic classifiers — version matching is mandatory
      
      `qiime feature-classifier classify-sklearn` (action name verified in the Moving Pictures
      tutorial) takes a **pretrained naive-Bayes classifier** `.qza` plus your `rep-seqs.qza`
      and emits `taxonomy.qza`.
      
      ```bash
      qiime feature-classifier classify-sklearn \
        --i-classifier <classifier>.qza \
        --i-reads rep-seqs.qza \
        --o-classification taxonomy.qza
      qiime metadata tabulate --m-input-file taxonomy.qza --o-visualization taxonomy.qzv
      ```
      
      ## The #1 trap: classifier must match your QIIME 2 version
      
      A pretrained classifier is a **pickled scikit-learn model**. scikit-learn does not
      guarantee unpickling across versions, so a classifier trained for one QIIME 2 release may
      **fail to load (or silently misbehave)** under another. Always download the classifier
      artifact built for the **exact QIIME 2 release you are running** from the QIIME 2 Library
      data resources (the docs note pretrained classifiers are published there as data
      resources), or train your own in the same env (below).
      
      ## Reference databases by amplicon
      
      | Amplicon | Reference DB | Notes |
      |----------|--------------|-------|
      | 16S / 18S rRNA | **SILVA 138** | Broad rRNA reference; full-length and region-specific (e.g. 515F/806R) classifiers are published. |
      | 16S rRNA | **Greengenes2** (e.g. 2024.09) | Phylogeny-integrated 16S reference; pick the release whose date matches your workflow. |
      | Fungal ITS | **UNITE** | The standard ITS reference; use the UNITE-trained classifier, not SILVA. |
      
      Match the **region** too: a classifier trained on the **same primer region** as your reads
      (e.g. a 515F/806R V4 extract) generally outperforms a full-length classifier on short
      reads. Confirm the exact current classifier filenames/URLs from the QIIME 2 Library before
      downloading — do not hardcode a filename that may have moved.
      
      ## Train your own (when no pretrained artifact matches)
      
      If no published classifier matches your version + region, train one in the active env:
      
      ```bash
      # 1. Extract the amplicon region from a reference using YOUR primers
      qiime feature-classifier extract-reads \
        --i-sequences ref-seqs.qza \
        --p-f-primer <FORWARD_PRIMER> --p-r-primer <REVERSE_PRIMER> \
        --o-reads ref-seqs-extracted.qza
      # 2. Fit the naive-Bayes classifier
      qiime feature-classifier fit-classifier-naive-bayes \
        --i-reference-reads ref-seqs-extracted.qza \
        --i-reference-taxonomy ref-taxonomy.qza \
        --o-classifier my-classifier.qza
      ```
      
      Training is RAM-heavy (full SILVA can need tens of GB) — a good local/offline job. Verify
      the exact `extract-reads` / `fit-classifier-naive-bayes` signatures with
      `qiime feature-classifier <action> --help` in your env.
      
      ## Alternatives to sklearn classification
      
      - `classify-consensus-vsearch` / `classify-consensus-blast` — alignment-based consensus
        classification; no pretrained pickle, so no version-pickle risk (slower, needs the ref
        sequences + taxonomy artifacts). Useful when a matching sklearn classifier is unavailable.
      
      ## Sources
      
      - QIIME 2 Moving Pictures tutorial (`feature-classifier classify-sklearn`).
      - QIIME 2 amplicon docs (pretrained classifiers published as Library data resources).
      - SILVA 138 / Greengenes2 / UNITE are the standard 16S/18S/ITS references; confirm exact
        artifact versions and URLs from the QIIME 2 Library at use time.
      
    • import_and_manifest.md 2.4 KB
      # Importing data & the manifest format
      
      Everything entering QIIME 2 must be **imported into a typed `.qza`** first. For
      demultiplexed reads, a **manifest** gives you explicit control over the sample-ID →
      FASTQ-path mapping (preferred over directory-format guessing).
      
      ## Paired-end manifest (recommended)
      
      Semantic type: `SampleData[PairedEndSequencesWithQuality]`.
      Input format: `PairedEndFastqManifestPhred33V2` (verified present in `q2-types`,
      `q2_types/per_sample_sequences/_formats.py`).
      
      The V2 manifest is a **TSV** with a header and one row per sample:
      
      ```
      sample-id	forward-absolute-filepath	reverse-absolute-filepath
      sample1	/abs/path/sample1_R1.fastq.gz	/abs/path/sample1_R2.fastq.gz
      sample2	/abs/path/sample2_R1.fastq.gz	/abs/path/sample2_R2.fastq.gz
      ```
      
      - Paths must be **absolute**.
      - `Phred33V2` means Phred+33 quality encoding (modern Illumina). A `Phred64` variant
        exists for legacy data; do not mix.
      
      ```bash
      qiime tools import \
        --type 'SampleData[PairedEndSequencesWithQuality]' \
        --input-format PairedEndFastqManifestPhred33V2 \
        --input-path manifest.tsv \
        --output-path demux.qza
      ```
      
      ## Single-end manifest
      
      Format `SingleEndFastqManifestPhred33V2` (also in `q2-types`), one path column
      (`absolute-filepath`), type `SampleData[SequencesWithQuality]`.
      
      ## EMP-style (multiplexed, barcodes still attached)
      
      If reads are **not yet demultiplexed** (EMP protocol), import as
      `EMPPairedEndSequences` / `EMPSingleEndSequences` and demultiplex with `qiime demux`
      (e.g. `qiime demux emp-single`) using a barcodes column in the metadata. The Moving
      Pictures tutorial uses `EMPSingleEndSequences` + `qiime tools import` then
      `qiime demux summarize`.
      
      ## After import — always summarize
      
      ```bash
      qiime demux summarize --i-data demux.qza --o-visualization demux.qzv
      ```
      
      `demux.qzv` gives you the **interactive quality plot** that drives DADA2 truncation
      length choices. Read it before denoising.
      
      ## ITS-specific note
      
      For fungal ITS amplicons, the amplicon length is **variable**, so aggressive fixed
      truncation in DADA2 can discard real reads. Many ITS workflows trim primers with cutadapt
      and then run DADA2 with `--p-trunc-len 0` (no truncation), relying on quality trimming
      only. Pair with the UNITE classifier (see `classifiers.md`).
      
      ## Sources
      
      - `q2-types` `dev` branch, `q2_types/per_sample_sequences/_formats.py` and `__init__.py`
        (manifest format class names confirmed).
      - QIIME 2 Moving Pictures tutorial (EMP import + `demux summarize` commands).
      
    • installation.md 3.1 KB
      # Installation — QIIME 2 amplicon distribution (conda only)
      
      QIIME 2 is distributed as a **conda environment**, not a PyPI package. There is no
      `pip install qiime2` for the full distribution; the plugin ecosystem, native binaries
      (MAFFT, FastTree, DADA2's R/C++ stack, cutadapt) and the framework are resolved by conda.
      
      ## 2026.7 — current release (the `qiime2` distribution)
      
      Verified environment files in the `qiime2/distributions` repo at
      `2026.7/qiime2/released/`:
      
      - `rachis-qiime2-linux-64-conda.yml`
      - `rachis-qiime2-osx-64-conda.yml`
      
      These resolve from the channels `conda-forge`, `bioconda`, and
      `https://packages.qiime2.org/qiime2/2026.7/qiime2/released`.
      
      ```bash
      # Linux
      conda env create \
        --name rachis-qiime2-2026.7 \
        --file https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/2026.7/qiime2/released/rachis-qiime2-linux-64-conda.yml
      
      # macOS
      conda env create \
        --name rachis-qiime2-2026.7 \
        --file https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/2026.7/qiime2/released/rachis-qiime2-osx-64-conda.yml
      
      conda activate rachis-qiime2-2026.7
      qiime info        # prints version + every installed plugin
      ```
      
      `mamba` is a faster drop-in for the solve if available (`mamba env create ...`).
      
      ## The 2026.4 rename, and what older instructions look like
      
      Before 2026.4 the distribution was called `amplicon` and its env files were named after the
      CI runner, e.g. `2026.1/amplicon/released/qiime2-amplicon-ubuntu-latest-conda.yml` with the
      env named `qiime2-amplicon-2026.1`. Since 2026.4 the distribution is `qiime2` (the historical
      package collection users associate with the `qiime2` namespace), the files carry a `rachis-`
      prefix, and the platform is spelled `linux-64` / `osx-64`. Tutorials written before mid-2026
      will still show the old paths — they 404 for newer releases rather than failing loudly later.
      
      Also from the 2026.1 notes: the underlying **framework was renamed from `qiime2` to
      `rachis`** and published to PyPI, which is where the file prefix comes from. The plugin
      **commands** in this skill
      (`qiime tools import`, `qiime cutadapt trim-paired`, `qiime dada2 denoise-paired`,
      `qiime feature-classifier classify-sklearn`, `qiime diversity core-metrics-phylogenetic`)
      are unchanged by the rename — only the env name, channel path, and file names move.
      
      Always confirm the exact current command from the official source rather than hardcoding:
      - Quickstart: https://library.qiime2.org/quickstart/amplicon
      - 2026.7 announcement: https://qiime2.org/news/qiime-2-2026-7-is-now-available-34255/
      - 2026.1 announcement: https://qiime2.org/news/qiime-2-2026-1-is-now-available-33935/
      
      ## Viewing artifacts
      
      - In-browser, offline: https://view.qiime2.org (nothing is uploaded; it runs locally).
      - CLI: `qiime tools view file.qzv`.
      
      ## Sources
      
      - `qiime2/distributions` repo, `dev` branch, `2026.7/qiime2/released/` (env files confirmed
        to exist and resolve over HTTPS, 2026-09-23).
      - QIIME 2 2026.1 release announcement (distribution rename to `qiime2` in 2026.4;
        framework renamed to `rachis` on PyPI).
      - QIIME 2 Library amplicon quickstart (2026.4 `rachis-qiime2-*` install command).
      
    • pipeline_steps.md 4.5 KB
      # Per-step parameters, primers, and QC reading
      
      All action and flag names below are verified from the QIIME 2 plugin sources
      (`q2-cutadapt`, `q2-dada2`) and the Moving Pictures tutorial. Do not invent flags —
      run `qiime <plugin> <action> --help` in the active env to see the exact signature for
      your installed version.
      
      ## cutadapt trim-paired
      
      Source-verified parameters (`q2-cutadapt` `dev`, `plugin_setup.py`): `front_f`,
      `front_r`, `discard_untrimmed` (CLI: `--p-front-f`, `--p-front-r`,
      `--p-discard-untrimmed`). The single-end action is `trim-single` with `--p-front`.
      
      ```bash
      qiime cutadapt trim-paired \
        --i-demultiplexed-sequences demux.qza \
        --p-front-f <FORWARD_PRIMER> \
        --p-front-r <REVERSE_PRIMER> \
        --p-discard-untrimmed \
        --o-trimmed-sequences demux-trimmed.qza
      ```
      
      ### Common primer pairs (fill in YOUR study's actual primers)
      
      These are widely used reference primers; confirm against your sequencing facility's
      protocol before using — primer choice is study-specific.
      
      | Target | Primer | Sequence |
      |--------|--------|----------|
      | 16S V4 | 515F (Parada) | `GTGYCAGCMGCCGCGGTAA` |
      | 16S V4 | 806R (Apprill) | `GGACTACNVGGGTWTCTAAT` |
      | 16S V3–V4 | 341F | `CCTACGGGNGGCWGCAG` |
      | 16S V3–V4 | 805R | `GACTACHVGGGTATCTAATCC` |
      | Fungal ITS | ITS1F | `CTTGGTCATTTAGAGGAAGTAA` |
      | Fungal ITS | ITS2 | `GCTGCGTTCTTCATCGATGC` |
      
      `--p-discard-untrimmed` keeps only reads where the primer was found — standard for
      targeted amplicons. Without it, untrimmed reads pass through and pollute DADA2.
      
      ## dada2 denoise-paired
      
      Source-verified parameters (`q2-dada2` `dev`, `plugin_setup.py`): `trunc_len_f`,
      `trunc_len_r`, `trim_left_f`, `trim_left_r` (CLI `--p-trunc-len-f` etc.). The single-end
      action `denoise-single` uses `--p-trunc-len` / `--p-trim-left`.
      
      ```bash
      qiime dada2 denoise-paired \
        --i-demultiplexed-seqs demux-trimmed.qza \
        --p-trunc-len-f <F> --p-trunc-len-r <R> \
        --p-trim-left-f 0 --p-trim-left-r 0 \
        --o-representative-sequences rep-seqs.qza \
        --o-table table.qza \
        --o-denoising-stats denoising-stats.qza
      ```
      
      ### Choosing `--p-trunc-len-f/-r`
      
      1. Open `demux-trimmed.qzv` → "Interactive Quality Plot".
      2. Truncate each read where the **median quality** (box plot) drops sharply
         (commonly below ~Q25–Q30). Forward and reverse are chosen independently.
      3. **Overlap constraint:** for paired merging, `trunc_len_f + trunc_len_r` must exceed
         the amplicon length by enough for DADA2's minimum overlap (default ~12 nt). Truncate
         too hard and pairs fail to merge.
      4. `0` means no truncation (use for ITS / variable-length amplicons).
      
      ### Reading `denoising-stats.qzv`
      
      `qiime metadata tabulate --m-input-file denoising-stats.qza --o-visualization
      denoising-stats.qzv`. Inspect per-sample columns:
      
      - **input → filtered**: quality filtering loss (usually small).
      - **denoised → merged**: a large drop here means insufficient overlap → relax trunc-len.
      - **merged → non-chimeric**: a large drop means many chimeras → often a sign primers were
        not removed before denoising.
      
      ## feature-table summarize
      
      ```bash
      qiime feature-table summarize \
        --i-table table.qza \
        --m-sample-metadata-file sample-metadata.tsv \
        --o-summary table.qzv
      ```
      
      Since 2026.1 this is the former `summarize_plus` (see `version_notes.md`). Use `table.qzv`
      to pick `--p-sampling-depth` for diversity: the "Interactive Sample Detail" /
      frequency-per-sample view shows how many samples you retain at each depth.
      
      ## phylogeny + core-metrics-phylogenetic
      
      ```bash
      qiime phylogeny align-to-tree-mafft-fasttree \
        --i-sequences rep-seqs.qza \
        --o-alignment aligned.qza --o-masked-alignment masked.qza \
        --o-tree unrooted-tree.qza --o-rooted-tree rooted-tree.qza
      
      qiime diversity core-metrics-phylogenetic \
        --i-phylogeny rooted-tree.qza \
        --i-table table.qza \
        --p-sampling-depth <DEPTH> \
        --m-metadata-file sample-metadata.tsv \
        --output-dir core-metrics
      ```
      
      `core-metrics-phylogenetic` rarefies to `--p-sampling-depth` and outputs Faith's PD,
      observed features, Shannon, Pielou evenness, Bray-Curtis / Jaccard / weighted &
      unweighted UniFrac distance matrices, plus Emperor PCoA `.qzv`s.
      
      ## Sources
      
      - `q2-cutadapt` `dev` `plugin_setup.py` (trim-paired / trim-single parameter names).
      - `q2-dada2` `dev` `plugin_setup.py` (denoise-paired / denoise-single parameter names).
      - QIIME 2 Moving Pictures tutorial (`phylogeny align-to-tree-mafft-fasttree`,
        `diversity core-metrics-phylogenetic`, `--p-sampling-depth`).
      - Primer sequences are standard published reference primers; verify against your protocol.
      
    • version_notes.md 3.5 KB
      # Version notes — QIIME 2 2026.1 -> 2026.7
      
      The current release is **QIIME 2 2026.7** (announced 2026-07-22,
      https://qiime2.org/news/qiime-2-2026-7-is-now-available-34255/). The amplicon pipeline
      commands this skill teaches are unchanged across 2026.1 -> 2026.7; what moved is the
      distribution name, the env files, and some plugin boundaries on the shotgun side. Facts
      about the `summarize` change below come from the official 2026.1 release announcement
      (https://qiime2.org/news/qiime-2-2026-1-is-now-available-33935/, announced 2026-01-28).
      
      ## Breaking change: `feature-table summarize`
      
      In `q2-feature-table`, **2026.1 swapped two action names**:
      
      - the old `summarize` **visualizer** was renamed **`_summarize`** (now private), and
      - the former **`summarize_plus` pipeline** was renamed to **`summarize`**.
      
      Net effect: today, calling `qiime feature-table summarize` runs what used to be
      `summarize_plus` — the **enhanced** summary that also produces feature-frequency and
      sample-frequency artifacts in addition to the `.qzv`. Consequences for workflows:
      
      - **Older tutorials that call `summarize_plus`** must switch to `summarize`.
      - Do **not** call `_summarize` (private/legacy).
      - Practically, keep using `qiime feature-table summarize` and read `table.qzv`; that *is*
        the plus behavior now.
      
      ## Distribution rename, shipped in 2026.4
      
      The 2026.1 notes announced: *"in our next release (2026.4) we will be renaming the amplicon
      distribution to qiime2, since this is the historical collection of packages that our user
      base is familiar with in the context of the qiime2 namespace."* This shipped as planned and
      holds in 2026.7.
      
      Implications:
      
      - The conda **env file name and channel path change** (`rachis-qiime2-<platform>-conda.yml`
        under `<release>/qiime2/released/`; see `installation.md`).
      - The **plugin commands do not change** — `qiime tools import`,
        `qiime cutadapt trim-paired`, `qiime dada2 denoise-paired`,
        `qiime feature-classifier classify-sklearn`,
        `qiime diversity core-metrics-phylogenetic` are all stable across the rename.
      
      ## Framework renamed to `rachis`
      
      Also in 2026.1: the underlying QIIME 2 **framework was renamed from `qiime2` to
      `rachis`** and is now published on PyPI. This is the framework package, not the user-facing
      `qiime` CLI; pipeline command names are unaffected. (This is why the 2026.4 env files are
      named `rachis-qiime2-*`.)
      
      ## Other plugin updates noted in 2026.1
      
      - `q2-alignment`: added protein-sequence support.
      - `q2-boots`: improved memory efficiency in medoid calculations.
      - `q2-types`: added formats for genomic data and taxonomy-to-contig mappings.
      
      ## Plugin moves in 2026.7
      
      These affect the shotgun-metagenomics side, not the amplicon pipeline, but they break older
      command lines:
      
      - Binning / MAG actions moved out of `q2-annotate` into a new **`q2-mag`** plugin.
      - Pangenome filtering actions moved into **`q2-quality-control`**.
      - `da-barplot` was replaced by **`ancombc2-visualizer`**, which took over the old name.
      - `q2view` now shows annotations in the provenance DAG.
      
      ## How to stay current
      
      When running a different release, **verify command names and install files from the
      official sources** rather than trusting this file:
      
      - Latest announcement: https://qiime2.org/news/qiime-2-2026-7-is-now-available-34255/
      - 2026.1 announcement: https://qiime2.org/news/qiime-2-2026-1-is-now-available-33935/
      - Amplicon docs: https://amplicon-docs.qiime2.org/
      - Library quickstart (install): https://library.qiime2.org/quickstart/amplicon
      - In the active env: `qiime info` and `qiime <plugin> <action> --help`.
      
  • scripts
    • check_artifact.py 4.5 KB
      #!/usr/bin/env python3
      """check_artifact.py — Inspect a QIIME 2 .qza/.qzv WITHOUT a QIIME 2 install.
      
      A QIIME 2 artifact (.qza) or visualization (.qzv) is just a ZIP whose single
      top-level directory is the artifact's UUID. Inside that directory:
      
          <uuid>/metadata.yaml     # 'uuid:', 'type:' (semantic type), 'format:'
          <uuid>/data/...          # the payload
          <uuid>/provenance/       # recorded actions, parameters, plugin versions
      
      This reads those without importing qiime2, so you can sanity-check that an artifact is
      the SEMANTIC TYPE a downstream step expects (e.g. FeatureTable[Frequency],
      SampleData[PairedEndSequencesWithQuality]) before wiring it into the next command, and
      list the provenance actions that produced it. Pure standard library (zipfile + a tiny
      line parser for the handful of metadata.yaml keys) — no PyYAML, no qiime2, runs under a
      bare ``uv run python``.
      
      Usage:
        uv run python check_artifact.py ARTIFACT.qza [--provenance] [--json]
        uv run python check_artifact.py table.qza                 # type + uuid + format
        uv run python check_artifact.py table.qza --provenance     # + action list
        uv run python check_artifact.py table.qza --json           # machine-readable
      
      Exit codes: 0 = parsed; 2 = not a readable QIIME 2 zip / missing metadata.yaml.
      """
      
      from __future__ import annotations
      
      import argparse
      import json
      import sys
      import zipfile
      from pathlib import PurePosixPath
      
      
      def _scalar(line: str, key: str) -> str | None:
          """Extract 'key: value' from a flat metadata.yaml line (no PyYAML needed)."""
          stripped = line.strip()
          if stripped.startswith(key + ":"):
              return stripped[len(key) + 1 :].strip().strip("'\"")
          return None
      
      
      def read_metadata(zf: zipfile.ZipFile) -> dict:
          # The single top-level dir is the artifact UUID.
          roots = {PurePosixPath(n).parts[0] for n in zf.namelist() if n.strip("/")}
          if len(roots) != 1:
              raise SystemExit(f"ERROR: expected one top-level dir (UUID), found {sorted(roots)}")
          root = roots.pop()
          meta_path = f"{root}/metadata.yaml"
          if meta_path not in zf.namelist():
              raise SystemExit(f"ERROR: no metadata.yaml at {meta_path} — not a QIIME 2 artifact?")
          text = zf.read(meta_path).decode("utf-8", "replace")
          info = {"root_uuid": root, "uuid": None, "type": None, "format": None}
          for line in text.splitlines():
              for key in ("uuid", "type", "format"):
                  val = _scalar(line, key)
                  if val is not None and info[key] is None:
                      info[key] = val
          return info
      
      
      def list_provenance_actions(zf: zipfile.ZipFile, root: str) -> list[str]:
          """List provenance action.yaml entries (one per recorded action)."""
          prefix = f"{root}/provenance/"
          actions = sorted(
              n for n in zf.namelist()
              if n.startswith(prefix) and n.endswith("/action/action.yaml")
          )
          out: list[str] = []
          for n in actions:
              plugin = act = None
              for line in zf.read(n).decode("utf-8", "replace").splitlines():
                  plugin = plugin or _scalar(line, "plugin")
                  act = act or _scalar(line, "action")
              label = "/".join(p for p in (plugin, act) if p) or n
              out.append(label)
          return out
      
      
      def main(argv: list[str] | None = None) -> int:
          ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
          ap.add_argument("artifact", help="Path to a .qza or .qzv file")
          ap.add_argument("--provenance", action="store_true", help="List provenance actions")
          ap.add_argument("--json", action="store_true", help="Emit JSON")
          args = ap.parse_args(argv)
      
          try:
              zf = zipfile.ZipFile(args.artifact)
          except (FileNotFoundError, zipfile.BadZipFile) as exc:
              print(f"ERROR: cannot open as zip: {exc}", file=sys.stderr)
              return 2
      
          with zf:
              info = read_metadata(zf)
              prov: list[str] = []
              if args.provenance:
                  prov = list_provenance_actions(zf, info["root_uuid"])
      
          if args.json:
              payload = {"uuid": info["uuid"] or info["root_uuid"],
                         "type": info["type"], "format": info["format"]}
              if args.provenance:
                  payload["provenance_actions"] = prov
              print(json.dumps(payload, indent=2))
          else:
              print(f"uuid:   {info['uuid'] or info['root_uuid']}")
              print(f"type:   {info['type']}")
              print(f"format: {info['format']}")
              if args.provenance:
                  print("provenance actions ({}):".format(len(prov)))
                  for a in prov:
                      print(f"  - {a}")
          return 0
      
      
      if __name__ == "__main__":
          raise SystemExit(main())
      
    • make_manifest.py 5.1 KB
      #!/usr/bin/env python3
      """make_manifest.py — Build a QIIME 2 paired-end manifest (V2) from a FASTQ folder.
      
      QIIME 2 imports demultiplexed reads from a *manifest*: a TSV mapping each sample-id
      to the ABSOLUTE paths of its forward (and, for paired data, reverse) FASTQ files.
      This produces a ``PairedEndFastqManifestPhred33V2`` (or single-end) manifest that
      ``qiime tools import`` accepts directly:
      
          qiime tools import \\
            --type 'SampleData[PairedEndSequencesWithQuality]' \\
            --input-format PairedEndFastqManifestPhred33V2 \\
            --input-path manifest.tsv --output-path demux.qza
      
      It pairs files by a configurable read-tag (default Illumina ``_R1``/``_R2``) and
      derives the sample-id from the filename prefix before that tag. Nothing is uploaded
      anywhere; it only inspects local filenames. Pure standard library — runs under a bare
      ``uv run python`` with no QIIME 2 environment.
      
      Usage:
        uv run python make_manifest.py FASTQ_DIR [--out manifest.tsv]
                                       [--fwd-tag _R1] [--rev-tag _R2]
                                       [--single] [--ext .fastq.gz]
        uv run python make_manifest.py ./reads --out manifest.tsv      # paired, R1/R2
        uv run python make_manifest.py ./reads --single --fwd-tag _R1  # single-end
      
      Exit codes: 0 = wrote a manifest; 2 = bad usage / no FASTQs found / unpaired files.
      """
      
      from __future__ import annotations
      
      import argparse
      import re
      import sys
      from pathlib import Path
      
      
      def sample_id_from(name: str, tag: str) -> str:
          """Derive a sample-id from a filename: everything before the read tag.
      
          e.g. 'gut42_S3_L001_R1_001.fastq.gz' with tag '_R1' -> 'gut42_S3_L001'.
          """
          base = name
          idx = base.find(tag)
          if idx != -1:
              base = base[:idx]
          else:
              # No tag present: strip a trailing extension chain (.fastq.gz, .fq, ...).
              base = re.sub(r"\.(fastq|fq)(\.gz)?$", "", base)
          return base.rstrip("_.")
      
      
      def collect(directory: Path, ext: str) -> list[Path]:
          files = sorted(p for p in directory.iterdir() if p.is_file() and p.name.endswith(ext))
          return files
      
      
      def build_paired(files: list[Path], fwd_tag: str, rev_tag: str) -> list[tuple[str, Path, Path]]:
          fwd = {sample_id_from(p.name, fwd_tag): p for p in files if fwd_tag in p.name}
          rev = {sample_id_from(p.name, rev_tag): p for p in files if rev_tag in p.name}
          rows: list[tuple[str, Path, Path]] = []
          missing: list[str] = []
          for sid in sorted(fwd):
              if sid in rev:
                  rows.append((sid, fwd[sid], rev[sid]))
              else:
                  missing.append(sid)
          orphan_rev = sorted(set(rev) - set(fwd))
          if missing or orphan_rev:
              msg = []
              if missing:
                  msg.append(f"forward reads with no reverse mate: {', '.join(missing)}")
              if orphan_rev:
                  msg.append(f"reverse reads with no forward mate: {', '.join(orphan_rev)}")
              raise SystemExit("ERROR: unpaired files — " + "; ".join(msg))
          return rows
      
      
      def build_single(files: list[Path], fwd_tag: str) -> list[tuple[str, Path]]:
          return [(sample_id_from(p.name, fwd_tag), p) for p in files]
      
      
      def main(argv: list[str] | None = None) -> int:
          ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
          ap.add_argument("fastq_dir", help="Directory containing demultiplexed FASTQ files")
          ap.add_argument("--out", default="manifest.tsv", help="Output manifest path (default manifest.tsv)")
          ap.add_argument("--fwd-tag", default="_R1", help="Forward-read filename tag (default _R1)")
          ap.add_argument("--rev-tag", default="_R2", help="Reverse-read filename tag (default _R2)")
          ap.add_argument("--single", action="store_true", help="Single-end (one column) manifest")
          ap.add_argument("--ext", default=".fastq.gz", help="FASTQ extension to match (default .fastq.gz)")
          args = ap.parse_args(argv)
      
          directory = Path(args.fastq_dir).expanduser().resolve()
          if not directory.is_dir():
              print(f"ERROR: not a directory: {directory}", file=sys.stderr)
              return 2
      
          files = collect(directory, args.ext)
          if not files:
              print(f"ERROR: no '*{args.ext}' files in {directory}", file=sys.stderr)
              return 2
      
          out = Path(args.out).expanduser()
          if args.single:
              rows = build_single(files, args.fwd_tag)
              with out.open("w") as fh:
                  fh.write("sample-id\tabsolute-filepath\n")
                  for sid, p in rows:
                      fh.write(f"{sid}\t{p}\n")
              print(f"Wrote {len(rows)} single-end samples -> {out}")
              print("Import with: --type 'SampleData[SequencesWithQuality]' "
                    "--input-format SingleEndFastqManifestPhred33V2")
          else:
              rows = build_paired(files, args.fwd_tag, args.rev_tag)
              with out.open("w") as fh:
                  fh.write("sample-id\tforward-absolute-filepath\treverse-absolute-filepath\n")
                  for sid, f, r in rows:
                      fh.write(f"{sid}\t{f}\t{r}\n")
              print(f"Wrote {len(rows)} paired-end samples -> {out}")
              print("Import with: --type 'SampleData[PairedEndSequencesWithQuality]' "
                    "--input-format PairedEndFastqManifestPhred33V2")
          return 0
      
      
      if __name__ == "__main__":
          raise SystemExit(main())
      
  • SKILL.md 13.6 KB
    ---
    name: alterlab-qiime2-amplicon
    description: 'Runs 16S/ITS amplicon (microbiome) analysis with the QIIME 2 distribution (2026.7; the "amplicon" distribution was renamed "qiime2" in 2026.4) in the correct order: manifest import, cutadapt trim-paired primer removal BEFORE dada2 denoise-paired (trunc-len chosen from the demux quality .qzv), feature-classifier classify-sklearn against a version-matched SILVA 138 or Greengenes2 classifier, and diversity core-metrics-phylogenetic — teaching the .qza/.qzv artifact-and-provenance model and the 2026.1 feature-table summarize change (the former summarize_plus). Use when the request mentions QIIME2, QIIME 2, qiime, 16S, 18S, ITS, amplicon, microbiome, ASV, DADA2 denoising, feature table, taxonomic classification, or core-metrics diversity. For downstream alpha/beta diversity, PCoA, and PERMANOVA on the exported feature table prefer alterlab-scikit-bio; this is conda-only (no pip install). Part of the AlterLab Academic Skills suite.'
    license: MIT
    allowed-tools: Read Write Edit Bash(python:*) Bash(uv:*) Bash(qiime:*) Bash(conda:*)
    compatibility: "Requires the QIIME 2 conda environment (cannot be pip-installed); commands are run via the `qiime` CLI. Current release 2026.7 (2026-07-22); the distribution formerly called `amplicon` is named `qiime2` since 2026.4 and its env files carry the `rachis-` prefix. Pretrained classifiers and reference data are downloaded from the QIIME 2 Library. The helper scripts in scripts/ are stdlib-only and run under `uv run python` without a QIIME 2 env."
    metadata:
        skill-author: AlterLab
        version: "1.1.0"
        last_updated: "2026-09-23"
    ---
    
    # QIIME 2 Amplicon — 16S/ITS Microbiome Pipeline (FASTQ → Feature Table → Taxonomy → Diversity)
    
    The command-line, workflow-runner entry point for marker-gene (amplicon) microbiome
    analysis. Given raw demultiplexed paired-end reads, it walks the **canonical QIIME 2
    order** — import → primer trim → denoise → classify → diversity — and teaches the two
    things people get wrong most: **trimming primers BEFORE DADA2**, and the **.qza/.qzv
    provenance model**. It is the raw-data-to-result pipeline that hands a feature table off
    to in-memory analysis skills (see routing below).
    
    Written against **QIIME 2 2026.7** (released 2026-07-22), the current release. The
    distribution formerly called `amplicon` was **renamed `qiime2` in 2026.4**, and its conda
    env files carry a `rachis-` prefix (the framework package was renamed `qiime2` -> `rachis`
    in 2026.1). Only the env name, channel path, and file names moved: every plugin command
    below is unchanged across those releases.
    
    ## When to Use This Skill
    
    Use this skill when the request involves running an amplicon / microbiome pipeline from
    sequencing reads:
    
    - "Run a QIIME 2 16S pipeline on my paired-end reads."
    - "I have ITS amplicon FASTQs — denoise with DADA2 and assign taxonomy."
    - "Build a feature table / ASV table and classify against SILVA."
    - "Pick truncation lengths from my quality plot and run core-metrics diversity."
    - "How do I trim primers before DADA2 in QIIME 2?"
    - "What's the right order of QIIME 2 commands?"
    
    ### Does NOT Trigger — route these elsewhere
    
    | The request is really about… | Route to |
    |------------------------------|----------|
    | Alpha/beta diversity, UniFrac, **PCoA ordination, PERMANOVA** on an already-exported feature/distance table (in-memory, Python) | `alterlab-scikit-bio` |
    | Building / manipulating a phylogenetic tree, tree visualization, or comparative phylogenetics outside QIIME 2 | `alterlab-phylogenetics` / `alterlab-etetoolkit` |
    | **Shotgun metagenomics** taxonomic profiling, MAG assembly, functional genes (not marker-gene amplicons) | not in this skill — amplicon only; flag the gap |
    | **RNA-seq** transcript quantification (salmon/kallisto), differential expression | `alterlab-rnaseq-quant` → `alterlab-pydeseq2` |
    | **Variant calling** FASTQ → VCF (germline/somatic) | `alterlab-nf-core-sarek` |
    | Protein/nucleotide **sequence similarity search** (BLAST+/DIAMOND) | `alterlab-blast` |
    | **Spatial** transcriptomics neighborhood/enrichment analysis | `alterlab-squidpy-spatial` |
    | Quick one-off gene/sequence/database lookups | `alterlab-gget` |
    | Reading/writing BAM/SAM/VCF, alignment file surgery | `alterlab-pysam` |
    
    This skill is **amplicon (marker-gene) only**. If the data is shotgun metagenomic,
    single-cell, or anything other than 16S/18S/ITS marker-gene sequencing, say so and stop.
    
    ## The Artifact Model (.qza / .qzv) — read this first
    
    Everything in QIIME 2 is a **typed, zipped artifact** that records its own provenance:
    
    - **`.qza`** — a QIIME 2 **Artifact**: data (a feature table, sequences, a classifier)
      plus an embedded **semantic type** (e.g. `SampleData[PairedEndSequencesWithQuality]`,
      `FeatureTable[Frequency]`) and a full **provenance graph** of every action that
      produced it.
    - **`.qzv`** — a **Visualization**: a human-viewable report (quality plots, summaries,
      diversity emperor plots). Drag it into **https://view.qiime2.org** (offline, in-browser)
      or run `qiime tools view file.qzv`.
    - Provenance is the reproducibility win: any `.qza/.qzv` carries the exact commands,
      parameters, and plugin versions that made it. Keep artifacts, not just exports.
    
    Treat semantic types as the contract: an action only accepts artifacts of the type it
    declares, which is why import (step 1) matters so much.
    
    ## The Canonical Order (do not reorder)
    
    ```
    manifest import → cutadapt trim-paired (primers) → dada2 denoise-paired
       → feature-table summarize → feature-classifier classify-sklearn
       → phylogeny → diversity core-metrics-phylogenetic
    ```
    
    **Primer trimming comes BEFORE DADA2.** DADA2 models per-base error rates; leftover
    primer/adapter bases corrupt that error model and inflate spurious ASVs. Trim with
    `cutadapt trim-paired` first, then denoise. (If your reads are already primer-free —
    e.g. EMP-style — you can skip cutadapt, but verify, don't assume.)
    
    ### 0. Install / activate the environment (conda only — no pip)
    
    QIIME 2 **cannot be pip-installed**; it ships as a conda environment. For 2026.7 (env files
    verified in `qiime2/distributions`):
    
    ```bash
    # Linux — 2026.7 qiime2 distribution
    conda env create \
      --name rachis-qiime2-2026.7 \
      --file https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/2026.7/qiime2/released/rachis-qiime2-linux-64-conda.yml
    # macOS: swap the filename for rachis-qiime2-osx-64-conda.yml
    conda activate rachis-qiime2-2026.7
    qiime info   # confirm version + installed plugins
    ```
    
    The env file names encode the platform (`linux-64`, `osx-64`), not the OS-runner names used
    before 2026.4. Give each release its own environment — the classifier must match the running
    version, so parallel envs are the norm, not clutter.
    
    For other releases the same pattern applies with the version swapped in both the env name
    and the URL path; see the QIIME 2
    Library quickstart. Full install detail and the env-file matrix:
    [`references/installation.md`](references/installation.md).
    
    > Bulk DADA2 denoising and classifier training are CPU/RAM heavy. On Cem's M4 Max these
    > run fine locally — keep them off the API and run them in a `conda activate`d shell.
    
    ### 1. Import demultiplexed paired-end reads (manifest)
    
    Use a **manifest** (a TSV mapping sample IDs → absolute FASTQ paths) so you control
    exactly which files map to which sample. Format: `PairedEndFastqManifestPhred33V2`
    (verified in `q2-types`).
    
    ```bash
    qiime tools import \
      --type 'SampleData[PairedEndSequencesWithQuality]' \
      --input-format PairedEndFastqManifestPhred33V2 \
      --input-path manifest.tsv \
      --output-path demux.qza
    
    qiime demux summarize \
      --i-data demux.qza \
      --o-visualization demux.qzv     # ← READ THIS to choose trunc-len
    ```
    
    Manifest schema, single-end and EMP variants, and ITS notes:
    [`references/import_and_manifest.md`](references/import_and_manifest.md).
    Generate a manifest from a folder of FASTQs with
    [`scripts/make_manifest.py`](scripts/make_manifest.py).
    
    ### 2. Trim primers with cutadapt (BEFORE DADA2)
    
    ```bash
    qiime cutadapt trim-paired \
      --i-demultiplexed-sequences demux.qza \
      --p-front-f GTGYCAGCMGCCGCGGTAA \   # forward primer (example: 515F)
      --p-front-r GGACTACNVGGGTWTCTAAT \  # reverse primer (example: 806R)
      --p-discard-untrimmed \
      --o-trimmed-sequences demux-trimmed.qza
    qiime demux summarize --i-data demux-trimmed.qza --o-visualization demux-trimmed.qzv
    ```
    
    `--p-discard-untrimmed` drops reads where the primer was not found (usually what you
    want for targeted amplicons). Action and flag names verified from the `q2-cutadapt`
    source. Primer choice by region (515F/806R, ITS1F/ITS2, etc.):
    [`references/pipeline_steps.md`](references/pipeline_steps.md).
    
    ### 3. Denoise with DADA2 → ASVs + feature table
    
    Open `demux-trimmed.qzv`, read the **interactive quality plot**, and pick truncation
    lengths where median quality drops (forward and reverse independently). Truncated read
    length must still leave enough overlap to merge pairs.
    
    ```bash
    qiime dada2 denoise-paired \
      --i-demultiplexed-seqs demux-trimmed.qza \
      --p-trunc-len-f 0 --p-trunc-len-r 0 \   # ← set from the quality .qzv (0 = no truncation)
      --p-trim-left-f 0 --p-trim-left-r 0 \
      --o-representative-sequences rep-seqs.qza \
      --o-table table.qza \
      --o-denoising-stats denoising-stats.qza
    qiime metadata tabulate \
      --m-input-file denoising-stats.qza --o-visualization denoising-stats.qzv
    ```
    
    Always inspect `denoising-stats.qzv`: low merge or chimera-survival rates usually mean
    trunc-len was too aggressive (no overlap) or primers were not trimmed.
    
    ### 4. Summarize the feature table — note the 2026.1 change
    
    ```bash
    qiime feature-table summarize \
      --i-table table.qza \
      --m-sample-metadata-file sample-metadata.tsv \
      --o-summary table.qzv
    ```
    
    **2026.1 breaking change (verified in the release notes):** the old `summarize`
    visualizer was renamed `_summarize`, and the former **`summarize_plus` pipeline is now
    `summarize`** — so today's `feature-table summarize` *is* the enhanced summary (it also
    emits feature/sample frequency artifacts). Older tutorials calling `summarize_plus` must
    switch to `summarize`. Details: [`references/version_notes.md`](references/version_notes.md).
    
    ### 5. Assign taxonomy — VERSION-MATCHED classifier
    
    ```bash
    qiime feature-classifier classify-sklearn \
      --i-classifier silva-138-99-nb-classifier.qza \   # MUST match your QIIME 2 version
      --i-reads rep-seqs.qza \
      --o-classification taxonomy.qza
    qiime metadata tabulate --m-input-file taxonomy.qza --o-visualization taxonomy.qzv
    ```
    
    A pretrained naive-Bayes classifier is **pickled scikit-learn** — it only loads under the
    QIIME 2 release it was trained on. Download the classifier built for **your** version
    from the QIIME 2 Library (SILVA 138 for 16S/18S, Greengenes2 for 16S, UNITE for ITS).
    Version-match traps and the train-your-own path:
    [`references/classifiers.md`](references/classifiers.md).
    
    ### 6. Phylogeny + core diversity
    
    ```bash
    qiime phylogeny align-to-tree-mafft-fasttree \
      --i-sequences rep-seqs.qza \
      --o-alignment aligned.qza --o-masked-alignment masked.qza \
      --o-tree unrooted-tree.qza --o-rooted-tree rooted-tree.qza
    
    qiime diversity core-metrics-phylogenetic \
      --i-phylogeny rooted-tree.qza \
      --i-table table.qza \
      --p-sampling-depth 1103 \           # ← choose from table.qzv rarefaction; see below
      --m-metadata-file sample-metadata.tsv \
      --output-dir core-metrics
    ```
    
    **Sampling depth** is a rarefaction floor: every sample is subsampled to this many reads,
    and samples below it are dropped. Pick it from `table.qzv` to balance depth against sample
    retention — never guess. `core-metrics-phylogenetic` produces Faith's PD, Shannon,
    observed features, Bray-Curtis / Jaccard / weighted+unweighted UniFrac distance matrices,
    and Emperor PCoA `.qzv`s in one shot.
    
    For **stats and ordination off the exported table** (PERMANOVA, custom PCoA, alpha/beta
    metrics in Python), export and hand off to **`alterlab-scikit-bio`** — that is the
    in-memory companion to this pipeline.
    
    ## Export to hand off downstream
    
    ```bash
    qiime tools export --input-path table.qza --output-path exported/   # → feature-table.biom
    qiime tools export --input-path taxonomy.qza --output-path exported/ # → taxonomy.tsv
    ```
    
    `scripts/check_artifact.py` reads a `.qza/.qzv` (it is just a zip) and prints its semantic
    type, UUID, and the provenance action list **without a QIIME 2 install** — handy for
    sanity-checking that an artifact is what a downstream step expects.
    
    ## Self-Check Before Reporting
    
    - Did primers get trimmed **before** DADA2? If `--p-discard-untrimmed` dropped almost
      everything, the primer sequences are likely wrong.
    - Were trunc-lens chosen from the **quality `.qzv`**, and does `denoising-stats.qzv` show
      reasonable merge + non-chimeric retention?
    - Is the classifier **version-matched** to the running QIIME 2 release?
    - Is `--p-sampling-depth` justified from `table.qzv`, not guessed?
    - Did you call `feature-table summarize` (since 2026.1 this is the former `summarize_plus`),
      not a removed action name?
    
    ## References
    
    - [`references/installation.md`](references/installation.md) — conda env files (2026.7 current; the 2026.4 `qiime2` rename), `qiime info`, why no pip.
    - [`references/import_and_manifest.md`](references/import_and_manifest.md) — manifest formats, single-end/EMP/ITS import.
    - [`references/pipeline_steps.md`](references/pipeline_steps.md) — per-step flags, primer sets by region, denoising QC reading.
    - [`references/classifiers.md`](references/classifiers.md) — SILVA 138 / Greengenes2 / UNITE, version-matching, train-your-own.
    - [`references/version_notes.md`](references/version_notes.md) — release deltas through 2026.7, the `qiime2` rename, the `summarize` change.
    
    Part of the AlterLab Academic Skills suite.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related