Add Bactopia Tool
Scaffold a complete Bactopia Tool pipeline from a bioconda/conda-forge package. This creates all three tiers in one shot:
- Module (
modules/{tool}/) -- the Nextflow process that runs the tool
- Subworkflow (
subworkflows/{tool}/) -- orchestrates the module + aggregation
- Workflow (
workflows/bactopia-tools/{tool}/) -- user-facing entry point
This skill handles the common single-tool pattern which covers ~80% of bactopia-tools (abricate, mlst, bakta, quast, sistr, etc.). Multi-stage pipelines like snippy and pangenome should be hand-built.
Prerequisites
Before using this skill, read:
.agents/docs/standards/05-module-documentation.md -- Module GroovyDoc standards
.agents/docs/standards/04-subworkflow-documentation.md -- Subworkflow GroovyDoc standards
Interactive Questioning
This skill is interactive -- ask the user early and often, especially before creating files.
- Multiple questions at once: Use
AskUserQuestion popups (up to 4 questions per batch).
Mark the recommended option with "(Recommended)" at the end of its label and place it first.
- Single simple question: Just ask in chat, no popup needed.
- When in doubt: Ask. It's cheaper to clarify upfront than to regenerate files.
Phased Workflow
Follow these phases in order. When unsure about ANYTHING, ask the user rather than guess.
Phase 1: Package Verification
Goal: Confirm the package exists on bioconda and retrieve version/container information.
Ask the user for the bioconda package name (e.g., mlst, bakta, ssuissero).
Run the lookup command:
bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-scaffold.sh lookup {package_name} --bactopia-path . --pretty
The output includes:
package, channel, version, build -- package identity
summary, home -- tool description and documentation URL
container_refs -- toolName, docker, image strings
existing_components -- which of module/subworkflow/workflow already exist
Present findings to the user and ask them to confirm before proceeding.
If any existing components are found, warn the user.
If the package is not found, ask the user to verify the name.
If the package does not exist on bioconda, inform the user you cannot proceed until a valid bioconda package is provided.
Phase 2: Tool Design
Goal: Gather all design decisions using interactive prompts so files can be generated coherently.
Important: Use the AskUserQuestion tool for structured choices throughout this phase.
Present up to 4 questions per batch. Mark the recommended option (based on WebFetch findings)
with "(Recommended)" at the end of its label and place it first in the options list.
Fetch the tool's documentation using WebFetch on the home URL from Phase 1.
- Extract: command-line options, input file types, output files, version command
- If WebFetch fails, ask the user directly
Batch 1: Core design choices (AskUserQuestion, up to 4 questions)
Based on WebFetch findings, ask these structured questions:
Question 1 -- Input type:
Determines which BACTOPIATOOL_INIT channel to use.
| Input Type |
Channel |
params.workflow.ext |
Module record input |
| Assembly |
assembly |
['fna'] |
record(meta: Record, fna: Path) |
| Reads |
reads |
['fastq'] |
record(meta: Record, r1: Path?, r2: Path?, se: Path?, lr: Path?) |
| Assembly + reads |
assembly_reads |
['fna', 'fastq'] |
record(meta: Record, fna: Path, r1: Path?, r2: Path?, se: Path?, lr: Path?) |
| Proteins |
proteins |
['faa'] |
record(meta: Record, faa: Path) |
| GFF |
gff |
['gff'] |
record(meta: Record, gff: Path) |
| GenBank |
gbff |
['gbk'] |
record(meta: Record, gbff: Path) |
Options (pick top 3 most relevant, "Other" is auto-added for the rest):
- Assembly -- takes FASTA assembly files
- Reads -- takes FASTQ read files
- Assembly + Reads -- takes both FASTA and FASTQ
Question 2 -- Database requirement:
- No database needed
- Yes, requires a user-provided database
Question 3 -- Resource label:
- process_low -- 4 CPU, 8GB, 4h (default for most tools)
- process_medium -- 8 CPU, 32GB, 12h (BLAST-based, database searches)
- process_high -- 12 CPU, 64GB, 24h (memory-intensive)
- process_single -- 1 CPU, 4GB, 2h (single-threaded only)
Question 4 -- Compressed input:
- Yes, handles .gz natively
- No, needs decompression first
Run test-data discovery based on the input type selected in Batch 1:
bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-scaffold.sh test-data --input-type {input_type} --bactopia-path . --pretty
This returns species/accession combinations already used by similar modules, with
pre-computed test_data_path, test_uncompressed_path, test_species, and
test_sample_id values. Use the returned paths directly in the scaffold config
(Phase 3) -- do NOT construct paths manually.
Batch 2: Aggregation and test data (AskUserQuestion, up to 2 questions)
Question 1 -- Aggregation strategy:
- CSVTK_CONCAT -- concatenate per-sample tabular output (most common)
- Dedicated summary module -- tool has its own aggregation command (rare)
- No aggregation -- tool doesn't produce per-sample tabular output
Question 2 -- Test data species:
Present top 3-4 species from the test-data discovery results. Recommend species that
exercise the tool's functionality (e.g., species with multiple MLST schemes for
typing tools, species with known resistance genes for AMR tools). Include the accession
in each option's description.
Present auto-detected details for confirmation.
After the structured choices, present these findings from WebFetch in a summary and
ask the user to confirm or request changes:
- Tool identity: name (snake_case), display name, one-sentence description
- Output files: extensions, descriptions, aggregation field
- User parameters: only flags representing user-meaningful analysis choices
(identity thresholds, scheme selection, algorithm toggles). Exclude infrastructure
params (see below).
- Version command: how the tool reports its version
- Citation: key, name, URL, description, citation text
- Keywords: for GroovyDoc
Infrastructure vs. user parameters (do NOT expose these):
| Tool flag |
Wired to |
Where |
--prefix, --label, --sample-name, etc. |
prefix variable (task.ext.prefix ?: "${_meta.name}") |
Shell block |
--threads, --cpus, -t, -p, etc. |
${task.cpus} |
Shell block or ext.args in module.config |
--output, --outdir, -o, etc. |
Usually . or ${prefix} |
Shell block |
These are written directly in the module's shell block (e.g., --prefix ${prefix},
--threads ${task.cpus}). The prefix variable is set in every module's script block
as prefix = task.ext.prefix ?: "${_meta.name}" and carries the sample name.
Only expose flags that represent user-meaningful analysis choices.
Every user parameter MUST be prefixed with the tool name: {tool}_{param}.
Parameter defaults:
- Do NOT assume a default is needed. Ask the user whether each parameter should have
a specific default value.
- If a string parameter needs a default, use an empty string
"", never null.
- Only include a parameter in the config's
"parameters" array if the user confirms
it should be exposed.
Final confirmation (AskUserQuestion, 1 question)
After presenting the summary, ask:
- Looks good, proceed to file generation
- I need to make changes (user provides details via "Other" or notes)
Phase 3: File Generation
Goal: Generate all 16 files across the three tiers using bactopia-scaffold.
Construct the JSON config from the design decisions. Write it to /tmp/scaffold-config.json:
{
"tool": "{tool_name}",
"display_name": "{DisplayName}",
"description": "{One-sentence description}",
"process_name": "{TOOL_NAME}",
"package": "{package_name}",
"version": "{version}",
"build": "{build}",
"home_url": "{github_url}",
"input_type": "{assembly|reads|assembly_reads|proteins|gff|genbank}",
"has_database": false,
"handles_gz": false,
"layout": "flat",
"resource_label": "{process_low|process_medium|process_high|process_single}",
"version_command": "{version_command}",
"citation_key": "{citation_key}",
"keywords": ["{keyword1}", "{keyword2}"],
"aggregation": {
"strategy": "{csvtk_concat|dedicated_summary|none}",
"field": "{output_field}",
"format": "{tsv|csv}"
},
"outputs": [
{"name": "{field}", "extension": "{ext}", "description": "{desc}"}
],
"parameters": [
{"name": "{tool}_{param}", "type": "{type}", "default": "{default}", "description": "{desc}", "flag": "{--flag}"}
],
"container_refs": {
"toolName": "{from lookup}",
"docker": "{from lookup}",
"image": "{from lookup}"
},
"test_species": "{species}",
"test_sample_id": "{sample_id}",
"test_data_path": "{compressed_path}",
"test_uncompressed_path": "{uncompressed_path}",
"test_dataset": "{dataset_path_or_empty}",
"test_dataset2": "",
"test_dataset3": ""
}
For database-dependent tools, also include:
{
"database": {
"param_name": "{tool}_db",
"test_path": "datasets/{tool}/{db_file}"
}
}
Run the scaffold command:
bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-scaffold.sh tool --config /tmp/scaffold-config.json --bactopia-path . --pretty
The command creates all 16 files. Review the output to confirm which files were created.
Phase 4: Review & Customize
Goal: Review generated files and make tool-specific adjustments.
The templates produce correct scaffolds but many tools need customization:
Module main.nf -- the shell script block is a placeholder. Customize:
- The actual tool command, flags, and I/O handling
- Input decompression logic (if the tool doesn't handle .gz) -- use the standard
is_compressed pattern (see below)
- Database extraction logic (if database-dependent)
- Always preserve the
# Cleanup comment line -- even if empty, it marks where
cleanup steps go and keeps the shell block structure consistent across all modules
- Version extraction command
Standard decompression pattern (for tools that don't handle .gz natively):
In the Groovy script block, before the shell heredoc:
def is_compressed = fna.getName().endsWith(".gz") ? true : false
def fna_name = fna.getName().replace(".gz", "")
In the shell block:
if [ "${is_compressed}" == "true" ]; then
gzip -c -d ${fna} > ${fna_name}
fi
Then use ${fna_name} as the input filename for the tool command. This pattern is
used consistently across modules (e.g., staphopiasccmec, traitar). Prefer fna.getName();
it returns the task-relative staged path, which is what read-in-place tools need. Use
fna.fileName.name only when you copy/decompress to a fresh bare-named local file (explicit
if/else with cp -L) and this module stageAs's the input into a subdir, where a
staging/fna/ prefix would corrupt the output name (e.g., agrvate, gamma). Do NOT use
alternatives like fna.getName()[0..-4] or inline gunzip -c with if [[ ... == *.gz ]].
Module module.config -- review the ext.args construction:
- Verify boolean/string/integer flag handling is correct for each parameter
- Add any fixed flags (e.g.,
--threads ${task.cpus})
Subworkflow main.nf -- usually correct as-is for CSVTK_CONCAT pattern. Check:
- The
@input GroovyDoc matches the subworkflow's input name (may differ from module input)
- The
@output field descriptions are accurate
Workflow main.nf -- check GroovyDoc @publish sections match actual outputs
Run the linter to catch structural issues before proceeding:
bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-lint.sh {tool} --bactopia-path .
This runs bactopia-lint scoped to the new module, subworkflow, and workflow.
Fix any FAILs before moving to Phase 5. Common issues:
- JS005: type/default mismatch in schema.json (e.g.,
type=string but default=null)
- S011: misaligned include braces in subworkflow
- M035/S019: citation key not found in
data/citations.yml
Phase 5: Integration & Next Steps
Goal: Wire up citations and inform the user about remaining steps.
Update data/citations.yml -- add the tool citation entry in alphabetical order:
{tool}:
name: "{ToolName}"
link: "{github_url}"
description: "{One-sentence description}"
cite: "{Full citation text}"
List all created files with full paths.
Remind the user to run these follow-up skills in order:
/run-tests {tool} module and subworkflow --generate -- generate snapshots and verify tests pass (new tools have no existing snapshots)
/update-catalog -- regenerate catalog.json and llms.txt (only after tests pass)
/merge-schemas on the new workflow -- generate nextflow_schema.json
/run-tests {tool} workflow --generate -- generate snapshots and verify the workflow test passes
The --generate flag is required because newly scaffolded tools have no
snapshot files yet. Without it, nf-test will fail immediately on missing
snapshots.
There is no point running /update-catalog or /merge-schemas if the
module/subworkflow tests are failing.
Note: nextflow_schema.json is NOT generated by this skill -- /merge-schemas handles it automatically from the module schema.json files.
Edge Cases
Package not found: The lookup command tries bioconda first, then conda-forge. If both fail, ask the user for version/build manually.
No build string: Container URLs will contain TODO_BUILD placeholders. Flag for manual review.
No --version CLI support: Use hardcoded VERSION pattern in the module main.nf.
Multi-package tools (mulled containers): Warn the user that container URLs cannot be auto-constructed. Flag for manual review.
Component already exists: The lookup output includes existing_components. Warn before proceeding.
Test Data Discovery
Test data paths are discovered dynamically from existing module tests using:
bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-scaffold.sh test-data --input-type {type} --bactopia-path . --pretty
This scans modules/*/tests/main.nf.test for paths matching the input type and returns
pre-computed template variables. Always use the discovered paths -- never construct test
data paths manually. The output includes test_data_path (compressed, for subworkflow
tests), test_uncompressed_path (for module tests), test_species, and test_sample_id.
Supported input types: assembly, reads, assembly_reads, proteins, gff, genbank.
1---2name: add-bactopia-tool3description: Scaffold a complete Bactopia Tool across all three tiers -- module, subworkflow, and workflow entry point under workflows/bactopia-tools/. Creates all files (main.nf, module.config, schema.json, nextflow.config, tests) for the common single-tool pattern. Use when asked to add a new bactopia tool, create a bactopia tool, scaffold a complete tool, add a new analysis tool to bactopia-tools, or wire up a bioconda package as a bactopia-tool. This skill handles the full pipeline from package lookup through file generation -- do not use add-module or add-subworkflow separately when the goal is a complete bactopia-tool.4---56# Add Bactopia Tool78Scaffold a complete Bactopia Tool pipeline from a bioconda/conda-forge package. This creates **all three tiers** in one shot:9101. **Module** (`modules/{tool}/`) -- the Nextflow process that runs the tool112. **Subworkflow** (`subworkflows/{tool}/`) -- orchestrates the module + aggregation123. **Workflow** (`workflows/bactopia-tools/{tool}/`) -- user-facing entry point1314This skill handles the **common single-tool pattern** which covers ~80% of bactopia-tools (abricate, mlst, bakta, quast, sistr, etc.). Multi-stage pipelines like snippy and pangenome should be hand-built.1516## Prerequisites1718Before using this skill, read:19- `.agents/docs/standards/05-module-documentation.md` -- Module GroovyDoc standards20- `.agents/docs/standards/04-subworkflow-documentation.md` -- Subworkflow GroovyDoc standards2122## Interactive Questioning2324This skill is interactive -- ask the user early and often, especially before creating files.2526- **Multiple questions at once:** Use `AskUserQuestion` popups (up to 4 questions per batch).27 Mark the recommended option with "(Recommended)" at the end of its label and place it first.28- **Single simple question:** Just ask in chat, no popup needed.29- **When in doubt:** Ask. It's cheaper to clarify upfront than to regenerate files.3031## Phased Workflow3233Follow these phases in order. When unsure about ANYTHING, ask the user rather than guess.3435---3637### Phase 1: Package Verification3839**Goal:** Confirm the package exists on bioconda and retrieve version/container information.40411. Ask the user for the **bioconda package name** (e.g., `mlst`, `bakta`, `ssuissero`).42432. Run the lookup command:44 ```bash45 bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-scaffold.sh lookup {package_name} --bactopia-path . --pretty46 ```47483. The output includes:49 - `package`, `channel`, `version`, `build` -- package identity50 - `summary`, `home` -- tool description and documentation URL51 - `container_refs` -- `toolName`, `docker`, `image` strings52 - `existing_components` -- which of module/subworkflow/workflow already exist53544. **Present findings to the user** and ask them to confirm before proceeding.55 If any existing components are found, warn the user.56 If the package is not found, ask the user to verify the name.57 If the package does not exist on bioconda, inform the user you cannot proceed until a valid bioconda package is provided.5859---6061### Phase 2: Tool Design6263**Goal:** Gather all design decisions using interactive prompts so files can be generated coherently.6465**Important:** Use the `AskUserQuestion` tool for structured choices throughout this phase.66Present up to 4 questions per batch. Mark the recommended option (based on WebFetch findings)67with "(Recommended)" at the end of its label and place it first in the options list.68691. **Fetch the tool's documentation** using WebFetch on the `home` URL from Phase 1.70 - Extract: command-line options, input file types, output files, version command71 - If WebFetch fails, ask the user directly72732. **Batch 1: Core design choices** (AskUserQuestion, up to 4 questions)7475 Based on WebFetch findings, ask these structured questions:7677 **Question 1 -- Input type:**78 Determines which BACTOPIATOOL_INIT channel to use.7980 | Input Type | Channel | `params.workflow.ext` | Module record input |81 |---|---|---|---|82 | Assembly | `assembly` | `['fna']` | `record(meta: Record, fna: Path)` |83 | Reads | `reads` | `['fastq']` | `record(meta: Record, r1: Path?, r2: Path?, se: Path?, lr: Path?)` |84 | Assembly + reads | `assembly_reads` | `['fna', 'fastq']` | `record(meta: Record, fna: Path, r1: Path?, r2: Path?, se: Path?, lr: Path?)` |85 | Proteins | `proteins` | `['faa']` | `record(meta: Record, faa: Path)` |86 | GFF | `gff` | `['gff']` | `record(meta: Record, gff: Path)` |87 | GenBank | `gbff` | `['gbk']` | `record(meta: Record, gbff: Path)` |8889 Options (pick top 3 most relevant, "Other" is auto-added for the rest):90 - Assembly -- takes FASTA assembly files91 - Reads -- takes FASTQ read files92 - Assembly + Reads -- takes both FASTA and FASTQ9394 **Question 2 -- Database requirement:**95 - No database needed96 - Yes, requires a user-provided database9798 **Question 3 -- Resource label:**99 - process_low -- 4 CPU, 8GB, 4h (default for most tools)100 - process_medium -- 8 CPU, 32GB, 12h (BLAST-based, database searches)101 - process_high -- 12 CPU, 64GB, 24h (memory-intensive)102 - process_single -- 1 CPU, 4GB, 2h (single-threaded only)103104 **Question 4 -- Compressed input:**105 - Yes, handles .gz natively106 - No, needs decompression first1071083. **Run test-data discovery** based on the input type selected in Batch 1:109 ```bash110 bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-scaffold.sh test-data --input-type {input_type} --bactopia-path . --pretty111 ```112 This returns species/accession combinations already used by similar modules, with113 pre-computed `test_data_path`, `test_uncompressed_path`, `test_species`, and114 `test_sample_id` values. Use the returned paths directly in the scaffold config115 (Phase 3) -- do NOT construct paths manually.1161174. **Batch 2: Aggregation and test data** (AskUserQuestion, up to 2 questions)118119 **Question 1 -- Aggregation strategy:**120 - CSVTK_CONCAT -- concatenate per-sample tabular output (most common)121 - Dedicated summary module -- tool has its own aggregation command (rare)122 - No aggregation -- tool doesn't produce per-sample tabular output123124 **Question 2 -- Test data species:**125 Present top 3-4 species from the test-data discovery results. Recommend species that126 exercise the tool's functionality (e.g., species with multiple MLST schemes for127 typing tools, species with known resistance genes for AMR tools). Include the accession128 in each option's description.1291305. **Present auto-detected details for confirmation.**131132 After the structured choices, present these findings from WebFetch in a summary and133 ask the user to confirm or request changes:134135 - **Tool identity**: name (snake_case), display name, one-sentence description136 - **Output files**: extensions, descriptions, aggregation field137 - **User parameters**: only flags representing user-meaningful analysis choices138 (identity thresholds, scheme selection, algorithm toggles). Exclude infrastructure139 params (see below).140 - **Version command**: how the tool reports its version141 - **Citation**: key, name, URL, description, citation text142 - **Keywords**: for GroovyDoc143144 **Infrastructure vs. user parameters (do NOT expose these):**145146 | Tool flag | Wired to | Where |147 |-----------|----------|-------|148 | `--prefix`, `--label`, `--sample-name`, etc. | `prefix` variable (`task.ext.prefix ?: "${_meta.name}"`) | Shell block |149 | `--threads`, `--cpus`, `-t`, `-p`, etc. | `${task.cpus}` | Shell block or `ext.args` in module.config |150 | `--output`, `--outdir`, `-o`, etc. | Usually `.` or `${prefix}` | Shell block |151152 These are written directly in the module's shell block (e.g., `--prefix ${prefix}`,153 `--threads ${task.cpus}`). The `prefix` variable is set in every module's script block154 as `prefix = task.ext.prefix ?: "${_meta.name}"` and carries the sample name.155156 Only expose flags that represent **user-meaningful analysis choices**.157158 Every user parameter MUST be prefixed with the tool name: `{tool}_{param}`.159160 **Parameter defaults:**161 - Do NOT assume a default is needed. Ask the user whether each parameter should have162 a specific default value.163 - If a string parameter needs a default, use an empty string `""`, never `null`.164 - Only include a parameter in the config's `"parameters"` array if the user confirms165 it should be exposed.1661676. **Final confirmation** (AskUserQuestion, 1 question)168169 After presenting the summary, ask:170 - Looks good, proceed to file generation171 - I need to make changes (user provides details via "Other" or notes)172173---174175### Phase 3: File Generation176177**Goal:** Generate all 16 files across the three tiers using `bactopia-scaffold`.1781791. Construct the JSON config from the design decisions. Write it to `/tmp/scaffold-config.json`:180181 ```json182 {183 "tool": "{tool_name}",184 "display_name": "{DisplayName}",185 "description": "{One-sentence description}",186 "process_name": "{TOOL_NAME}",187 "package": "{package_name}",188 "version": "{version}",189 "build": "{build}",190 "home_url": "{github_url}",191 "input_type": "{assembly|reads|assembly_reads|proteins|gff|genbank}",192 "has_database": false,193 "handles_gz": false,194 "layout": "flat",195 "resource_label": "{process_low|process_medium|process_high|process_single}",196 "version_command": "{version_command}",197 "citation_key": "{citation_key}",198 "keywords": ["{keyword1}", "{keyword2}"],199 "aggregation": {200 "strategy": "{csvtk_concat|dedicated_summary|none}",201 "field": "{output_field}",202 "format": "{tsv|csv}"203 },204 "outputs": [205 {"name": "{field}", "extension": "{ext}", "description": "{desc}"}206 ],207 "parameters": [208 {"name": "{tool}_{param}", "type": "{type}", "default": "{default}", "description": "{desc}", "flag": "{--flag}"}209 ],210 "container_refs": {211 "toolName": "{from lookup}",212 "docker": "{from lookup}",213 "image": "{from lookup}"214 },215 "test_species": "{species}",216 "test_sample_id": "{sample_id}",217 "test_data_path": "{compressed_path}",218 "test_uncompressed_path": "{uncompressed_path}",219 "test_dataset": "{dataset_path_or_empty}",220 "test_dataset2": "",221 "test_dataset3": ""222 }223 ```224225 For database-dependent tools, also include:226 ```json227 {228 "database": {229 "param_name": "{tool}_db",230 "test_path": "datasets/{tool}/{db_file}"231 }232 }233 ```2342352. Run the scaffold command:236 ```bash237 bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-scaffold.sh tool --config /tmp/scaffold-config.json --bactopia-path . --pretty238 ```2392403. The command creates all 16 files. Review the output to confirm which files were created.241242---243244### Phase 4: Review & Customize245246**Goal:** Review generated files and make tool-specific adjustments.247248The templates produce correct scaffolds but many tools need customization:2492501. **Module `main.nf`** -- the shell script block is a placeholder. Customize:251 - The actual tool command, flags, and I/O handling252 - Input decompression logic (if the tool doesn't handle .gz) -- use the standard253 `is_compressed` pattern (see below)254 - Database extraction logic (if database-dependent)255 - **Always preserve the `# Cleanup` comment line** -- even if empty, it marks where256 cleanup steps go and keeps the shell block structure consistent across all modules257 - Version extraction command258259 **Standard decompression pattern** (for tools that don't handle .gz natively):260261 In the Groovy script block, before the shell heredoc:262 ```groovy263 def is_compressed = fna.getName().endsWith(".gz") ? true : false264 def fna_name = fna.getName().replace(".gz", "")265 ```266267 In the shell block:268 ```bash269 if [ "${is_compressed}" == "true" ]; then270 gzip -c -d ${fna} > ${fna_name}271 fi272 ```273274 Then use `${fna_name}` as the input filename for the tool command. This pattern is275 used consistently across modules (e.g., staphopiasccmec, traitar). Prefer `fna.getName()`;276 it returns the task-relative staged path, which is what read-in-place tools need. Use277 `fna.fileName.name` only when you copy/decompress to a fresh bare-named local file (explicit278 `if/else` with `cp -L`) and this module `stageAs`'s the input into a subdir, where a279 `staging/fna/` prefix would corrupt the output name (e.g., `agrvate`, `gamma`). Do NOT use280 alternatives like `fna.getName()[0..-4]` or inline `gunzip -c` with `if [[ ... == *.gz ]]`.2812822. **Module `module.config`** -- review the `ext.args` construction:283 - Verify boolean/string/integer flag handling is correct for each parameter284 - Add any fixed flags (e.g., `--threads ${task.cpus}`)2852863. **Subworkflow `main.nf`** -- usually correct as-is for CSVTK_CONCAT pattern. Check:287 - The `@input` GroovyDoc matches the subworkflow's input name (may differ from module input)288 - The `@output` field descriptions are accurate2892904. **Workflow `main.nf`** -- check GroovyDoc `@publish` sections match actual outputs2912925. **Run the linter** to catch structural issues before proceeding:293 ```bash294 bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-lint.sh {tool} --bactopia-path .295 ```296 This runs `bactopia-lint` scoped to the new module, subworkflow, and workflow.297 Fix any FAILs before moving to Phase 5. Common issues:298 - JS005: type/default mismatch in schema.json (e.g., `type=string` but `default=null`)299 - S011: misaligned include braces in subworkflow300 - M035/S019: citation key not found in `data/citations.yml`301302---303304### Phase 5: Integration & Next Steps305306**Goal:** Wire up citations and inform the user about remaining steps.3073081. **Update `data/citations.yml`** -- add the tool citation entry in alphabetical order:309 ```yaml310 {tool}:311 name: "{ToolName}"312 link: "{github_url}"313 description: "{One-sentence description}"314 cite: "{Full citation text}"315 ```3163172. **List all created files** with full paths.3183193. **Remind the user** to run these follow-up skills in order:320 1. `/run-tests {tool} module and subworkflow --generate` -- generate snapshots and verify tests pass (new tools have no existing snapshots)321 2. `/update-catalog` -- regenerate `catalog.json` and `llms.txt` (only after tests pass)322 3. `/merge-schemas` on the new workflow -- generate `nextflow_schema.json`323 4. `/run-tests {tool} workflow --generate` -- generate snapshots and verify the workflow test passes324325 The `--generate` flag is required because newly scaffolded tools have no326 snapshot files yet. Without it, nf-test will fail immediately on missing327 snapshots.328329 There is no point running `/update-catalog` or `/merge-schemas` if the330 module/subworkflow tests are failing.3313324. **Note:** `nextflow_schema.json` is NOT generated by this skill -- `/merge-schemas` handles it automatically from the module `schema.json` files.333334---335336## Edge Cases3373381. **Package not found**: The lookup command tries bioconda first, then conda-forge. If both fail, ask the user for version/build manually.3393402. **No build string**: Container URLs will contain `TODO_BUILD` placeholders. Flag for manual review.3413423. **No --version CLI support**: Use hardcoded VERSION pattern in the module main.nf.3433444. **Multi-package tools** (mulled containers): Warn the user that container URLs cannot be auto-constructed. Flag for manual review.3453465. **Component already exists**: The lookup output includes `existing_components`. Warn before proceeding.347348## Test Data Discovery349350Test data paths are discovered dynamically from existing module tests using:351```bash352bash .agents/skills/add-bactopia-tool/scripts/run-bactopia-scaffold.sh test-data --input-type {type} --bactopia-path . --pretty353```354355This scans `modules/*/tests/main.nf.test` for paths matching the input type and returns356pre-computed template variables. Always use the discovered paths -- never construct test357data paths manually. The output includes `test_data_path` (compressed, for subworkflow358tests), `test_uncompressed_path` (for module tests), `test_species`, and `test_sample_id`.359360Supported input types: `assembly`, `reads`, `assembly_reads`, `proteins`, `gff`, `genbank`.