Skip to content
GitHub
View on GitHub

Tutorials

Runnable Modal training examples across intro, RL, SFT, and infrastructure-focused walkthroughs.

Every tutorial below has a one-click Launch in Modal Notebook button. The button opens the .ipynb in a fresh Modal Notebook — the first code cell is a ! pip install git+https://github.com/modal-projects/training-gym.git@joy/initial-setup that installs modal-training-gym into the notebook kernel, so the rest of the cells run as-is.

The Difficulty column is a rough self-assessed signal for where to start: Beginner tutorials are single-node and introduce one framework concept; Intermediate tutorials span 1–2 nodes or wire up something non-default (custom reward, external script); Advanced tutorials run on ≥2 nodes with non-trivial parallelism (tensor-parallel, colocated RL, long context) and assume familiarity with the underlying framework.

TutorialSummaryDifficultyFrameworkClusterLaunch
quickstartShared concepts: config containers, framework factories, volume layout, running the pipelineBeginner— (concepts)Open in Modal
TutorialSummaryDifficultyFrameworkClusterLaunch
slime_gsm8kQwen3-4B GRPO on GSM8K (colocated)Advancedslime4 × 8×H100Open in Modal
slime_haikuQwen3-4B GRPO on haiku poems — structure score + LLM judgeIntermediateslime1 × 8×H100Open in Modal
harbor_code_golfQwen3-4B RL code-golf on MBPP with Harbor sandboxesAdvancedharbor2 × 8×H100Open in Modal
TutorialSummaryDifficultyFrameworkClusterLaunch
ms_swift_glm_4_7_gsm8kGLM-4.7 LoRA SFT on GSM8K (Megatron)Advancedms_swift4 × 8×H100Open in Modal
ms_swift_custom_hfCustom HuggingFace model (SmolLM2-135M) LoRA SFT — inline ModelConfiguration subclass, no catalog entryBeginnerms_swift1 × 1×H100Open in Modal
TutorialSummaryDifficultyFrameworkClusterLaunch
ray_slime_standaloneRay-on-Modal pattern demoIntermediate— (raw ModalRayCluster)2 × 8×H100Open in Modal

Every tutorial is also a plain .py file runnable via modal run. See the top-level README.md for the usage pattern.

Tutorials are generated from a Python source file under tutorial_generator/. The generator AST-walks each source and emits tutorials/<bucket>/<name>/<name>.py + tutorials/<bucket>/<name>/<name>.ipynb. Edit the source, not the generated files — the pre-commit hook (.pre-commit-config.yaml) regenerates on commit, so hand-edits to the .py / .ipynb will be overwritten.

Regenerate manually after editing a source file:

Terminal window
uv run python tutorials/generate_tutorial.py

Top-level functions in the source file produce cells; function names and argument lists don’t matter, only decorator + body. Cells appear in source order.

  • @markdown — the function’s docstring becomes one markdown cell (.ipynb) or # comments (.py).
  • @code — the function’s body (dedented) becomes one code cell.
  • @shell("…") — the string argument is emitted verbatim as a code cell (supports ! pip install … shell magic for notebook installs).
  • @py_only / @notebook_only — restrict a cell to one output format; stacks on top of @markdown / @code / @shell.

Every source file declares a module-level TUTORIAL_METADATA dict that drives the catalog table above. Fields:

KeyRequiredPurpose
frameworkyesBacktick-wrapped framework name (e.g., '`slime`') or '— (…)' for standalone tutorials
cluster_shapeyesHuman-readable shape ('4 × 8×H200') — must match what the config actually launches
summaryyesOne-line description of what the tutorial trains
difficultyrecommendedOne of 'Beginner', 'Intermediate', 'Advanced'. Falls back to if omitted. See the column description at the top of this page for what each tier means.
orderyesInteger controlling row order in the catalog; lower appears earlier

Treat the notebook as the tutorial’s home — the root README and this index are maps, the .ipynb is the walkthrough. Aim for roughly:

  • An intro cell naming what it trains, why someone would run it, and where to watch progress (W&B project/group, Modal dashboard).
  • A markdown cell before each @code block that names the non-obvious choices (why these hyperparams, why this cluster shape, why this chat template). Don’t repeat what the code itself makes obvious.
  • Custom pieces (reward functions, dataset preprocessing, model wrappers) get their own explanation cell.
  • A “Run it” section splitting CLI invocation (@py_only) from cell-by-cell interactive invocation (@notebook_only).
  • Optional: a “Serve / evaluate / next step” tail, where relevant — see slime_haiku for the shape.

slime_gsm8k and slime_haiku are the reference examples for tutorial narration depth.