Generated banner for Qiime2 Amplicon
Generated logo for Qiime2 Amplicon

Qiime2 Amplicon

K-DenseCommunityCreated by K-Dense Inc.

  • Skill
  • Workflow
  • Science and research
  • MIT
  • Low risk
  • Has scripts

From the author

Processes paired-end 16S amplicon reads into QIIME 2 ASVs and taxonomy with retained artifact provenance. Checks paired FASTQ manifests, primer orientation diagnostics, predicted post-trimming overlap, sample IDs, runtime versions and read retention, and guides selection of compatible taxonomic classifiers.
— the description by K-Dense Inc.

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured, validated workflow for processing demultiplexed, paired-end 16S amplicon reads using QIIME 2 (version 2026.7). It automates the import of FASTQ files, primer removal via Cutadapt, denoising with DADA2, and taxonomic classification. The workflow emphasizes data integrity by enforcing strict manifest formats, validating primer orientation, and maintaining artifact provenance throughout the analysis pipeline. It includes built-in quality control checks for read retention and sample consistency, ensuring that researchers can reliably move from raw sequences to taxonomic feature tables.

What it does

  • Imports paired-end FASTQ reads using a validated manifest format.
  • Performs primer removal and quality-based denoising using DADA2.
  • Generates taxonomic assignments using user-supplied compatible classifiers.
  • Validates input data, including sample IDs and primer orientation.
  • Tracks artifact provenance and generates retention statistics for quality assessment.
  • Produces standardized QIIME 2 artifacts (.qza/.qzv) for downstream ecological analysis.

When to use it

  • When processing 16S amplicon sequencing data in a QIIME 2 2026.7 environment.
  • When you need a reproducible pipeline that preserves artifact provenance.
  • When you have known primer sequences and expected insert lengths for your assay.
  • When you need to perform automated quality control on read retention and sample alignment.

Advantages

  • Reduces manual errors through automated validation of manifests and metadata.
  • Ensures reproducibility by maintaining full artifact provenance.
  • Provides clear diagnostic feedback on primer matching and read retention.
  • Integrates directly with standard QIIME 2 plugin workflows.

Usage examples

“Validate my 16S amplicon manifest and primer settings before running the full analysis.”
The skill performs a dry-run validation of the manifest structure, primer sequences, and truncation parameters to ensure compatibility before execution.
“Run the full 16S processing pipeline on my paired-end reads using a specific classifier.”
The skill executes the complete workflow, including import, trimming, denoising, and classification, outputting all results to a designated directory.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/k-dense-ai/qiime2-amplicon/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip qiime2-amplicon.zip -d .agents/skills

Documentation by K-Dense Inc.

QIIME 2 paired-end 16S amplicons

Use for a demultiplexed, paired-end 16S assay with known primers, quality encoding, expected insert length, and sample metadata. This bounded workflow imports reads, removes 5′ primers, denoises with DADA2, classifies ASVs using an explicitly supplied classifier, and retains .qza/.qzv provenance. Do not treat read counts as absolute cell counts or taxonomy assignments as strain identification.

Establish the assay before running

  • Confirm Phred+33, read orientation, primer sequences as sequenced in forward/reverse reads, and whether primers have already been removed. The bundled runner requires primers still present at the 5′ ends; it anchors Cutadapt matching and discards untrimmed pairs. Already trimmed reads need a direct import → DADA2 workflow with that omission recorded in provenance.

  • Choose truncation positions from actual per-base quality and error profiles. trunc-f/r are positions after primer removal. The expected maximum insert length also excludes primers. Require trunc_f + trunc_r - maximum_insert_length >= 12; use a margin for length variation. The check predicts geometrical overlap, not successful biological merging.

  • Choose a classifier whose reference database, taxonomic coverage, orientation and training approach fit the assay. Full-length classifiers are supported; primer-region-specific training is not mandatory. Match its scikit-learn version exactly to the installed environment (the official 2026.7 distribution pins 1.7.1). Record source URL, database version and checksum. QIIME's current data-resources page links externally hosted classifiers for 2026.4 and later; its older downloads are not automatically compatible. Do not automatically fetch an arbitrary “latest” classifier or reuse an incompatible serialized sklearn model. Load sklearn classifier artifacts only from trusted sources: QZA format validation does not make an untrusted serialized model safe.

  • Include extraction blanks, PCR negatives, and a mock community where available. The runner rejects empty FASTQs; preserve empty-control IDs separately and report them rather than silently deleting control evidence. Assess contamination before ecological interpretation.

Input files

Manifest is a tab-separated PairedEndFastqManifestPhred33V2 file with exactly these headers:

sample-id	forward-absolute-filepath	reverse-absolute-filepath
sample1	/data/sample1_R1.fastq.gz	/data/sample1_R2.fastq.gz

This is the helper's deliberately narrow manifest profile. Use actual tab characters, literal absolute paths visible to the runtime (expand environment variables before calling this helper), and one row per sample; no comment/directive rows or additional columns in this manifest. Do not reverse-complement R2 files. Sample metadata is a tab-separated file with first column sample-id, unique IDs matching the manifest, and optional #q2:types annotation. Include covariates and biological replicate IDs needed downstream. The helper checks metadata IDs and row structure; QIIME performs full metadata typing/directive validation during execution. Metadata used by actions persists in artifact provenance, so use de-identified biological replicate IDs.

Execute

The helper lives at scripts/amplicon_workflow.py. Commands below assume the skill directory is the working directory. First validate without QIIME. These example primers and lengths are illustrative, not universal assay settings:

python scripts/amplicon_workflow.py validate \
  --manifest manifest.tsv --metadata sample-metadata.tsv \
  --primer-f GTGYCAGCMGCCGCGGTAA --primer-r GGACTACNVGGGTWTCTAAT \
  --trunc-f 220 --trunc-r 200 --amplicon-max 300

Then run in the QIIME 2 2026.7 environment with a compatible classifier. This study-specific invocation is illustrative; choose lengths using a preceding quality inspection or pilot:

python scripts/amplicon_workflow.py run \
  --manifest manifest.tsv --metadata sample-metadata.tsv \
  --primer-f GTGYCAGCMGCCGCGGTAA --primer-r GGACTACNVGGGTWTCTAAT \
  --trunc-f 220 --trunc-r 200 --amplicon-max 300 \
  --classifier compatible-classifier.qza --threads 4 --output run01

run executes immediately, writes only to a fresh output directory, and stops on a failing QIIME command. It streams through every paired FASTQ record to catch mismatched IDs/order/counts, checks sequence/quality consistency and sample alignment, and profiles the first 1,000 read pairs for exact IUPAC primer matches. Low exact-match rates are warnings: Cutadapt allows mismatches, but a low rate can also indicate incorrect orientation, adapters, or already-trimmed data. At least one complete pair per sample must meet nominal post-primer truncation lengths. These length estimates subtract the stated primer lengths; they do not simulate Cutadapt indels or quality filtering, and do not establish that any pair will actually merge.

The runner uses --output-dir for plugin methods with evolving output sets, preserving Cutadapt statistics and DADA2 base-transition artifacts when supplied by the release. The 2026.7 table summary also produces feature-frequencies.qza and sample-frequencies.qza beside table.qzv. It records qiime-info.txt, commands.json, workflow.log, input QC, classifier checksum and output artifact checksums. It runs maximum-level QIIME artifact validation before reporting completion. See references/runtime-and-interpretation.md for the release-pinned runtime, actual validation scope, restart handling and scientific interpretation.

Inspect results before analysis

Open trimmed.qzv, table.qzv, and taxa.qzv in a local QIIME visualization environment or QIIME 2 View as appropriate for the data. Examine quality/length profiles, per-sample depth and dominant taxa. Retain original artifacts rather than replacing them with CSV/BIOM exports: exports do not retain the original provenance graph.

retention-qc.json compares raw pairs with DADA2 input and non-chimeric reads, so trimming losses remain visible. A <50% retained fraction is a review heuristic, not a universal rejection rule. Inspect the individual stages in stats/stats.tsv: filtering loss suggests quality/expected-error settings; loss after forward denoising includes reverse-denoising and merging failures; chimera loss warrants reviewing library quality and parameters. Investigate missing/zero samples and control behavior before rarefaction, diversity, or differential abundance. Those downstream analyses need a separate design decision; this skill does not choose a rarefaction depth automatically. The standalone retention stats.tsv subcommand knows only DADA2 input counts: it reports raw_pairs: null and names that denominator explicitly. It supports merged-only paired DADA2 statistics, as produced by this runner; it rejects retained-unmerged/concatenated-read statistics.

Primary references

The rolling documentation may describe a development release. Inspect qiime info and action --help in the exact installed environment before adapting the pinned runner to a later release.

Files

scripts/amplicon_workflow.py

#!/usr/bin/env python3
"""Validate paired-end amplicons and run a provenance-preserving QIIME 2 workflow."""
from __future__ import annotations

import argparse
import csv
import gzip
import hashlib
import itertools
import json
import math
from pathlib import Path
import re
import subprocess

IUPAC = dict(zip('ACGTRYSWKMBDHVN', ['A', 'C', 'G', 'T', 'AG', 'CT', 'GC', 'AT', 'GT', 'AC', 'CGT', 'AGT', 'ACT', 'ACG', 'ACGT']))
ID_HEADERS = {'id', 'sampleid', 'sample id', 'sample-id', 'featureid', 'feature id', 'feature-id'}
LEGACY_ID_HEADERS = {'#SampleID', '#Sample ID', '#OTUID', '#OTU ID', 'sample_name'}


def id_header(value: str) -> bool:
    return value.lower() in ID_HEADERS or value in LEGACY_ID_HEADERS


def fastq(path: Path):
    opener = gzip.open if path.suffix == '.gz' else open
    with opener(path, 'rt', encoding='ascii') as handle:
        while True:
            name = handle.readline()
            if not name:
                break
            sequence, plus, quality = (handle.readline().rstrip('\r\n') for _ in range(3))
            if not name.startswith('@') or not plus.startswith('+') or not sequence or len(sequence) != len(quality):
                raise ValueError(f'Malformed four-line FASTQ record in {path}')
            if set(sequence.upper()) - set('ACGTN') or any(not 33 <= ord(c) <= 126 for c in quality):
                raise ValueError(f'Invalid sequence or Phred+33 characters in {path}')
            tokens = name[1:].split()
            identifier = re.sub(r'/[12]$', '', tokens[0]) if tokens else ''
            if not identifier:
                raise ValueError(f'Empty FASTQ read identifier in {path}')
            yield identifier, sequence.upper()


def primer_match(sequence: str, primer: str) -> bool:
    return len(sequence) >= len(primer) and all(base in IUPAC[p] for base, p in zip(sequence, primer))


def read_metadata(path: Path) -> set[str]:
    with path.open(encoding='utf-8-sig') as handle:
        rows = [[cell.strip() for cell in row] for row in csv.reader(handle, delimiter='\t')]
    rows = [row for row in rows if any(row) and
            (not row[0].startswith('#') or row[0] in LEGACY_ID_HEADERS)]
    if not rows:
        raise ValueError('Metadata is empty')
    if not id_header(rows[0][0]):
        raise ValueError('Use sample-id as the first metadata header')
    columns = rows[0][1:]
    if any(not c or id_header(c) for c in columns) or len({c.lower() for c in columns}) != len(columns):
        raise ValueError('Metadata has empty, reserved, or duplicate column names')
    if any(len(row) != len(rows[0]) for row in rows[1:]):
        raise ValueError('Metadata rows must have the same number of columns as the header')
    samples = [row[0] for row in rows[1:]]
    if not samples or any(not s or id_header(s) for s in samples) or len(samples) != len(set(samples)):
        raise ValueError('Metadata has empty, reserved, or duplicate sample IDs')
    return set(samples)


def validate(manifest: Path, metadata: Path, primer_f: str, primer_r: str,
             trunc_f: int, trunc_r: int, amplicon_max: int, min_overlap: int = 12) -> dict:
    primers = (primer_f.upper(), primer_r.upper())
    if any(not p or set(p) - set(IUPAC) for p in primers):
        raise ValueError('Both primers must be nonempty IUPAC DNA, written 5-prime to 3-prime as sequenced')
    if min(trunc_f, trunc_r, amplicon_max) <= 0 or min_overlap < 12:
        raise ValueError('Positive post-primer truncation/amplicon lengths and overlap >=12 are required')
    overlap = trunc_f + trunc_r - amplicon_max
    if overlap < min_overlap:
        raise ValueError(f'Only {overlap} bp overlap remains; need at least {min_overlap}')
    with manifest.open(newline='', encoding='utf-8-sig') as handle:
        reader = csv.DictReader(handle, delimiter='\t')
        fields = ['sample-id', 'forward-absolute-filepath', 'reverse-absolute-filepath']
        if reader.fieldnames != fields:
            raise ValueError(f'PairedEndFastqManifestPhred33V2 requires tab-separated columns {fields}')
        rows = list(reader)
    seen, paths, results = set(), set(), []
    for row in rows:
        if None in row or any(row[key] is None or not row[key].strip() for key in fields):
            raise ValueError('Manifest rows must contain exactly three nonempty tab-separated cells')
        sample = row['sample-id'].strip()
        if sample.startswith('#') or id_header(sample) or sample in seen:
            raise ValueError(f'Reserved or duplicate sample ID: {sample}')
        seen.add(sample)
        files = [Path(row[key].strip()) for key in fields[1:]]
        if any(not p.is_absolute() or not p.is_file() for p in files):
            raise ValueError(f'{sample}: FASTQ paths must be absolute existing files')
        if len({p.resolve() for p in files}) != 2 or any(p.resolve() in paths for p in files):
            raise ValueError(f'{sample}: repeated forward/reverse FASTQ file')
        paths.update(p.resolve() for p in files)
        count, matched, too_short, long_pairs = 0, [0, 0], [0, 0], 0
        for forward, reverse in itertools.zip_longest(fastq(files[0]), fastq(files[1])):
            if forward is None or reverse is None or forward[0] != reverse[0]:
                raise ValueError(f'{sample}: paired read IDs/order/counts do not match')
            count += 1
            long_pairs += all(len(read[1]) - len(primers[i]) >= (trunc_f, trunc_r)[i]
                              for i, read in enumerate((forward, reverse)))
            for i, read in enumerate((forward, reverse)):
                sequence = read[1]
                if count <= 1000:
                    matched[i] += primer_match(sequence, primers[i])
                too_short[i] += len(sequence) - len(primers[i]) < (trunc_f, trunc_r)[i]
        if long_pairs == 0:
            raise ValueError(f'{sample}: no read pairs meet nominal truncation lengths after primer removal')
        results.append({'sample_id': sample, 'raw_pairs': count,
                        'nominal_length_eligible_pairs': long_pairs,
                        'exact_primer_fraction_first_1000': [v/min(count, 1000) for v in matched],
                        'short_fraction_before_quality_filter': [v/count for v in too_short]})
    if not seen or read_metadata(metadata) != seen:
        raise ValueError('Manifest and metadata sample IDs must match exactly')
    warnings = [f"{s['sample_id']}: fewer than 80% exact primer-prefix matches; inspect orientation/adapters"
                for s in results if min(s['exact_primer_fraction_first_1000']) < 0.8]
    return {'samples': results, 'minimum_predicted_overlap': overlap, 'warnings': warnings}


def retention(path: Path, raw_counts: dict[str, int] | None = None) -> dict:
    if raw_counts is not None and any(type(v) is not int or v < 0 for v in raw_counts.values()):
        raise ValueError('Raw read-pair counts must be nonnegative integers')
    with path.open() as handle:
        reader = csv.DictReader((line for line in handle if not line.startswith('#q2:')), delimiter='\t')
        rows = list(reader)
    summaries, warnings = [], []
    for row in rows:
        sample = row.get('sample-id', row.get('sampleid', row.get('#SampleID')))
        if not sample or not sample.strip():
            raise ValueError('DADA2 statistics lack sample IDs')
        sample = sample.strip()
        if 'concatenated' in row:
            raise ValueError('Retention helper requires merged-only DADA2 statistics (retain_unmerged=False)')
        counts = [float(row[key]) for key in ['input', 'filtered', 'denoised', 'merged', 'non-chimeric']]
        if any(not math.isfinite(x) or x < 0 or not x.is_integer() for x in counts):
            raise ValueError('Invalid DADA2 read counts')
        if any(b > a for a, b in zip(counts, counts[1:])):
            raise ValueError('DADA2 retained counts increase between stages')
        if raw_counts is not None and sample not in raw_counts:
            raise ValueError('DADA2 statistics contain samples absent from raw read counts')
        raw = raw_counts[sample] if raw_counts is not None else int(counts[0])
        if counts[0] > raw:
            raise ValueError('DADA2 input exceeds raw read pairs')
        fraction = counts[-1]/raw if raw else 0.0
        basis = 'raw pairs' if raw_counts is not None else 'DADA2 input pairs'
        if fraction < 0.5:
            warnings.append(f'{sample}: retained {fraction:.1%} of {basis}; inspect trimming, quality, merging, chimeras')
        summaries.append({'sample_id': sample, 'raw_pairs': raw if raw_counts is not None else None,
                          'retention_denominator': basis, 'dada2_input': int(counts[0]),
                          'non_chimeric': int(counts[-1]), 'retained_fraction': fraction})
    ids = [r['sample_id'] for r in summaries]
    if not ids or len(ids) != len(set(ids)) or (raw_counts is not None and set(ids) != set(raw_counts)):
        raise ValueError('Missing/duplicate samples in DADA2 statistics')
    return {'samples': summaries, 'warnings': warnings}


def validate_runtime(info: str) -> None:
    versions = {key.strip().replace('_', '-'): value.strip()
                for line in info.splitlines() if ':' in line
                for key, value in [line.split(':', 1)]}
    required = ['rachis version', 'q2cli version', 'cutadapt', 'dada2', 'demux',
                'feature-table', 'feature-classifier', 'taxa', 'types']
    incompatible = [name for name in required
                    if not re.fullmatch(r'2026\.7\.\d+', versions.get(name, ''))]
    if incompatible:
        raise ValueError('This runner requires stable QIIME 2 2026.7 and matching plugins; '
                         'missing or incompatible: ' + ', '.join(incompatible))


def run(args) -> dict:
    qc = validate(args.manifest, args.metadata, args.primer_f, args.primer_r,
                  args.trunc_f, args.trunc_r, args.amplicon_max, args.min_overlap)
    output = args.output.resolve()
    if output.exists() and any(output.iterdir()):
        raise ValueError('Use a fresh output directory; retain prior QIIME artifacts and provenance')
    if not args.classifier.is_file():
        raise ValueError('Provide a release-compatible TaxonomicClassifier .qza')
    info = subprocess.run([args.qiime, 'info'], check=True, text=True, capture_output=True).stdout
    validate_runtime(info)
    output.mkdir(parents=True, exist_ok=True)
    (output/'qiime-info.txt').write_text(info)
    (output/'input-qc.json').write_text(json.dumps(qc, indent=2)+'\n')
    commands = []
    def invoke(*parts):
        command = [args.qiime, *map(str, parts)]
        commands.append(command)
        (output/'commands.json').write_text(json.dumps(commands, indent=2)+'\n')
        with (output/'workflow.log').open('a') as log:
            subprocess.run(command, stdout=log, stderr=subprocess.STDOUT, check=True)
    invoke('tools', 'validate', args.classifier.resolve(), '--level', 'max')
    invoke('tools', 'import', '--type', 'SampleData[PairedEndSequencesWithQuality]',
           '--input-format', 'PairedEndFastqManifestPhred33V2', '--input-path', args.manifest.resolve(),
           '--output-path', output/'demux.qza')
    invoke('cutadapt', 'trim-paired', '--i-demultiplexed-sequences', output/'demux.qza',
           '--p-front-f', '^'+args.primer_f.upper(), '--p-front-r', '^'+args.primer_r.upper(),
           '--p-discard-untrimmed', '--p-cores', args.threads, '--output-dir', output/'cutadapt')
    invoke('demux', 'summarize', '--i-data', output/'cutadapt/trimmed_sequences.qza', '--o-visualization', output/'trimmed.qzv')
    invoke('dada2', 'denoise-paired', '--i-demultiplexed-seqs', output/'cutadapt/trimmed_sequences.qza',
           '--p-trunc-len-f', args.trunc_f, '--p-trunc-len-r', args.trunc_r,
           '--p-trim-left-f', 0, '--p-trim-left-r', 0, '--p-min-overlap', args.min_overlap,
           '--p-n-threads', args.threads, '--output-dir', output/'denoise')
    invoke('feature-table', 'summarize', '--i-table', output/'denoise/table.qza',
           '--m-metadata-file', args.metadata.resolve(), '--o-summary', output/'table.qzv',
           '--o-feature-frequencies', output/'feature-frequencies.qza',
           '--o-sample-frequencies', output/'sample-frequencies.qza')
    invoke('feature-classifier', 'classify-sklearn', '--i-classifier', args.classifier.resolve(),
           '--i-reads', output/'denoise/representative_sequences.qza', '--p-n-jobs', args.threads,
           '--o-classification', output/'taxonomy.qza')
    invoke('taxa', 'barplot', '--i-table', output/'denoise/table.qza', '--i-taxonomy', output/'taxonomy.qza',
           '--m-metadata-file', args.metadata.resolve(), '--o-visualization', output/'taxa.qzv')
    invoke('tools', 'export', '--input-path', output/'denoise/denoising_stats.qza',
           '--output-path', output/'stats')
    artifacts = sorted(output.rglob('*.qza'))
    for artifact in artifacts:
        invoke('tools', 'validate', artifact, '--level', 'max')
    result = retention(output/'stats/stats.tsv', {s['sample_id']: s['raw_pairs'] for s in qc['samples']})
    result.update({'classifier_sha256': digest(args.classifier),
                   'manifest_sha256': digest(args.manifest), 'metadata_sha256': digest(args.metadata),
                   'artifacts': {str(p.relative_to(output)): digest(p) for p in artifacts}})
    (output/'retention-qc.json').write_text(json.dumps(result, indent=2)+'\n')
    return result


def digest(path: Path) -> str:
    value = hashlib.sha256()
    with path.open('rb') as handle:
        for block in iter(lambda: handle.read(1024*1024), b''):
            value.update(block)
    return value.hexdigest()


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    sub = parser.add_subparsers(dest='action', required=True)
    for action in ['validate', 'run']:
        command = sub.add_parser(action)
        command.add_argument('--manifest', type=Path, required=True)
        command.add_argument('--metadata', type=Path, required=True)
        command.add_argument('--primer-f', required=True)
        command.add_argument('--primer-r', required=True)
        command.add_argument('--trunc-f', type=int, required=True)
        command.add_argument('--trunc-r', type=int, required=True)
        command.add_argument('--amplicon-max', type=int, required=True, help='Maximum expected biological insert length AFTER removing primers')
        command.add_argument('--min-overlap', type=int, default=12)
        if action == 'run':
            command.add_argument('--classifier', type=Path, required=True)
            command.add_argument('--output', type=Path, required=True)
            command.add_argument('--qiime', default='qiime')
            command.add_argument('--threads', type=int, default=1)
    stats = sub.add_parser('retention')
    stats.add_argument('stats_tsv', type=Path)
    args = parser.parse_args()
    try:
        if args.action == 'run':
            if args.threads < 1:
                raise ValueError('threads must be positive')
            result = run(args)
        elif args.action == 'validate':
            result = validate(args.manifest, args.metadata, args.primer_f, args.primer_r,
                              args.trunc_f, args.trunc_r, args.amplicon_max, args.min_overlap)
        else:
            result = retention(args.stats_tsv)
    except (ValueError, OSError, EOFError, KeyError, subprocess.CalledProcessError) as exc:
        parser.exit(1, f'Error: {exc}\n')
    print(json.dumps(result, indent=2))


if __name__ == '__main__':
    main()

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Python

The author says: Python 3.10+ for the standard-library validation helper; QIIME 2 2026.7 distribution with cutadapt, dada2, demux, feature-table, feature-classifier, taxa and types plugins for execution. Install through the official conda/container distribution, not PyPI. Requires a compatible trusted classifier and network for installation/reference downloads.

Security

What our scanner noticed· Low risk

  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
K-Dense Inc.
Publisher
K-Dense (Community)
Source
K-Dense-AI/scientific-agent-skills · skills/qiime2-amplicon · commit a25cf9e
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE.md)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by K-Dense Inc. or K-Dense.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download qiime2-amplicon.zip