Skip to content

Add 'Workflows in the AI era' side quest#679

Open
pinin4fjords wants to merge 12 commits intomasterfrom
workflow-management-fundamentals-side-quest-v2
Open

Add 'Workflows in the AI era' side quest#679
pinin4fjords wants to merge 12 commits intomasterfrom
workflow-management-fundamentals-side-quest-v2

Conversation

@pinin4fjords
Copy link
Copy Markdown
Collaborator

@pinin4fjords pinin4fjords commented Oct 16, 2025

Summary

A new side quest that answers, hands-on, the question newcomers actually arrive with in 2026: "why should I use a workflow tool when an AI agent can run my analysis or generate the whole pipeline for me?"

The reader builds a real RNA-seq analysis (FastQC, fastp, Salmon) twice. Once as a bash pipeline of the kind an agent would produce on demand, hitting each engineering limit in turn. Once as a Nextflow workflow, where reproducibility, software tracking, scalability, parallelisation, resource awareness, failure recovery, and portability come from the workflow boundary itself. A short closing section addresses the second half of the question (what if the AI writes the Nextflow?) with the punchline Claude needs them too.

Page

  • docs/en/docs/side_quests/workflows_in_the_ai_era/index.md (~1170 lines, ~75 minutes)
  • Entry in docs/en/docs/side_quests/index.md table and docs/en/mkdocs.yml nav, slotted between Development Environment and Essential Scripting Patterns.

Runnable assets

side-quests/workflows_in_the_ai_era/ (starter, with TODOs) and side-quests/solutions/workflows_in_the_ai_era/ (full solutions). Real RNA-seq test data from nf-core/test-datasets.

Compared to the original PR

This PR was opened in October 2025 as Workflow Management Fundamentals and has been substantially restructured:

  • Renamed to Workflows in the AI era, including the file path (docs/en/docs/side_quests/workflows_in_the_ai_era/index.md) and the runnable-asset directories. The mechanism (build in bash, rebuild in Nextflow, contrast at each step) is preserved.
  • New opening that leads with the agent question and answers it directly, plus a new closing section addressing AI-authored Nextflow.
  • Each Part 1 'Reflection' rewritten as a short observation tying back to AI-style ad-hoc execution; gushing toned down throughout per Adam's review.
  • Each Part 2 'Contrast with scripts' tip now includes the agent-on-its-own clause, so the AI angle lands in the recovery, not just the failure.
  • Install moved out of the way of teaching: section 3.2 is now a short Kick off the tool install block; the mamba activate + version check is a new 3.3.7 placed right before the learner actually needs to run anything. The 3-minute install finishes invisibly while the learner reads and edits.

Repo standards (brought up to current)

  • Migrated to the docs/en/ subtree and the dir-per-side-quest layout.
  • Migrated publishDir -> workflow output system (publish: block + top-level output {} + -output-dir on the CLI). No params.outdir left.
  • Stripped meta maps in favour of tuple val(id), path(reads). The metadata side quest is the right home for maps.
  • Repo heading numbering applied (## 1. / ### 1.1. with trailing periods); passes check_headings.py.
  • All em-dashes removed from prose; passes prettier.
  • Adam's prior inline review comments (LLM-cliche line, polyglot terminology, table tidying, container-line accuracy, FASTQC paste-and-explain framing, val(meta) -> val(id)) addressed; some were already fixed in earlier commits and are now consolidated into the rewrite.

Verified

  • nextflow lint side-quests/solutions/workflows_in_the_ai_era/ returns zero errors. (Starter copy keeps ??? placeholders; CI lints **/solutions/* only per .github/workflows/nextflow-lint.yml.)
  • uv run .github/check_headings.py clean.
  • prettier --check clean.
  • Solution Nextflow pipeline runs end-to-end in Docker (10 tasks, ~1 min); -resume is a full cache hit; outputs land at results/{fastqc,fastp,salmon}/.
  • Tutorial walkthrough using the /run-tutorial skill inside the ghcr.io/nextflow-io/training:latest container: Part 1 mamba install completes in ~3 min, fastp + salmon run on real test data; Part 2 already covered above.

Test plan

  • Render the page on the Netlify deploy preview and confirm the new opening, the kick-off section, the agent clauses in Part 2 callbacks, and the closing section read as intended.
  • Walk through Part 1 in a fresh Codespace to confirm the mamba activate + version check at 3.3.7 lands when the install would have finished naturally.
  • Walk through Part 2 in a fresh Codespace to confirm the nextflow run main.nf -output-dir results -profile docker flow.

@netlify
Copy link
Copy Markdown

netlify Bot commented Oct 16, 2025

Deploy Preview for nextflow-training ready!

Name Link
🔨 Latest commit c9e8860
🔍 Latest deploy log https://app.netlify.com/projects/nextflow-training/deploys/69f33c115b6f460008950ef3
😎 Deploy Preview https://deploy-preview-679--nextflow-training.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@pinin4fjords pinin4fjords marked this pull request as draft October 16, 2025 15:25
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 12, 2026

Nextflow linting complete!

❌ 4 files had 21 errors
✅ 170 files had no errors
🔧 153 files would be changed by auto-formatting

💡 Tip: Click filename locations to go directly to that code.

View all 21 issues
Type Location Message
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:11:1 Invalid include source: '/home/runner/work/training/training/hello-nextflow/solutions/5-hello-containers/modules/sayHello.nf'
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:12:1 Invalid include source: '/home/runner/work/training/training/hello-nextflow/solutions/5-hello-containers/modules/convertToUpper.nf'
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:13:1 Invalid include source: '/home/runner/work/training/training/hello-nextflow/solutions/5-hello-containers/modules/collectGreetings.nf'
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:24:5 sayHello is not defined
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:27:5 convertToUpper is not defined
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:27:20 sayHello is not defined
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:30:5 collectGreetings is not defined
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:30:22 convertToUpper is not defined
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:33:5 collectGreetings is not defined
Error hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf:36:11 collectGreetings is not defined
Error hello-nf-core/solutions/core-hello-part2/nextflow.config:154:17 Invalid include source: '/home/runner/work/training/training/hello-nf-core/solutions/core-hello-part2/conf/test_full.config'
Error side-quests/solutions/workflows_of_workflows/workflows/greeting.nf:1:1 Invalid include source: '/home/runner/work/training/training/side-quests/solutions/workflows_of_workflows/modules/validate_name.nf'
Error side-quests/solutions/workflows_of_workflows/workflows/greeting.nf:2:1 Invalid include source: '/home/runner/work/training/training/side-quests/solutions/workflows_of_workflows/modules/say_hello.nf'
Error side-quests/solutions/workflows_of_workflows/workflows/greeting.nf:3:1 Invalid include source: '/home/runner/work/training/training/side-quests/solutions/workflows_of_workflows/modules/timestamp_greeting.nf'
Error side-quests/solutions/workflows_of_workflows/workflows/greeting.nf:11:24 VALIDATE_NAME is not defined
Error side-quests/solutions/workflows_of_workflows/workflows/greeting.nf:12:24 SAY_HELLO is not defined
Error side-quests/solutions/workflows_of_workflows/workflows/greeting.nf:13:26 TIMESTAMP_GREETING is not defined
Error side-quests/solutions/workflows_of_workflows/workflows/transform.nf:1:1 Invalid include source: '/home/runner/work/training/training/side-quests/solutions/workflows_of_workflows/modules/say_hello_upper.nf'
Error side-quests/solutions/workflows_of_workflows/workflows/transform.nf:2:1 Invalid include source: '/home/runner/work/training/training/side-quests/solutions/workflows_of_workflows/modules/reverse_text.nf'
Error side-quests/solutions/workflows_of_workflows/workflows/transform.nf:10:20 SAY_HELLO_UPPER is not defined
Error side-quests/solutions/workflows_of_workflows/workflows/transform.nf:11:23 REVERSE_TEXT is not defined
View formatting changes
FileDiff
hello-nextflow/solutions/1-hello-world/hello-world-3.nf
View
@@ -8,7 +8,7 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     output:
-        path 'output.txt'
+    path 'output.txt'
 
     script:
     """
hello-nextflow/solutions/1-hello-world/hello-world-4.nf
View
@@ -8,14 +8,14 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path 'output.txt'
+    path 'output.txt'
 
     script:
     """
-    echo '$greeting' > output.txt
+    echo '${greeting}' > output.txt
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-1.nf
View
@@ -8,14 +8,14 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path 'output.txt'
+    path 'output.txt'
 
     script:
     """
-    echo '$greeting' > output.txt
+    echo '${greeting}' > output.txt
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-2.nf
View
@@ -8,14 +8,14 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path "${greeting}-output.txt"
+    path "${greeting}-output.txt"
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-3.nf
View
@@ -8,14 +8,14 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path "${greeting}-output.txt"
+    path "${greeting}-output.txt"
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-4.nf
View
@@ -8,14 +8,14 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path "${greeting}-output.txt"
+    path "${greeting}-output.txt"
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-1.nf
View
@@ -8,14 +8,14 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path "${greeting}-output.txt"
+    path "${greeting}-output.txt"
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-2.nf
View
@@ -8,14 +8,14 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path "${greeting}-output.txt"
+    path "${greeting}-output.txt"
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-3.nf
View
@@ -8,14 +8,14 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path "${greeting}-output.txt"
+    path "${greeting}-output.txt"
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-4.nf
View
@@ -8,14 +8,14 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path "${greeting}-output.txt"
+    path "${greeting}-output.txt"
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
... (truncated)
hello-nextflow/solutions/4-hello-modules/hello-modules-2.nf
View
@@ -8,14 +8,14 @@ process convertToUpper {
     publishDir 'results', mode: 'copy'
 
     input:
-        path input_file
+    path input_file
 
     output:
-        path "UPPER-${input_file}"
+    path "UPPER-${input_file}"
 
     script:
     """
-    cat '$input_file' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
+    cat '${input_file}' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
... (truncated)
hello-nextflow/solutions/4-hello-modules/hello-modules-3.nf
View
@@ -8,15 +8,15 @@ process collectGreetings {
     publishDir 'results', mode: 'copy'
 
     input:
-        path input_files
-        val batch_name
+    path input_files
+    val batch_name
 
     output:
-        path "COLLECTED-${batch_name}-output.txt" , emit: outfile
-        val count_greetings , emit: count
+    path "COLLECTED-${batch_name}-output.txt", emit: outfile
+    val count_greetings, emit: count
 
... (truncated)
hello-nextflow/solutions/4-hello-modules/hello-modules-4.nf
View
@@ -15,8 +15,8 @@ workflow {
 
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.greeting)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
 
     // emit a greeting
     sayHello(greeting_ch)
@@ -28,5 +28,5 @@ workflow {
     collectGreetings(convertToUpper.out.collect(), params.batch)
 
     // emit a message about the size of the batch
... (truncated)
hello-nextflow/solutions/4-hello-modules/modules/collectGreetings.nf
View
@@ -6,15 +6,15 @@ process collectGreetings {
     publishDir 'results', mode: 'copy'
 
     input:
-        path input_files
-        val batch_name
+    path input_files
+    val batch_name
 
     output:
-        path "COLLECTED-${batch_name}-output.txt" , emit: outfile
-        val count_greetings , emit: count
+    path "COLLECTED-${batch_name}-output.txt", emit: outfile
+    val count_greetings, emit: count
 
... (truncated)
hello-nextflow/solutions/4-hello-modules/modules/convertToUpper.nf
View
@@ -8,13 +8,13 @@ process convertToUpper {
     publishDir 'results', mode: 'copy'
 
     input:
-        path input_file
+    path input_file
 
     output:
-        path "UPPER-${input_file}"
+    path "UPPER-${input_file}"
 
     script:
     """
-    cat '$input_file' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
+    cat '${input_file}' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
... (truncated)
hello-nextflow/solutions/4-hello-modules/modules/sayHello.nf
View
@@ -8,13 +8,13 @@ process sayHello {
     publishDir 'results', mode: 'copy'
 
     input:
-        val greeting
+    val greeting
 
     output:
-        path "${greeting}-output.txt"
+    path "${greeting}-output.txt"
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
... (truncated)
hello-nextflow/solutions/5-hello-containers/modules/cowpy.nf
View
@@ -8,14 +8,14 @@ process cowpy {
     container 'community.wave.seqera.io/library/cowpy:1.1.5--3db457ae1977a273'
 
     input:
-        path input_file
-        val character
+    path input_file
+    val character
 
     output:
-        path "cowpy-${input_file}"
+    path "cowpy-${input_file}"
 
     script:
     """
... (truncated)
hello-nextflow/solutions/6-hello-config/modules/cowpy.nf
View
@@ -9,14 +9,14 @@ process cowpy {
     conda 'conda-forge::cowpy==1.1.5'
 
     input:
-        path input_file
-        val character
+    path input_file
+    val character
 
     output:
-        path "cowpy-${input_file}"
+    path "cowpy-${input_file}"
 
     script:
     """
... (truncated)
hello-nf-core/solutions/composable-hello/hello.nf
View
@@ -14,9 +14,7 @@ include { collectGreetings } from './modules/collectGreetings.nf'
 include { cowpy } from './modules/cowpy.nf'
 
 workflow HELLO {
-
     take:
-    // channel of greetings
     greeting_ch
 
     main:
hello-nf-core/solutions/composable-hello/main.nf
View
@@ -9,12 +9,12 @@ params.greeting = 'greetings.csv'
 workflow {
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.greeting)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
 
     // call the imported workflow on the channel of greetings
     HELLO(greeting_ch)
 
     // view the outputs emitted by the workflow
-    HELLO.out.view { output -> "Output: $output" }
+    HELLO.out.view { output -> "Output: ${output}" }
... (truncated)
hello-nf-core/solutions/composable-hello/modules/collectGreetings.nf
View
@@ -10,8 +10,8 @@ process collectGreetings {
     val batch_name
 
     output:
-    path "COLLECTED-${batch_name}-output.txt" , emit: outfile
-    val count_greetings , emit: count
+    path "COLLECTED-${batch_name}-output.txt", emit: outfile
+    val count_greetings, emit: count
 
     script:
     count_greetings = input_files.size()
hello-nf-core/solutions/composable-hello/modules/convertToUpper.nf
View
@@ -15,6 +15,6 @@ process convertToUpper {
 
     script:
     """
-    cat '$input_file' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
+    cat '${input_file}' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
     """
 }
hello-nf-core/solutions/composable-hello/modules/cowpy.nf
View
@@ -17,6 +17,6 @@ process cowpy {
 
     script:
     """
-    cat $input_file | cowpy -c "$character" > cowpy-${input_file}
+    cat ${input_file} | cowpy -c "${character}" > cowpy-${input_file}
     """
 }
hello-nf-core/solutions/composable-hello/modules/sayHello.nf
View
@@ -15,6 +15,6 @@ process sayHello {
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
     """
 }
hello-nf-core/solutions/core-hello-part2/conf/base.config
View
@@ -11,13 +11,13 @@
 process {
 
     // TODO nf-core: Check the defaults for all processes
-    cpus   = { 1      * task.attempt }
-    memory = { 6.GB   * task.attempt }
-    time   = { 4.h    * task.attempt }
+    cpus = { 1 * task.attempt }
+    memory = { 6.GB * task.attempt }
+    time = { 4.h * task.attempt }
 
     errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' }
-    maxRetries    = 1
-    maxErrors     = '-1'
+    maxRetries = 1
... (truncated)
hello-nf-core/solutions/core-hello-part2/conf/modules.config
View
@@ -15,7 +15,6 @@ process {
     publishDir = [
         path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" },
         mode: params.publish_dir_mode,
-        saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
+        saveAs: { filename -> filename.equals('versions.yml') ? null : filename },
     ]
-
 }
hello-nf-core/solutions/core-hello-part2/conf/test.config
View
@@ -14,18 +14,18 @@ process {
     resourceLimits = [
         cpus: 2,
         memory: '4.GB',
-        time: '1.h'
+        time: '1.h',
     ]
 }
 
 params {
-    config_profile_name        = 'Test profile'
+    config_profile_name = 'Test profile'
     config_profile_description = 'Minimal test dataset to check pipeline function'
 
     // Input data
... (truncated)
hello-nf-core/solutions/core-hello-part2/main.nf
View
@@ -13,9 +13,9 @@
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
 
-include { HELLO  } from './workflows/hello'
+include { HELLO } from './workflows/hello'
 include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_hello_pipeline'
-include { PIPELINE_COMPLETION     } from './subworkflows/local/utils_nfcore_hello_pipeline'
+include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_hello_pipeline'
 /*
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     NAMED WORKFLOWS FOR PIPELINE
@@ -26,7 +26,6 @@ include { PIPELINE_COMPLETION     } from './subworkflows/local/utils_nfcore_hell
 // WORKFLOW: Run main analysis pipeline depending on type of input
 //
... (truncated)
hello-nf-core/solutions/core-hello-part2/modules/local/collectGreetings.nf
View
@@ -10,8 +10,8 @@ process collectGreetings {
     val batch_name
 
     output:
-    path "COLLECTED-${batch_name}-output.txt" , emit: outfile
-    val count_greetings , emit: count
+    path "COLLECTED-${batch_name}-output.txt", emit: outfile
+    val count_greetings, emit: count
 
     script:
     count_greetings = input_files.size()
hello-nf-core/solutions/core-hello-part2/modules/local/convertToUpper.nf
View
@@ -15,6 +15,6 @@ process convertToUpper {
 
     script:
     """
-    cat '$input_file' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
+    cat '${input_file}' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
     """
 }
hello-nf-core/solutions/core-hello-part2/modules/local/cowpy.nf
View
@@ -17,6 +17,6 @@ process cowpy {
 
     script:
     """
-    cat $input_file | cowpy -c "$character" > cowpy-${input_file}
+    cat ${input_file} | cowpy -c "${character}" > cowpy-${input_file}
     """
 }
hello-nf-core/solutions/core-hello-part2/modules/local/sayHello.nf
View
@@ -15,6 +15,6 @@ process sayHello {
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
     """
 }
hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf
View
@@ -8,13 +8,13 @@
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
 
-include { UTILS_NFSCHEMA_PLUGIN     } from '../../nf-core/utils_nfschema_plugin'
-include { paramsSummaryMap          } from 'plugin/nf-schema'
-include { samplesheetToList         } from 'plugin/nf-schema'
-include { paramsHelp                } from 'plugin/nf-schema'
-include { completionSummary         } from '../../nf-core/utils_nfcore_pipeline'
-include { UTILS_NFCORE_PIPELINE     } from '../../nf-core/utils_nfcore_pipeline'
-include { UTILS_NEXTFLOW_PIPELINE   } from '../../nf-core/utils_nextflow_pipeline'
+include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin'
+include { paramsSummaryMap } from 'plugin/nf-schema'
+include { samplesheetToList } from 'plugin/nf-schema'
+include { paramsHelp } from 'plugin/nf-schema'
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nextflow_pipeline/main.nf
View
@@ -10,9 +10,9 @@
 
 workflow UTILS_NEXTFLOW_PIPELINE {
     take:
-    print_version        // boolean: print version
-    dump_parameters      // boolean: dump parameters
-    outdir               //    path: base directory used to publish pipeline results
+    print_version // boolean: print version
+    dump_parameters // boolean: dump parameters
+    outdir //    path: base directory used to publish pipeline results
     check_conda_channels // boolean: check conda channels
 
     main:
@@ -72,10 +72,10 @@ def getWorkflowVersion() {
 //
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config
View
@@ -1,9 +1,9 @@
 manifest {
-    name            = 'nextflow_workflow'
-    author          = """nf-core"""
-    homePage        = 'https://127.0.0.1'
-    description     = """Dummy pipeline"""
+    name = 'nextflow_workflow'
+    author = """nf-core"""
+    homePage = 'https://127.0.0.1'
+    description = """Dummy pipeline"""
     nextflowVersion = '!>=23.04.0'
-    version         = '9.9.9'
-    doi             = 'https://doi.org/10.5281/zenodo.5070524'
+    version = '9.9.9'
+    doi = 'https://doi.org/10.5281/zenodo.5070524'
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/main.nf
View
@@ -125,12 +125,12 @@ def paramsSummaryMultiqc(summary_params) {
         }
 
     def yaml_file_text = "id: '${workflow.manifest.name.replace('/', '-')}-summary'\n" as String
-    yaml_file_text     += "description: ' - this information is collected when the pipeline is started.'\n"
-    yaml_file_text     += "section_name: '${workflow.manifest.name} Workflow Summary'\n"
-    yaml_file_text     += "section_href: 'https://github.com/${workflow.manifest.name}'\n"
-    yaml_file_text     += "plot_type: 'html'\n"
-    yaml_file_text     += "data: |\n"
-    yaml_file_text     += "${summary_section}"
+    yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n"
+    yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n"
+    yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n"
+    yaml_file_text += "plot_type: 'html'\n"
+    yaml_file_text += "data: |\n"
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config
View
@@ -1,9 +1,9 @@
 manifest {
-    name            = 'nextflow_workflow'
-    author          = """nf-core"""
-    homePage        = 'https://127.0.0.1'
-    description     = """Dummy pipeline"""
-    nextflowVersion  = '!>=23.04.0'
-    version         = '9.9.9'
-    doi             = 'https://doi.org/10.5281/zenodo.5070524'
+    name = 'nextflow_workflow'
+    author = """nf-core"""
+    homePage = 'https://127.0.0.1'
+    description = """Dummy pipeline"""
+    nextflowVersion = '!>=23.04.0'
+    version = '9.9.9'
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/main.nf
View
@@ -2,30 +2,25 @@
 // Subworkflow that uses the nf-schema plugin to validate parameters and render the parameter summary
 //
 
-include { paramsSummaryLog   } from 'plugin/nf-schema'
+include { paramsSummaryLog } from 'plugin/nf-schema'
 include { validateParameters } from 'plugin/nf-schema'
-include { paramsHelp         } from 'plugin/nf-schema'
+include { paramsHelp } from 'plugin/nf-schema'
 
 workflow UTILS_NFSCHEMA_PLUGIN {
-
     take:
-    input_workflow      // workflow: the workflow object used by nf-schema to get metadata from the workflow
-    validate_params     // boolean:  validate the parameters
... (truncated)
hello-nf-core/solutions/core-hello-part2/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-part3/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-part3/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-part3/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-part3/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-part3/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/convertToUpper.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/cowpy.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/sayHello.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/nf-core/cat/cat/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/nf-core/cat/cat/tests/nextflow_unzipped_zipped.config(truncated)
hello-nf-core/solutions/core-hello-part3/modules/nf-core/cat/cat/tests/nextflow_zipped_unzipped.config(truncated)
hello-nf-core/solutions/core-hello-part3/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-part4/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-part4/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-part4/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-part4/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-part4/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/convertToUpper.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/cowpy.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/cowpy/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/sayHello.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/nf-core/cat/cat/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/nf-core/cat/cat/tests/nextflow_unzipped_zipped.config(truncated)
hello-nf-core/solutions/core-hello-part4/modules/nf-core/cat/cat/tests/nextflow_zipped_unzipped.config(truncated)
hello-nf-core/solutions/core-hello-part4/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-part5/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-part5/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-part5/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-part5/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-part5/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/local/convertToUpper.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/local/cowpy.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/local/cowpy/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/local/sayHello.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/nf-core/cat/cat/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/nf-core/cat/cat/tests/nextflow_unzipped_zipped.config(truncated)
hello-nf-core/solutions/core-hello-part5/modules/nf-core/cat/cat/tests/nextflow_zipped_unzipped.config(truncated)
hello-nf-core/solutions/core-hello-part5/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-start/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-start/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-start/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-start/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-start/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/workflows/hello.nf(truncated)
side-quests/solutions/essential_scripting_patterns/collect.nf(truncated)
side-quests/solutions/essential_scripting_patterns/main.nf(truncated)
side-quests/solutions/essential_scripting_patterns/modules/fastp.nf(truncated)
side-quests/solutions/essential_scripting_patterns/modules/trimgalore.nf(truncated)
side-quests/solutions/metadata/1/main.nf(truncated)
side-quests/solutions/metadata/2/main.nf(truncated)
side-quests/solutions/metadata/3.2/main.nf(truncated)
side-quests/solutions/metadata/3.2/modules/cowpy.nf(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/conf/base.config(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/conf/modules.config(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/conf/test.config(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/conf/test_full.config(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/main.nf(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/modules/local/fastqe/main.nf(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/modules/nf-core/multiqc/main.nf(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/modules/nf-core/multiqc/tests/nextflow.config(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/modules/nf-core/seqtk/trim/main.nf(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/nextflow.config(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/subworkflows/local/utils_nfcore_myfirstpipeline_pipeline/main.nf(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
side-quests/solutions/nf-core/myorg-myfirstpipeline/workflows/myfirstpipeline.nf(truncated)
side-quests/solutions/nf-test/tests/nextflow.config(truncated)
side-quests/solutions/splitting_and_grouping/main.nf(truncated)
side-quests/solutions/workflow_management_fundamentals/nextflow/main.nf(truncated)
side-quests/solutions/workflow_management_fundamentals/nextflow/modules/fastp.nf(truncated)
side-quests/solutions/workflow_management_fundamentals/nextflow/modules/fastqc.nf(truncated)

@pinin4fjords pinin4fjords marked this pull request as ready for review January 13, 2026 10:04
@pinin4fjords pinin4fjords changed the title [WIP] Add Workflow Management Fundamentals side quest Add Workflow Management Fundamentals side quest Jan 13, 2026
Copy link
Copy Markdown
Collaborator

@adamrtalbot adamrtalbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great start! I have some comments:

  • reduce the gushing over workflows a bit, show don't tell
  • reduce the rate of hyphens.
  • we shouldn't over explain how a Nextflow process works. Just highlight the features (inputs, outputs, script, software packaging). If a user wants to learn how to use Nextflow, they should move to hello-nextflow afterwards.

Comment thread docs/side_quests/workflow_management_fundamentals.md Outdated
- **Efficient parallelization** - Independent tasks run simultaneously, so analysis completes in hours, not days.
- **Resource awareness** - Respects memory and CPU limits. No crashed jobs or killed processes.
- **Failure recovery** - Can resume from where it stopped. A single failure doesn't waste hours of completed work.
- **Portability** - Runs on laptop, cluster, or cloud with the same code.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Polyglot?

Comment thread docs/side_quests/workflow_management_fundamentals.md Outdated

#### 1.3.4. Add Salmon Index Download

Salmon needs a pre-built index of the reference transcriptome. We'll download a pre-built index (to save time) only if it doesn't already exist. This avoids re-downloading for every sample.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's possibly a lesson on conditional logic here, which is easier in a workflow language.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, ish. It may be a trickier conceptually in Nextflow, but it's more robust (detecting the directory vs the object existing).

Comment thread docs/side_quests/workflow_management_fundamentals.md Outdated
Comment thread docs/side_quests/workflow_management_fundamentals.md Outdated
Comment thread docs/side_quests/workflow_management_fundamentals.md Outdated
Comment thread docs/side_quests/workflow_management_fundamentals.md Outdated
Comment thread docs/side_quests/workflow_management_fundamentals.md Outdated
Comment thread docs/side_quests/workflow_management_fundamentals.md Outdated
@pinin4fjords
Copy link
Copy Markdown
Collaborator Author

Changes addressing review feedback

Adam's specific comments addressed:

  • Line 29: Fixed LLM-cliche phrasing → "The question is how can we achieve this in one pipeline?"
  • Line 46: Reformatted table with Software column
  • Line 284: Added note about conditional logic fragility (directory checks vs actual task success)
  • Line 585: Toned down "There has to be a better way" → "This is where workflow managers come in."
  • Line 618: Fixed container accuracy - now mentions Nextflow supports multiple software packaging tools, not just containers
  • Line 666: Streamlined FASTQC process explanation - shows complete process first, then brief explanation
  • Line 743: Simplified container tip text
  • Line 898: Changed val(meta) to val(id) throughout - simpler for an intro tutorial

Additional changes per feedback:

  • Toned down LLM language throughout - replaced "Remember...?" rhetorical callbacks with "In Part 1..." factual references, changed "The Magic of Resume" to "Resume and Caching", removed dramatic one-liners
  • Added MultiQC aggregation sections to both Part 1 (bash) and Part 2 (Nextflow) to better demonstrate workflow benefits for complex pipelines - this addresses the feedback that it "doesn't quite hit home the benefit of workflows for complex pipelines"

Unclear comments (left as-is for clarification):

  • Line 25 "Polyglot?" - "Portability" seems correct for describing cross-platform execution
  • Line 614 empty suggestion - This was the "#### No Tool Installation Needed" header, unclear what was intended

pinin4fjords and others added 5 commits April 30, 2026 10:15
Resets the PR branch onto current master and places the side quest
content under the new docs/en/ subtree at workflows_in_the_ai_era/
to match the dir-per-quest layout used by the rest of the side
quests, and to make the AI-era framing visible in the file structure.

Filename + nav layout only; content rewrite, publishDir migration,
meta-map removal, and lint fixes follow in subsequent commits.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop publishDir directives from all three modules
- Drop params.outdir; replace with workflow-level output { } block
  in main.nf using publish: declarations
- Replace tuple val(meta), path(reads) with tuple val(id),
  path(reads); meta maps are the metadata side quest's territory
- Switch deprecated `Channel` to lowercase `channel`
- Trim explanatory comments from modules; the markdown does the
  teaching
- Tidy nextflow.config: trace/timeline/report write under
  pipeline_info/, profiles cleaned up

Solution copy passes nextflow lint with zero errors. Starter copy
keeps ??? placeholders (CI lints only solutions/, per
.github/workflows/nextflow-lint.yml).

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- New title and opening anchor: lead with the question newcomers
  actually arrive with ('why a workflow tool when an agent can run my
  analysis or generate the pipeline for me?'), and answer with the
  durable-artefact case in three short paragraphs
- Reframe the 'good analysis pipeline' list as the properties an AI
  assistant doesn't give you for free
- Apply repo heading numbering (## 1., ### 1.1., #### 1.1.1.) across
  the page; passes check_headings.py
- Replace each Part 1 'Reflection' / advocacy paragraph with a short
  '### Takeaway' that names what the agent's ad-hoc execution didn't
  give you (provenance, throttling, version pinning, resume)
- Update Part 2 'Contrast with scripts' tips to 'Contrast with the
  agent's script' and add the agent-on-its-own clause to each
- Migrate Part 2 process examples to drop publishDir; show the
  workflow-level publish: + output {} block in main.nf and recommend
  -output-dir on the CLI
- Update path references: side-quests/workflow_management_fundamentals
  -> side-quests/workflows_in_the_ai_era; ../hello_nextflow ->
  ../../hello_nextflow (matches the dir-per-quest layout)
- Add 'Learning goals' and 'Prerequisites' subsections near the top to
  match other side quests
- Add new section 5 'But what if the AI writes the Nextflow?' that
  closes the loop on the second half of the user's question, with the
  punchline 'because Claude needs them too'
- Restructure Summary as 'Key patterns' (pinned container, publish/
  output block, -output-dir, -resume, profiles) plus 'Additional
  resources' and a 'What's next?' link back to side_quests/index.md
- Strip em-dashes (CLAUDE.md style); replace with periods, colons, or
  semicolons
- Drop tag '$meta.id' references in markdown to match the modules

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add --platform=linux/amd64 to docker.runOptions, mirroring
  hello-nf-core. Required for FastQC's bioconda image to run on
  Apple Silicon (the JVM SIGSEGVs under qemu without it).
- Drop the timeline/report/trace blocks. They were writing into
  pipeline_info/ relative to the launch dir, polluting the source
  tree and tripping 'file already exists' on -resume. They aren't
  load-bearing for this side quest's pedagogy; if a learner wants
  them they can pass -with-report -with-timeline -with-trace.

Verified end-to-end: solution pipeline completes 10 tasks in ~1m on
docker; -resume is a full cache hit; outputs land at
results/{fastqc,fastp,salmon}/.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Correct hl_lines on three Nextflow code blocks: avoid highlighting
  structural keywords (input:/output:), highlight the meaningful
  content lines, and don't run past the end of the snippet.
  - fastp.nf:   "5 8-10 13-21" -> "6 9-11 15-21"
  - salmon.nf:  "8-9 12 16-22" -> "9-10 13 17-23"
  - main.nf:    "1 4-10 13-30" -> "1 3-9 12-18"
- Rename two subsection labels back from 'Takeaway' to 'The problem:
  sequential execution' and 'The hidden problem' (they discuss new
  problems, not summarise what was learned).
- Update side-quests/workflows_in_the_ai_era/README.md to match the
  new title, the new solution path, and the AI-era framing.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pinin4fjords pinin4fjords force-pushed the workflow-management-fundamentals-side-quest-v2 branch from a41659b to b67f0fe Compare April 30, 2026 09:43
Two findings from walking the tutorial as a learner inside the
training container:

1. Section 3.1.3 documented "ls -la bash/" but showed tree-style
   output. ls -la wouldn't produce that. Switched to "ls bash/" with
   the actual one-line output, then added a short bullet list giving
   each script's role (which was the value of the original tree
   listing).

2. The mamba install is ~3 minutes. The previous structure had it as
   a hard wall in 3.2 before any teaching happened. Restructured:
   - 3.2 is now a short "Kick off the tool install" section: one
     paragraph + the install command, with a note that the activation
     and version check come later.
   - The activate + version check + "remember to re-activate" warning
     moved to a new 3.3.7 "Activate the env and verify it's ready",
     placed right before the learner actually needs to run anything.
   - The install-pain takeaway folded into 3.3.9 (Takeaway), which
     now mentions provenance for the conda env solve.

   Net: the learner kicks off the install, reads through 3.3.1-3.3.6
   building the script (which takes longer than 3 minutes), and by
   the time they need to run, the env is ready. No idle waiting.

Verified end-to-end: mamba install (~3 min), activate, fastp + salmon
ran on a real sample inside the training container. FastQC's JVM
crashes under x86 emulation on Apple Silicon Docker without Rosetta;
that's a Mac-host issue, not a tutorial bug, since Codespaces is
linux/amd64 native.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pinin4fjords pinin4fjords changed the title Add Workflow Management Fundamentals side quest Add 'Workflows in the AI era' side quest Apr 30, 2026
pinin4fjords and others added 6 commits April 30, 2026 11:20
The previous framing implied 'agent produces bash, you produce
Nextflow'. In reality the same agent writes either form just as
readily. The lesson is not 'AI vs no-AI' but 'what abstraction is
worth pointing AI at'.

- Opening: leads with 'agent will produce either bash or Nextflow;
  question is which artefact is worth keeping'. Both forms are AI-
  authored options; the engineering virtues come from the abstraction,
  not the author.
- Section 1 properties intro: 'properties any agent producing bash
  has to remember to write, every time, and the properties a workflow
  tool supplies structurally'.
- 3.3.9 takeaway: bash script is what the agent might hand you for a
  quick analysis; everything past 'ran once on my laptop' is the
  agent's responsibility separately. Asking the same agent for a
  workflow is what fixes it.
- 3.5.3 hidden problem: an agent producing bash needs to write 20-30
  lines of throttling. The same agent producing Nextflow doesn't.
- 4.4.3 (was 'agent on its own would have hit the same wall'): the
  same agent producing this Nextflow process gets parallelisation for
  free; producing bash, it has to write throttling itself and won't.
- Section 5 reframed: 'why this matters more, not less, when AI is
  writing the code'. The case for the workflow tool gets stronger
  with more AI authoring, because the agent's mistakes have somewhere
  safe to land.
- Summary: the pipeline is the durable artefact; the agent writes
  either form; the form that makes the agent's output trustworthy is
  the one with a workflow boundary baked in.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ion'

The previous framing implied 'agent writes bash, you write Nextflow'
or 'agent's bash is worse than agent's Nextflow'. Both miss the
deeper point: the agent will write either form on demand, and the
question is which artefact is worth keeping after the conversation
ends.

Structural changes:
- New section 2, 'The artefact those properties live in', explicitly
  introduces the artefact as a thing that lives in version control,
  gets vetted at code review, tested, updated when tools change,
  read by colleagues. Without this concept named before Part 1, the
  takeaways throughout don't have a referent.
- Sections 2-5 renumbered to 3-6 to make room.
- Section 6 (was 5) reshaped as the closing argument that walks
  through the four eras (commands -> scripts -> workflows -> AI
  authoring), ending on 'the artefact has to outlive the
  conversation'.
- Opening anchor rewrites to lead with the four-era arc and the
  artefact framing, replacing the previous 'durable artefact'
  paragraph.
- Summary punchline replaces 'Claude needs them too' (cute but
  oblique) with 'the artefact has to outlive the conversation that
  made it' (concrete, vendor-neutral, ages well).

Vendor neutrality:
- Removed the 'Claude' punchline.
- Removed inline links to 'nf-core Claude Code skills' (specific
  product naming).
- Kept Seqera AI in Additional resources as a useful pointer per
  user request, but vendor-neutralised the surrounding language.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous intro (~330 words) was an outlier against the rest of
the side-quests intro range (median ~50-180 words). Worse, it
litigated the script-vs-workflow thesis in paragraph 4 before the
reader had any reason to care, duplicating what section 2 ('The
artefact those properties live in') already does properly.

Cut paragraph 4 entirely. Trim the laundry-list tail of paragraph 3.
Result: 4 short paragraphs that pose the question, sketch the four
eras, and signal the worked-example arc. The thesis lives in
section 2 where it has room to breathe.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously the AI angle was load-bearing in the intro, section 3,
and Summary, but in Parts 1 and 2 it was decorative phrases tacked
onto timeless explanations ('the agent didn't pin versions',
'whether you wrote it or asked an agent to'). The lesson read as
the timeless script-vs-workflow story with AI sprinkles.

Reframed Parts 1 and 2's premises so the AI thread is the framing,
not the commentary:

- Section 1 intro: 'this is the kind of script an agent would
  produce from a paragraph of intent: it works on three samples on
  the laptop where it ran. Each property is something the author,
  agent or human, has to remember to write into the script.'
- Section 2 intro: 'the same paragraph of intent, given to the same
  agent, would produce something close to what you write here. The
  difference is not authorship or speed; it is the artefact's shape.'
- 'Contrast with the agent's script' admonitions retitled to
  'Contrast with the script form'. Bodies rewritten to contrast
  the artefact forms (where the script put X on the author, the
  workflow puts X in the structure), not the authors.
- Section 1.8 takeaway closes with an artefact-form judgement: each
  warning is more bash someone writes and a maintainer reads; the
  form is the problem, not who wrote it.
- Section 2.8 takeaway closes mirroring: every property is supplied
  by the workflow boundary itself, not by the author; a maintainer
  can see at a glance what ran where; the form did the work the
  script left to the author.
- Section 3 tightened to two paragraphs. The four-era recap moved
  out (the intro already names them); the bottleneck shift and the
  'case gets stronger with AI' argument stay, plus the punchline.

Page is now 1137 lines (was 1142) but reads more cohesively: the
AI angle frames each part rather than decorating it.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three real fixes from the review pass:

1. Section 2.5 prescribed MULTIQC code that the solution didn't
   contain. Added side-quests/solutions/workflows_in_the_ai_era/
   nextflow/modules/multiqc.nf and wired it into main.nf with the
   .map/.mix/.collect pattern, plus multiqc_report in publish: and
   output {}. Solution now produces results/multiqc/multiqc_report
   .html on a successful run.

2. fastqc.nf and fastp.nf in the solution had cpus/memory directives
   and ${task.cpus} threading, but the doc walks the learner through
   building these modules without resource directives (the
   ${task.cpus} pattern is introduced for SALMON_QUANT in section
   2.4, deliberately). Stripped cpus/memory from fastqc.nf and
   fastp.nf in the solution; threads stay hardcoded at 2 and 4
   respectively to match what the doc shows. Pedagogical beat
   preserved.

3. Fixed multiqc.nf output mismatch: process declared
   path "multiqc_data" but the script ran with --filename
   multiqc_report, which makes MultiQC produce multiqc_report_data
   instead. Dropped --filename so MultiQC uses default names that
   match the declared outputs (multiqc_report.html, multiqc_data).

Plus the hl_lines nit:
- fastp.nf 'After' tab had hl_lines="6 9-11 15-21" but missed line
  22 (--thread 4). Now hl_lines="6 9-11 15-22".

Plus a lint cleanup on three .map { id, files -> files } closures
in main.nf where id was unused; renamed to _id to suppress the
'parameter not used' warning. Mirrored in the markdown.

Plus the duplicated thesis: dropped the standalone 'The artefact
has to outlive the conversation that made it' line from the Summary
since the line above already lands the same point.

Verified end-to-end on Apple Silicon (Docker / linux/amd64
emulation): all 11 tasks complete via -resume, multiqc_report.html
lands at results/multiqc/. Solution lints clean (0 errors, 0
warnings). check_headings.py clean.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fix items:
- Block 12 hl_lines: '1 3-9 12-18' -> '1 4-9 13-18'. The original
  highlighted 'publish:' (line 3) and 'output {' (line 12) which
  already exist in the Before as structural placeholders, contrary
  to CLAUDE.md's 'don't highlight structural keywords' rule. Now
  highlights only the genuinely new lines (channel assignments and
  path entries).
- Side-quest table description: 22-word phrase that wraps badly on
  narrow screens replaced with 'When to use a workflow tool in an
  AI-driven world' (~10 words).

Plus my own check-highlights pass found two consistency issues that
the earlier manual check missed:
- Block 2 (FastQC) hl_lines: '3-5' -> '2-5' to include the echo
  line, matching block 1 (download) and block 5 (salmon quant).
- Block 3 (fastp) hl_lines: '3-10' -> '2-10' for the same reason.

Polish items:
- Added a 'Why main:?' admonition after the publish/output wire-up
  in 2.4.2, explaining when the main: label is required.
- Reframed section 2.5 (MultiQC) so it reads as 'walking through
  code that's already been written for you' rather than asking the
  learner to add it; matches the section's actual structure.
- Added an inline comment + a parenthetical explaining the _id
  underscore convention at first use in the MULTIQC wiring.
- Section 3 title 'Why workflows still matter when AI does the
  writing' -> 'Workflows when AI writes the code'. Matches the
  noun-phrase pattern of other section titles.

Minor items:
- Resume output block in 2.6: added a MULTIQC line with the
  '<- And anything downstream' annotation, since modifying the
  pipeline would re-run MULTIQC too. Was previously misleading.
- Closed the '50 samples next week' narrative loop in the Part 2
  takeaway: 'That 50-sample run next week your PI mentioned in
  section 1.1.1? Same nextflow run command, no changes to main.nf,
  swap -profile docker for -profile slurm if you want it on the
  cluster.'

Reviewer's note that I claimed to use /check-highlights earlier
when I'd only manually counted lines was correct. This pass invokes
the skill properly.

[skip ci]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants