Skip to content

Add run-tutorial and docker-setup Claude skills#768

Merged
pinin4fjords merged 18 commits intomasterfrom
add-run-tutorial-skill
Jan 13, 2026
Merged

Add run-tutorial and docker-setup Claude skills#768
pinin4fjords merged 18 commits intomasterfrom
add-run-tutorial-skill

Conversation

@pinin4fjords
Copy link
Collaborator

@pinin4fjords pinin4fjords commented Jan 12, 2026

Summary

  • Adds new Claude Code skill (/run-tutorial) for testing training tutorials end-to-end
  • Adds new Claude Code skill (/docker-setup) for Docker container environment setup
  • Simulates a learner's experience by progressively building code and running commands
  • Verifies "Before" state matches documentation before applying changes
  • Compares final results against solution files
  • Proposes fixes for any issues found and offers to create a PR (with user approval)

New Skills

/run-tutorial

Walks through a training tutorial as a learner would:

  1. Reads documentation and identifies code changes/commands
  2. Verifies current file state matches "Before" blocks
  3. Applies changes progressively (not copying final solution)
  4. Runs commands exactly as documented
  5. Compares output with documented expectations
  6. Validates final code matches solution files
  7. If issues found: presents proposed fixes and asks user for approval before creating PR

References existing skills (/validate, /test-example, /docker-setup) to avoid duplication.

/docker-setup

Sets up Docker container environment for running Nextflow training examples:

  • Basic setup - For tutorials without containerized processes
  • DooD setup - Docker-outside-of-Docker for tutorials with containerized processes (FASTP, BWA, etc.)
  • ARM Mac support - Platform emulation configuration
  • Troubleshooting - Common errors and solutions table
  • Container restart - Recovery procedure for long sessions

Skill Quality Improvements

Both skills follow Claude Code best practices:

  • Explicit AskUserQuestion tool usage for gathering user input
  • Clear Skill tool invocation syntax for referencing other skills
  • TodoWrite recommendation for tracking progress through complex workflows
  • Proper placeholder handling (${PWD}, ${WORKING_DIR} instead of [path])
  • Model-agnostic co-author line

Test plan

  • Tested by running through the plugin development tutorial
  • Verified skill correctly identifies state mismatches
  • Verified cleanup works after successful walkthrough
  • Tested PR creation flow with nf-test tutorial (created PR Fix formatting issues in nf-test side quest #769)
  • Tested DooD setup with essential_scripting_patterns side quest
  • All CI checks passing

🤖 Generated with Claude Code

New skill that simulates a learner's experience by:
- Progressively building code section by section
- Running commands exactly as documented
- Verifying "Before" state matches before applying changes
- Comparing final results against solution files
- Cleaning up working directories after successful runs

Uses Docker container with dynamically-determined NXF_VER
from devcontainer.json to match the learner environment.
References existing skills for specialized checks.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@netlify
Copy link

netlify bot commented Jan 12, 2026

Deploy Preview for nextflow-training ready!

Name Link
🔨 Latest commit 4f3104a
🔍 Latest deploy log https://app.netlify.com/projects/nextflow-training/deploys/69650c36b59619000811f9fd
😎 Deploy Preview https://deploy-preview-768--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.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 12, 2026

Nextflow linting complete!

❌ 4 files had 21 errors
✅ 165 files had no errors
🔧 149 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/workflows_of_workflows/main.nf(truncated)
side-quests/solutions/working_with_files/1/main.nf(truncated)
side-quests/solutions/working_with_files/1/modules/count_lines.nf(truncated)
side-...*[Comment body truncated]*

pinin4fjords and others added 17 commits January 12, 2026 10:24
Instead of just recommending follow-up skills, the walkthrough now:
- Invokes /validate in Phase 1 to check highlights, structure, pedagogy
- Invokes /test-example in Phase 3 on solution files
- Reports results from both skills in the output summary

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Discovered during workflow_outputs tutorial walkthrough:

- Add UTF-8 locale settings (LANG=C.UTF-8, LC_ALL=C.UTF-8) to Docker
  commands to handle non-ASCII characters like "Holà" - without these,
  Nextflow fails with "Malformed input or unmappable characters" error
- Clean up existing container before starting to avoid conflicts
- Improve output format to report actual results from /validate skill
  (heading count, hl_lines blocks checked, TODO counts, etc.)
- Improve output format to report actual results from /test-example skill
  (process counts, resume verification, output checks)
- Organize issues by severity (Critical/Warning/Minor)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Skill files are internal instructions for Claude, not student-facing
training materials. They don't need to follow the same heading
numbering conventions as lesson content.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When issues are found during tutorial walkthrough:
- Categorize issues as auto-fixable vs requiring manual review
- Present proposed fixes to user in a clear table format
- Ask user for approval before making any changes
- Allow user to review/modify fixes one at a time
- Create PR only after user approval

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Document DooD setup for tutorials with containerized processes
- Explain path matching requirement for sibling containers
- Add Apple Silicon platform emulation instructions
- Include troubleshooting table for common DooD errors

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CRITICAL note at start of Phase 2 about completing all steps per section
- Add new step 2.6 "Confirm Section Complete Before Proceeding"
- Expand Notes section with explicit "ONE SECTION AT A TIME" and "Test after EVERY change"
- Add guidance to test even when tutorial doesn't explicitly say to run

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add task 6 to validate skill to invoke /check-highlights for comprehensive hl_lines validation
- Simplify run-tutorial skill to consolidate validate references since validate now handles highlights

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Document symlink workaround for Codespaces paths when testing locally
- Add container stability issues section with recovery procedure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When reporting issues or creating PRs, always read the actual section
headings from the document rather than guessing section numbers.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add blank line after "**Symptoms**:" for proper markdown list formatting
- Fix table column alignment in PR body template
- Apply prettier formatting to list items

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix pre-commit markdown formatting for proper list rendering.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
## Changes

- Extract Docker container setup into new `/docker-setup` skill
  - Basic setup for tutorials without containerized processes
  - DooD (Docker-outside-of-Docker) for containerized processes
  - ARM Mac platform emulation support
  - Troubleshooting table and container restart procedure

- Improve run-tutorial skill:
  - Reference docker-setup skill instead of inline Docker instructions
  - Add explicit AskUserQuestion tool usage for initial questions
  - Clarify skill invocation using Skill tool
  - Add TodoWrite recommendation for tracking progress
  - Fix placeholder values in commands (use ${PWD}, ${WORKING_DIR})
  - Simplify environment options to Docker or Existing
  - Fix co-author line (model-agnostic)
  - Reduce file size from 600 to ~400 lines

Co-Authored-By: Claude <noreply@anthropic.com>
@pinin4fjords pinin4fjords changed the title Add run-tutorial Claude skill for walkthrough testing Add run-tutorial and docker-setup Claude skills Jan 12, 2026
@vdauwera vdauwera self-requested a review January 13, 2026 15:49
Copy link
Collaborator

@vdauwera vdauwera left a comment

Choose a reason for hiding this comment

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

LGTM!

@pinin4fjords pinin4fjords merged commit 17212ea into master Jan 13, 2026
9 checks passed
@pinin4fjords pinin4fjords deleted the add-run-tutorial-skill branch January 13, 2026 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants