# ML-For-Beginners — Admin & Contributor Guide

Operational reference for **teachers, curriculum maintainers, translation reviewers, and contributors** of the Microsoft *Machine Learning for Beginners* curriculum. If you are a student looking for how to run the lessons, read the User Guide instead — this document covers what the learner-facing guide deliberately skips: architecture, authoring contracts, the multi-language translation pipeline, classroom delivery patterns, and the Microsoft contribution workflow.

---

## 1. Executive Summary

ML-For-Beginners is a **12-week, 26-lesson curriculum repository** published by Microsoft's cloud-advocacy team. It is not a runtime system. It is an *authoring* and *delivery* artifact that ships four distinct kinds of content in one repository:

| Artifact | Technology | Purpose |
|---|---|---|
| Lesson content | Markdown + Jupyter notebooks (Python) + R notebooks | Core curriculum: 26 lessons across 7 topic areas |
| Quiz front-end | Vue 3 + vue-router + vue-i18n (Vue CLI 5) in `quiz-app/` | Pre/post-lecture quizzes with i18n |
| Demo web app | Flask + scikit-learn + `ufo-model.pkl` in `3-Web-App/` | Lesson 9 teaches how to wrap a trained model in Flask |
| Documentation site | Docsify (zero-build) via root `index.html` | Renders the curriculum as a browsable site |

Everything else in the repo exists to support these four artifacts: translations of every Markdown file into 50+ languages (generated by the [Co-op Translator](https://github.com/Azure/co-op-translator) GitHub Action), mirrored image assets in `translated_images/`, GitHub issue/PR templates, a dev container, and housekeeping workflows (stale-issue closure, SLSA provenance on releases, closed-issue locking).

**What this means operationally:**

1. **No production runtime to operate.** There are no servers to patch, no databases to back up, no queues to drain. "Operating" the project is authoring content and reviewing pull requests.
2. **The translation pipeline is the most complex subsystem.** It runs as a GitHub Action and is the single largest source of repository churn — most of the 17,000+ tracked files are translation artifacts.
3. **Sub-projects (Flask, Vue) are illustrative, not production.** They are pinned to older, lesson-compatible versions and are not security-hardened. Do not use them as templates for production apps.
4. **Authorship contracts matter more than code quality.** Because the project is pedagogical, the authoring conventions (lesson sections, quiz wiring, sketchnote placement) carry more weight than typical software engineering concerns like test coverage.

This guide is organized around those realities.

> [!NOTE]
> This documentation is generated from the repository at commit `000d5941`. Version numbers, file paths, and configuration values refer to that exact snapshot. Behavior in newer commits may differ.

---

## 2. Architecture

The repository has **four loosely coupled content systems** that share a common top-level layout. There is no service mesh, no inter-process communication, no shared database — each system is a static or self-contained asset. The diagram below shows how they relate.

```
                    ┌──────────────────────────────────────────┐
                    │            Source of truth               │
                    │   English Markdown + notebooks in repo   │
                    └────────────────────┬─────────────────────┘
                                         │
      ┌──────────────────┬───────────────┼──────────────────────┬───────────────┐
      │                  │               │                      │               │
      ▼                  ▼               ▼                      ▼               ▼
┌───────────┐   ┌────────────────┐  ┌──────────┐       ┌────────────────┐  ┌─────────┐
│  Docsify  │   │ Co-op Trans-   │  │ docsify- │       │  Lesson quizzes│  │   PDF   │
│  static   │   │ lator GitHub   │  │ to-pdf   │       │  rendered by   │  │  output │
│  site     │   │ Action         │  │ (Pup-    │       │  Vue quiz-app  │  │ pdf/    │
│           │   │                │  │  peteer) │       │                │  │         │
└───────────┘   └───────┬────────┘  └────┬─────┘       └────────┬───────┘  └─────────┘
                        │                │                      │
                        ▼                ▼                      ▼
                translations/      pdf/readme.pdf        ff-quizzes.netlify.app
                translated_images/                       (external quiz host)
                                                         + local quiz-app build
```

### 2.1 Docsify documentation site (root)

The root `index.html` is a 27-line Docsify bootstrap that turns the repo into a static documentation site **without a build step**. Docsify fetches `README.md` and any linked Markdown on demand from the hosting server. Configuration:

```javascript
window.$docsify = {
  name: 'Machine Learning for Beginners',
  repo: 'https://github.com/Microsoft/ML-For-Beginners',
  relativePath: true,
  auto2top: true,
}
```

Theming is pulled from the CDN (`docsify-themeable@0/dist/css/theme-simple.css`). The `.nojekyll` file prevents GitHub Pages from rewriting underscore-prefixed paths. A sidebar at `docs/_sidebar.md` provides the navigation tree.

**Why this matters:** every Markdown file in the repo is potentially linkable from the site. When authoring, assume that any relative link in a lesson README will resolve correctly via Docsify's `relativePath: true` mode.

### 2.2 Translation pipeline

Translations live under `translations/{lang-code}/...` mirroring the English tree, and translated images live under `translated_images/`. Both are **generated artifacts** produced by the Co-op Translator GitHub Action (see §6). They are committed to the repo rather than built on demand because Docsify has no build step and the site must serve pre-translated files.

Supported languages at this snapshot include: `ar, bg, bn, cs, da, de, el, en, es, fa, fi, fr, he, hi, hk, hr, hu, id, it, ja, ko, lt, mo, mr, ms, nl, ne, no, pa, pl, pt, ro, ru, sk, sl, sr, sv, sw, ta, te, th, tl, tr, tw, uk, ur, vi, zh-CN, zh-TW`, among others.

### 2.3 Quiz system

Quizzes are authored as data in Vue components under `quiz-app/src/` and consumed in two places:

1. **Inline in the lesson README** — each lesson links to the pre- and post-lecture quiz on the **external host** `https://ff-quizzes.netlify.app/en/ml/`. This is the path students actually use.
2. **Locally via the quiz-app** — teachers or offline classrooms can run `npm run serve` in `quiz-app/` to host the same quizzes on localhost, or deploy them to Azure Static Web Apps (see §11.3).

The quiz-app is a Vue 3 SPA with vue-router for lesson navigation and vue-i18n for in-app translation. It is **version-pinned to Vue CLI 5** (`@vue/cli-service ~5.0.8`) and Vue 3.5.12.

### 2.4 Demo Flask web app (Lesson 9)

`3-Web-App/1-Web-App/solution/web-app/app.py` is a 20-line Flask application that loads a pickled scikit-learn model and predicts "likely country of a UFO sighting" from form input:

```python
from flask import Flask, request, render_template
import pickle, numpy as np
app = Flask(__name__)
model = pickle.load(open("../ufo-model.pkl", "rb"))
@app.route("/predict", methods=["POST"])
def predict():
    int_features = [int(x) for x in request.form.values()]
    final_features = [np.array(int_features)]
    prediction = model.predict(final_features)
    countries = ["Australia", "Canada", "Germany", "UK", "US"]
    return render_template("index.html",
        prediction_text="Likely country: {}".format(countries[output]))
```

`requirements.txt`: `scikit-learn`, `pandas`, `numpy`, `flask`. This is a teaching artifact — see §10 for the security properties you must explicitly call out when students use it as a template.

### 2.5 PDF generation

`docsifytopdf.js` configures `docsify-to-pdf` (a Puppeteer wrapper) to crawl `docs/_sidebar.md` and emit `pdf/readme.pdf`. The top-level `package.json` exposes this as `npm run convert`. Output is checked into the repo under `pdf/`.

```javascript
module.exports = {
  contents: ['docs/_sidebar.md'],
  pathToPublic: 'pdf/readme.pdf',
  pdfOptions: { margin: { top: '100px', bottom: '100px' } },
  removeTemp: true,
  emulateMedia: 'print',
};
```

---

## 3. Repository Layout

```
ML-For-Beginners/
├── 1-Introduction/          Lessons 1–4: ML intro, history, fairness, tools
├── 2-Regression/            Lessons 1–4: regression, Scikit-learn pipeline
├── 3-Web-App/               Lesson 1: Flask web app wrapping a trained model
├── 4-Classification/        Lessons 1–4: classification, cuisine dataset
├── 5-Clustering/            Lessons 1–2: K-Means, Nigerian music dataset
├── 6-NLP/                   Lessons 1–5: NLP tasks, translation, sentiment
├── 7-TimeSeries/            Lessons 1–3: time series, ARIMA, SVR
├── 8-Reinforcement/         Lessons 1–2: Q-learning, Gym environment
├── 9-Real-World/            Post-script: ML in production
├── docs/
│   └── _sidebar.md          Docsify navigation, also the TOC for PDF export
├── quiz-app/                Vue 3 pre/post-lecture quiz SPA
│   ├── src/
│   │   ├── App.vue, main.js
│   │   ├── router/          vue-router config
│   │   ├── views/           Lesson quiz views
│   │   ├── components/      Shared UI
│   │   └── assets/          Translation JSON files
│   ├── public/
│   ├── package.json         Vue CLI 5 + Vue 3.5.12
│   └── README.md            Quiz-app build/deploy docs
├── translations/            {lang-code}/ mirror of English content (generated)
├── translated_images/       Translated image assets (generated)
├── sketchnotes/             Lesson cover sketchnotes (Nitya Narasimhan)
├── images/                  Shared imagery, favicon
├── .devcontainer/           VS Code dev container (Python 3.10-bullseye)
├── .github/
│   ├── workflows/           stale.yml, lock.yml, SLSA publish
│   ├── ISSUE_TEMPLATE/
│   ├── PULL_REQUEST_TEMPLATE/
│   └── chatmodes/           Copilot chat modes for curriculum authoring
├── README.md                Master curriculum table, sparse-checkout recipe
├── AGENTS.md                Pre-structured project overview (for AI agents)
├── TROUBLESHOOTING.md       Lesson-by-lesson error recipes
├── for-teachers.md          GitHub Classroom integration notes
├── CONTRIBUTING.md          Microsoft CLA + community translation note
├── SECURITY.md              MSRC reporting boilerplate
├── SUPPORT.md               Issue + Discord channels
├── CODE_OF_CONDUCT.md       Microsoft Open Source CoC pointer
├── LICENSE                  MIT
├── package.json             Root: docsify-to-pdf devDependency
├── docsifytopdf.js          PDF export config
├── index.html               Docsify bootstrap
├── .nojekyll                Disable Jekyll processing on GitHub Pages
├── pdf/                     Checked-in PDF exports
├── PyTorch_Fundamentals.ipynb  Supplementary PyTorch notebook (~73 KB)
└── .gitignore
```

Inside each lesson directory the layout is:

```
{N}-Topic/{lesson-number}-{lesson-name}/
├── README.md                Lesson body (English source of truth)
├── notebook.ipynb           Python Jupyter (when applicable)
├── solution/                Reference implementation
│   ├── notebook.ipynb
│   └── R/                   Tidymodels equivalent (when applicable)
├── assignment.md            End-of-lesson exercise
├── images/                  Lesson-local figures
└── translations/            {lang-code}/ per-lesson mirror (generated)
```

---

## 4. System Requirements

### 4.1 Authoring machine

| Component | Version | Notes |
|---|---|---|
| Git | 2.25+ | Required for `sparse-checkout` filter |
| Python | 3.9–3.11 | Lessons and solution notebooks; 3.10 matches the devcontainer |
| Jupyter / JupyterLab | any recent | Install via `pip install notebook` or `conda install jupyter` |
| Node.js | 18 LTS or 20 LTS | Required for quiz-app and `docsify-to-pdf` |
| npm | bundled with Node | `npm install` from repo root pulls `docsify-to-pdf` |
| R | 4.1+ | Only for R-track lessons; see `solution/R/` |
| RStudio | 2022.02+ | Recommended when editing `.Rmd` files |

### 4.2 Curriculum Python dependencies

There is no top-level `requirements.txt`. Each lesson that runs code either imports from the standard scientific-Python stack (scikit-learn, pandas, numpy, matplotlib, seaborn) or declares its own deps inline. The demo Flask app is the only place where a pinned list lives:

```
# 3-Web-App/1-Web-App/solution/web-app/requirements.txt
scikit-learn
pandas
numpy
flask
```

For the full curriculum we recommend creating a conda environment with:

```bash
conda create -n ml4beginners python=3.10
conda activate ml4beginners
conda install -c conda-forge jupyter scikit-learn pandas numpy matplotlib seaborn
pip install flask
```

### 4.3 Optional: dev container

The repo ships a VS Code dev container at `.devcontainer/`:

- Base image: `mcr.microsoft.com/vscode/devcontainers/python:0-3.10-bullseye`
- Pylance + Python linting (pylint) preconfigured
- Node version: `"none"` — students wanting to run the quiz-app or `docsify-to-pdf` must edit `devcontainer.json` to set `NODE_VERSION` to `lts/*` or rebuild with `--build-arg NODE_VERSION=18`.

Open the repo in VS Code → *Reopen in Container* and everything Python-side works out of the box.

### 4.4 GitHub/org requirements for deployment

- **Docsify site hosting** — GitHub Pages (free) or any static host. The site needs only `index.html`, `README.md`, and the Markdown tree.
- **Quiz-app deployment** — see §11.3. Requires an Azure subscription and the Static Web Apps service, or any static host.
- **Co-op Translator** — the Action requires repository secrets for the translation provider; see §6.3.

---

## 5. Lesson Authoring Contract

The single most important constraint when editing or adding content: **lessons follow a 10-section structure**. Deviations break the Docsify sidebar, the quiz wiring, and the expectations set in the root README.

### 5.1 Lesson Markdown template

```markdown
# Lesson Title

![sketchnote](../../sketchnotes/{lesson}.jpg)
> Sketchnote by [Tomomi Imura](https://twitter.com/girlie_mac)

## [Pre-lecture quiz](https://ff-quizzes.netlify.app/en/ml/)

### Introduction
Two to four paragraphs framing why the learner should care and
what they will be able to do after.

### What you'll learn
- Bulleted skills list
- Written in outcome language ("You will be able to …")

### Prerequisites
- References to earlier lessons
- Required libraries installed

## {Main body — H2-level sections specific to the topic}
### H3 subsections with code blocks, images, and exercises

## 🚀Challenge
A stretch exercise that goes beyond the lesson.

## [Post-lecture quiz](https://ff-quizzes.netlify.app/en/ml/)

## Review & Self Study
Three to five external links for deeper reading.

## Assignment
[Assignment Title](assignment.md)
```

### 5.2 Quiz linking rules

- Pre-lecture quiz link is always immediately after the sketchnote H1 title and before the Introduction.
- Post-lecture quiz link is immediately after the main body, before "Review & Self Study".
- Both links point at the **external host** `https://ff-quizzes.netlify.app/en/ml/`. The quiz-id is resolved from the URL path configured inside the quiz-app. Do **not** link to localhost or a relative path — translated lessons rely on the external host being resolvable.

### 5.3 Images and sketchnotes

- Lesson-local images live in `{lesson}/images/` and are referenced relatively: `![caption](images/foo.png)`.
- Cover sketchnotes live in `sketchnotes/` at the repo root and are referenced as `../../sketchnotes/{name}.jpg`.
- All images are candidates for translation. The Co-op Translator walks the tree, extracts text, and writes translated copies under `translated_images/{lang}/`. Do **not** hand-edit anything in `translated_images/` — it is regenerated.

### 5.4 Code blocks

- Fenced with a language tag: ` ```python `, ` ```r `, ` ```bash `, ` ```javascript `.
- No language tag = no syntax highlighting in Docsify and no translation exemption. Always tag code blocks so Co-op Translator leaves them alone.
- Shell commands prefer POSIX form; call out Windows differences with a blockquote: `> On Windows, use \` instead of /.`

### 5.5 Notebooks

- Notebooks are the actual teaching artifact for any lesson that runs code. The Markdown README explains the *why*; the notebook delivers the *how*.
- Use `solution/notebook.ipynb` for the reference implementation and keep the lesson-level `notebook.ipynb` as a scaffolded "fill in the blanks" version for students.
- For R-track lessons, mirror under `solution/R/` using tidymodels.

### 5.6 Assignment files

Each lesson's end-of-lesson exercise is a standalone `assignment.md` with this template:

```markdown
# Assignment Title

## Instructions
What the student must do.

## Rubric
| Exemplary | Adequate | Needs Improvement |
|-----------|----------|-------------------|
|  …        |  …       |  …                |
```

The rubric table is expected by graders; omitting it breaks the grading workflow documented in `for-teachers.md`.

### 5.7 README master table

`README.md` at the repo root carries the canonical 26-lesson inventory as a Markdown table. When adding or renumbering a lesson, update this table as the same commit — the sidebar, the quiz IDs in `quiz-app/`, and the translation outputs all key off lesson ordering.

---

## 6. Translation Subsystem

### 6.1 What Co-op Translator does

[Co-op Translator](https://github.com/Azure/co-op-translator) is an Azure-published GitHub Action that:

1. Walks the repository for English Markdown, notebooks, and images.
2. Sends text to an LLM translator (typically Azure OpenAI).
3. Writes translated Markdown/notebooks under `translations/{lang-code}/`.
4. Renders translated images (preserving layout) under `translated_images/{lang-code}/`.
5. Commits the results back to the repo via a workflow-authored commit.

This is why most of the ~17,000 tracked files are translation artifacts — a single lesson plus its image set expands across 50 language codes.

### 6.2 Languages supported

The language list is driven by a Co-op Translator config (typically `co-op-translator-config.yaml` or similar). To change the language set, edit that config, not the committed translation trees. The set visible in this snapshot includes Western European, Slavic, East Asian, Middle Eastern, South Asian, and Southeast Asian language groups — a full inventory is in `translations/`.

### 6.3 Required secrets and permissions

For the Action to run in your fork you need:

- Azure OpenAI endpoint and API key (repository secrets)
- `contents: write` permission on the workflow (to commit translated files)
- `pull-requests: write` if you configure the Action to open PRs instead of pushing directly

Consult the Co-op Translator README for the exact secret names at the commit you are using.

### 6.4 Community translation override

Machine translations can be overridden by **human volunteers**. `CONTRIBUTING.md` is explicit:

> Important: when translating text in this repo, please ensure that you do not use machine translation. We will verify translations via the community, so please only volunteer for translations in languages where you are proficient.

This means human-translated content should land as direct edits inside `translations/{lang}/` and must be protected from being overwritten on the next Action run. The review policy is: a human translation, once merged, is treated as ground truth for that language; re-runs of Co-op Translator must either skip files marked as human-reviewed or be constrained to new content only. If you operate the Action, audit its config for this behavior before scheduling large re-runs.

### 6.5 Review responsibilities for maintainers

| Task | Owner | Cadence |
|---|---|---|
| Triage translation PRs from volunteers | Curriculum maintainer | Per PR |
| Audit Co-op Translator output on new lessons | Curriculum maintainer | Per new lesson merge |
| Add/remove supported languages | Lead maintainer | Ad hoc |
| Investigate garbled translation reports | Translation reviewer for that language | Per issue |

---

## 7. Sub-Project: Flask Web App (`3-Web-App/`)

### 7.1 Purpose

Teaches students how to serialize a trained scikit-learn model with `pickle` and serve predictions through a minimal Flask route. It is **intentionally minimal** — the lesson goal is "a trained model is just a file; Flask is just a function router" — not production deployment.

### 7.2 Layout

```
3-Web-App/
└── 1-Web-App/
    ├── notebook.ipynb           Lesson notebook: train + pickle ufo-model.pkl
    ├── README.md                Lesson walkthrough
    ├── assignment.md            End-of-lesson challenge
    └── solution/
        ├── ufo-model.pkl        Pre-trained classifier (checked in)
        └── web-app/
            ├── app.py           Flask application (full source in §2.4)
            ├── requirements.txt scikit-learn, pandas, numpy, flask
            ├── static/
            │   └── css/styles.css
            └── templates/
                └── index.html   Single-page form + prediction display
```

### 7.3 Running locally

```bash
cd 3-Web-App/1-Web-App/solution/web-app
python -m venv .venv && source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -r requirements.txt
python app.py
# Flask dev server on http://127.0.0.1:5000 with debug=True
```

### 7.4 Security properties (important to call out when teaching)

| Property | State | Reason | What students must know before reuse |
|---|---|---|---|
| `pickle.load` on a model file | Used | Teaches the canonical scikit-learn persist pattern | `pickle` executes arbitrary code on load; never load a `.pkl` from an untrusted source |
| `debug=True` in `app.run()` | Used | Shows tracebacks in the browser when students break things | Never set in production — the Werkzeug debugger is an RCE if exposed |
| Input validation | Absent | `int_features = [int(x) for x in request.form.values()]` is the only coercion | Any field that is not an int raises `ValueError` — which `debug=True` then exposes. In production, validate and coerce explicitly. |
| Authentication | Absent | Irrelevant to the teaching goal | Add Flask-Login / a reverse proxy with auth for any real deployment |
| CSRF protection | Absent | Form posts use no token | Add Flask-WTF for real forms |
| Content Security Policy | Absent | Templates render directly | Set headers in front of Flask in production |
| HTTPS | Absent | Dev server is HTTP | Terminate TLS at the proxy |
| Rate limiting | Absent | Dev server is single-threaded | Use a production WSGI server + gateway |

All of these are deliberate teaching tradeoffs. When a student forks this as a template, the above table is the conversation to have with them.

### 7.5 Swapping the model

The lesson's own `notebook.ipynb` trains the classifier and writes `ufo-model.pkl`. To replace the model:

1. Re-run the notebook (or train in your own script) and emit a `.pkl` with a compatible `predict()` signature (takes an `n_samples × n_features` 2D array, returns an array of class indices).
2. Replace `3-Web-App/1-Web-App/solution/ufo-model.pkl`.
3. Update the `countries` list in `app.py` so the class index → label mapping stays consistent.

---

## 8. Sub-Project: Vue Quiz App (`quiz-app/`)

### 8.1 Purpose

Locally hostable version of the pre/post-lecture quizzes. The canonical student experience uses the externally hosted `ff-quizzes.netlify.app`, but teachers can self-host for air-gapped classrooms, for LMS integration, or when the external host is unreachable.

### 8.2 Stack at this commit

| Package | Version | Role |
|---|---|---|
| `vue` | ^3.5.12 | UI framework |
| `vue-router` | ^3.5.3 | Client-side routing (note: paired with Vue 3 — intentional lesson-era pinning) |
| `vue-i18n` | ^8.26.7 | In-app language switching |
| `@vue/cli-service` | ~5.0.8 | Build tool (Vue CLI 5) |
| `eslint` | ^9.33.0 | Linter; `eslint-plugin-vue` ^10.4.0 |
| `core-js` | ^3.6.5 | Polyfill |

The quiz-app also lives under `src/` with:

```
quiz-app/src/
├── App.vue         Root component
├── main.js         Bootstrap: router + i18n mount
├── router/         Routes per lesson/quiz
├── views/          Per-quiz views
├── components/     Shared UI (Quiz, Question, Result)
└── assets/         Per-language quiz JSON
```

### 8.3 Scripts

| Command | Action |
|---|---|
| `npm install` | Install deps into `quiz-app/node_modules/` |
| `npm run serve` | Vue CLI dev server with HMR (default port 8080) |
| `npm run build` | Production bundle to `quiz-app/dist/` |
| `npm run lint` | ESLint with `plugin:vue/essential` + `eslint:recommended` |

### 8.4 Adding a quiz

1. Add the question objects to the appropriate language JSON under `quiz-app/src/assets/translations/` (or wherever the quiz data lives for the version you are on).
2. If it is a new lesson, add a route in `quiz-app/src/router/` and a view in `quiz-app/src/views/`.
3. Update the root `README.md` master table and the lesson README's quiz links so the quiz-id matches.
4. `npm run build` and test the production bundle locally before pushing.

### 8.5 Deployment to Azure Static Web Apps

The quiz-app's README documents the Azure SWA flow. Summary of the Action config:

```yaml
uses: Azure/static-web-apps-deploy@v1
with:
  azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
  repo_token: ${{ secrets.GITHUB_TOKEN }}
  action: "upload"
  app_location: "/quiz-app"      # App source code path
  api_location: ""               # No API
  output_location: "dist"        # Vue CLI build output
```

Portal steps (condensed from `quiz-app/README.md`):

1. Fork the repo.
2. *Azure Portal → Create resource → Static Web App*. Select GitHub as source, authorize Azure, pick the fork and branch.
3. Build preset: **Vue**. App location: `/quiz-app`. Output location: `dist`.
4. Azure writes a workflow file at `.github/workflows/azure-static-web-apps-<name>.yml` and runs it on every push to the selected branch.

---

## 9. Classroom Delivery Patterns

The `for-teachers.md` file is short but prescriptive. The core patterns:

### 9.1 GitHub Classroom (recommended for formal courses)

Because GitHub Classroom expects one repo per assignment, teachers extract each lesson folder into its own repo so Classroom can assign them individually:

1. Fork this repo.
2. For each lesson you want to assign, extract the lesson folder into a standalone repo.
3. In [GitHub Classroom](https://classroom.github.com/classrooms), create an assignment pointing at the lesson repo.
4. Each student gets an auto-forked copy; submissions are managed through Classroom.

### 9.2 Repo-as-is (informal or cohort-based delivery)

Simplest pattern — the teacher just directs students to specific lessons in the upstream repo. Quizzes and assignments are submitted via:

- **Public submission** — students file GitHub Issues on the teacher's classroom repo with their answers.
- **Private submission** — students fork each lesson to a private repo, grant the teacher access, and submit via issues on those private forks.

### 9.3 Online classroom (Zoom/Teams/breakout rooms)

The recommended pattern in `for-teachers.md`:

- **Pre-lecture quiz** → breakout rooms of 3–4. Each room submits collective answers as an issue on the classroom repo before the lecture starts.
- **Lecture** → live-coded walkthrough of the lesson notebook.
- **Breakout work** → students work the assignment in pairs, TAs rotate rooms.
- **Post-lecture quiz** → back in the main room, quick recap.

### 9.4 Feedback channel

Teachers are asked to fill the feedback form referenced in `for-teachers.md` so Microsoft can iterate on the curriculum.

---

## 10. Security & Trust Boundary

### 10.1 Reporting vulnerabilities

`SECURITY.md` directs all reports to the **Microsoft Security Response Center (MSRC)**:

- Primary: [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report)
- Email fallback: `[email removed]` (PGP available from [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc))
- Response SLA: 24 hours

**Never report via a public GitHub issue.** The curriculum is watched by students — a public disclosure would expose them to copy-paste exploitation before MSRC can respond.

### 10.2 What counts as a vulnerability here

Because the repo has no production runtime, the attack surface is:

| Surface | Concern | Reporting route |
|---|---|---|
| Flask demo app in student forks | RCE via `debug=True` Werkzeug console; pickle-load of hostile `.pkl`; form-value coercion | MSRC (as the upstream template) |
| Quiz-app dependencies | Supply-chain CVEs in Vue / vue-cli / eslint-plugin-vue | MSRC or Dependabot PR |
| `docsify-to-pdf` | Puppeteer/Chromium CVEs reachable during PDF generation | MSRC or Dependabot PR |
| Notebooks | Embedded `!curl … | sh` or other remote-execution patterns | MSRC (high-priority — students run unverified notebooks) |
| Translations | Garbage content from MT pipeline that alters meaning in harmful ways | GitHub issue (quality), MSRC (if intentional malicious insertion) |

### 10.3 Intentional non-security for teaching clarity

The demo Flask app runs with `debug=True`, loads a local pickle, and has no auth. This is **documented as intentional**. The authoring contract is that lessons optimize for learner clarity; the operational mitigation is §7.4 — when reusing this code, the security table is the conversation.

### 10.4 Dependency hygiene

- Dependabot is available (free for public repos on GitHub); enabling it catches CVEs in the quiz-app and `docsify-to-pdf` stacks automatically.
- The `.github/workflows/generator-generic-ossf-slsa3-publish.yml` workflow produces SLSA level-3 provenance on releases. It currently ships `artifact1`/`artifact2` placeholders — adapt the `Build artifacts` step before cutting a tagged release if you want provenance to cover real binaries.

### 10.5 Secret handling

The repo holds no secrets. The Co-op Translator workflow *consumes* secrets (Azure OpenAI keys) stored in GitHub repository settings. When forking:

- Do not copy secrets from the upstream — they are not accessible anyway.
- Generate your own Azure OpenAI deployment and add its credentials as repo secrets before enabling the Action.

---

## 11. Operations Reference

### 11.1 Building the Docsify site

Docsify has **no build step**. Verifying the site locally:

```bash
# From repo root
npm install -g docsify-cli    # one-time
docsify serve .               # http://localhost:3000
```

Deployment: push to GitHub with Pages enabled for the branch. The `.nojekyll` file is already in place so Pages serves the tree as-is.

### 11.2 Generating the PDF

```bash
npm install            # pulls docsify-to-pdf@0.0.5 from root package.json
npm run convert        # runs node_modules/.bin/docsify-to-pdf
# Output: pdf/readme.pdf
```

`docsify-to-pdf` requires a Chromium binary (bundled via Puppeteer). On Linux CI you need the usual Chromium deps (`libnss3`, `libatk-bridge2.0-0`, `libcups2`, `libdrm2`, `libxcomposite1`, `libxrandr2`, `libgbm1`, `libxkbcommon0`, `libasound2`).

### 11.3 Deploying the quiz-app

Two supported paths:

| Target | Mechanism | Detail |
|---|---|---|
| Azure Static Web Apps | GitHub Action `Azure/static-web-apps-deploy@v1` | See §8.5. Preset: Vue. app_location `/quiz-app`, output_location `dist`. |
| Any static host (Netlify, Vercel, S3+CloudFront, GitHub Pages) | `npm run build` and upload `quiz-app/dist/` | No SPA routing gotchas — vue-router uses hash mode by default in this config. |

### 11.4 Running Co-op Translator

Run on demand via the Action UI (`workflow_dispatch`) or on a schedule. For a full re-translation of the repo:

1. Confirm Azure OpenAI quota — a full run hits every English Markdown and every image with text.
2. Decide the commit policy (direct push vs. PR). PRs are safer but add review overhead.
3. Kick off the workflow.
4. Expect a large commit (thousands of files). Use `git log --stat` on the generated commit to spot-check.

### 11.5 Repository maintenance workflows

| Workflow | Trigger | Behavior |
|---|---|---|
| `.github/workflows/stale.yml` | Cron `35 8 * * *` daily | Uses `actions/stale@v10` to comment on and close issues/PRs with no activity. Labels: `no-issue-activity`, `no-pr-activity`. |
| `.github/workflows/lock.yml` | On issue `closed` | Uses `OSDKDev/lock-issues@v1.1` to prevent new comments on closed issues. |
| `.github/workflows/generator-generic-ossf-slsa3-publish.yml` | `workflow_dispatch` or release created | SLSA level-3 provenance on release artifacts. |

Adjusting close timing: edit `stale.yml` — defaults of `actions/stale@v10` apply (typically 60-day warn + 7-day close) unless overridden. Adjusting issue-lock grace: edit the `lock.yml` step or swap in `dessant/lock-threads@v5` for more configuration.

### 11.6 Sparse-checkout recipe for maintainers

To work with a specific lesson without cloning translations:

```bash
git clone --filter=blob:none --no-checkout https://github.com/microsoft/ML-For-Beginners.git
cd ML-For-Beginners
git sparse-checkout init --cone
git sparse-checkout set 2-Regression 3-Web-App docs quiz-app
# Exclude translation noise from the working tree
git sparse-checkout set --no-cone \
    '/*' \
    '!/translations' \
    '!/translated_images'
git checkout main
```

This trims the working tree from thousands of generated files to only the English source. Cuts clone size by ~95%.

---

## 12. Contributing Workflow

### 12.1 Microsoft CLA (Contributor License Agreement)

Per `CONTRIBUTING.md`, all non-trivial contributions require a signed Microsoft CLA. The flow:

1. Open a PR against `main`.
2. The CLA-bot auto-comments on the PR with a signing link (first-time contributors).
3. Sign once at [https://cla.microsoft.com](https://cla.microsoft.com) — valid across all Microsoft CLA repositories.
4. The bot re-verifies and labels the PR accordingly.

### 12.2 Code of Conduct

The repo adopts the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). Reports go to `[email removed]`. The [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) explains enforcement.

### 12.3 Pull request categories

| PR type | Expectations | Extra steps |
|---|---|---|
| **Typo / copy fix** in English Markdown | Single-file PR, no translation update | CLA sign-off (one-time) |
| **New lesson content** or substantial rewrite | Follows §5 authoring contract; includes sketchnote; updates root README table; updates `docs/_sidebar.md` | CLA; re-run Co-op Translator after merge |
| **Human translation** | Direct edit under `translations/{lang}/`; marks file as human-reviewed so MT does not overwrite | CLA; proficiency declaration in PR description |
| **Quiz change** | Updates quiz-app JSON and lesson README quiz links in the same PR | CLA; `npm run lint` must pass |
| **Dependency bump** | `quiz-app/package.json` or root `package.json` | CLA; verify `npm run build` locally |
| **Security fix** | Route through MSRC first — do **not** open a public PR with an exploit description | Per §10.1 |

### 12.4 Commit signing

Not required by repo config at this commit, but Microsoft repos commonly adopt DCO or signed commits over time. Check the PR template and `main` branch protection rules before submitting.

### 12.5 Issue templates

Located in `.github/ISSUE_TEMPLATE/`. Use them — triagers depend on the structured fields to route issues. The default templates cover bug reports, feature/content requests, and translation issues.

---

## 13. Troubleshooting Runbook (Maintainer View)

A full learner-facing troubleshooting list lives in `TROUBLESHOOTING.md`. The items below are the *maintainer* failures that recur and how to triage them.

### 13.1 "Co-op Translator commit broke lesson N"

Symptom: a translation PR or push lands and a lesson's sidebar link 404s, or the post-lecture quiz link is missing in `translations/{lang}/`.

Triage:

1. Diff the generated commit against the English source: `git diff HEAD~1 -- translations/{lang}/{lesson-path}/README.md`.
2. Check whether the English `README.md` uses an uncommon Markdown construct (nested code fence, HTML embed) that the translator stripped.
3. Fix the English source to use the standard constructs, then re-run the Action for that language only.

### 13.2 Docsify site shows a blank page after a push

Symptom: Docsify hits a parsing error on a Markdown file and stops rendering.

Triage:

1. Open browser DevTools → Console. Docsify prints the failing URL.
2. Load that Markdown file directly in the browser — invalid YAML front matter or unbalanced fences are common.
3. For translated files, look for a dropped closing ` ``` ` — the Co-op Translator historically has had sporadic issues with fence preservation.

### 13.3 `npm run convert` hangs during PDF generation

Symptom: `docsify-to-pdf` launches Chromium and never completes.

Triage:

1. On Linux CI, missing Chromium libs — install per §11.2.
2. On large repos (this one qualifies), memory pressure. Increase the CI runner, or scope `docsifytopdf.js` `contents:` to a subset of `docs/_sidebar.md`.
3. Network timeouts on CDN-loaded theme — retry, or self-host the Docsify theme.

### 13.4 Quiz-app `npm install` fails on a fresh clone

Symptom: peer-dependency warnings escalate to errors with newer npm versions.

Triage:

1. The package set was authored for npm 7/8. On npm 9+ you may need `--legacy-peer-deps`.
2. If a devDependency (e.g. `babel-eslint`) is deprecated, do not unilaterally bump it — it affects how lesson-era quizzes tokenize. File a PR and test `npm run build` + the generated SPA against the full quiz set.

### 13.5 Stale workflow closes an active issue

Symptom: a discussion issue is auto-closed by `actions/stale@v10` mid-conversation.

Triage:

1. Add a non-stale label (e.g. `pinned` or `keep`) and configure `stale.yml`'s `exempt-issue-labels` to exclude it.
2. Reopen the issue. The `lock.yml` workflow locks issues *on close*, so a freshly reopened issue is unlocked again.

### 13.6 SLSA provenance workflow fails on release

Symptom: release job succeeds but the `provenance` job errors with signing/permission failures.

Triage:

1. The `provenance` job needs `id-token: write` and `contents: write`. Confirm the workflow block still includes them.
2. The called workflow is pinned to `slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.4.0`. If GitHub has deprecated the runner image or the action version, bump both and re-run.

---

## 14. Forking Guidance

Common reasons to fork:

| Reason | What to change | What to leave alone |
|---|---|---|
| Running a cohort-specific course | `README.md` cohort notes, `for-teachers.md` | Lesson content, quiz IDs, translations |
| Translating to a new language | Add language in Co-op Translator config; may seed `translations/{new-lang}/` with a run | English source (never branch English lesson content for translation work) |
| Derivative curriculum (different order, extra lessons) | Lesson tree, `README.md` master table, `docs/_sidebar.md` | Microsoft-specific files (CLA ref, SECURITY.md, CODE_OF_CONDUCT.md) unless you are replacing them with your own |
| Training-only material for an org | Private fork, add org-specific material alongside | Upstream lesson folders — makes future rebasing easier |

**Attribution:** The root README and LICENSE (MIT) document attribution. If you use the curriculum under MIT, keep `LICENSE` and the author credits in `AGENTS.md` / `README.md`. Translations retain the upstream authorship notice at the top (the Co-op Translator adds a standard attribution block).

**What to strip before re-publishing under your own brand:**

- `SECURITY.md` — replace with your org's reporting channel; MSRC is not appropriate outside Microsoft.
- `CONTRIBUTING.md` — the Microsoft CLA does not apply to a non-Microsoft fork.
- `SUPPORT.md` — swap in your support channels.
- `.github/ISSUE_TEMPLATE/` and `PULL_REQUEST_TEMPLATE/` — adjust to match your processes.

---

## 15. External Dependencies and References

### 15.1 Build-time dependencies

| Package | Scope | Role | Pin location |
|---|---|---|---|
| `docsify-to-pdf@0.0.5` | root devDependency | PDF export | `package.json` |
| `vue@^3.5.12` | `quiz-app` dependency | SPA framework | `quiz-app/package.json` |
| `vue-router@^3.5.3` | `quiz-app` dependency | Routing | `quiz-app/package.json` |
| `vue-i18n@^8.26.7` | `quiz-app` dependency | i18n | `quiz-app/package.json` |
| `@vue/cli-service@~5.0.8` | `quiz-app` devDependency | Build | `quiz-app/package.json` |
| `eslint@^9.33.0` | `quiz-app` devDependency | Linting | `quiz-app/package.json` |
| `eslint-plugin-vue@^10.4.0` | `quiz-app` devDependency | Vue lint rules | `quiz-app/package.json` |
| `flask` | Lesson 9 runtime | Web framework | `3-Web-App/1-Web-App/solution/web-app/requirements.txt` |
| `scikit-learn`, `pandas`, `numpy` | Lesson 9 + most Python lessons | ML stack | same `requirements.txt` |

### 15.2 Runtime external hosts

| Host | Purpose |
|---|---|
| `https://ff-quizzes.netlify.app/en/ml/` | External quiz host referenced from every lesson README |
| `https://cdn.jsdelivr.net/npm/docsify@4/lib/docsify.min.js` | Docsify runtime for the docs site |
| `https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple.css` | Docs site theme |
| `https://aka.ms/ml-beginners` | Canonical short URL for the curriculum |
| `https://aka.ms/foundry/discord` | Community Discord (`#ml-for-beginners` channel) |
| `https://cla.microsoft.com` | Microsoft CLA signing |
| `https://msrc.microsoft.com/create-report` | MSRC vulnerability reporting |

### 15.3 Upstream references

- [Curriculum landing page](https://aka.ms/ml-beginners)
- [Co-op Translator source](https://github.com/Azure/co-op-translator)
- [GitHub Classroom setup guide](https://github.blog/2020-03-18-set-up-your-digital-classroom-with-github-classroom/)
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Azure Static Web Apps documentation](https://learn.microsoft.com/azure/static-web-apps/getting-started)
- [SLSA specification](https://slsa.dev)

---

## 16. Quick Reference

### 16.1 Key paths

| Path | What it is |
|---|---|
| `/README.md` | Master curriculum table — update on any lesson add/remove |
| `/AGENTS.md` | AI-agent-readable project overview — keep in sync with README |
| `/docs/_sidebar.md` | Docsify nav + PDF TOC source |
| `/index.html` | Docsify bootstrap; change site name/repo URL here |
| `/docsifytopdf.js` | PDF export config |
| `/quiz-app/src/` | Vue quiz SPA source |
| `/3-Web-App/1-Web-App/solution/web-app/app.py` | Demo Flask app |
| `/translations/{lang}/` | Generated translations — do not hand-edit MT output |
| `/translated_images/{lang}/` | Generated image translations |
| `/.github/workflows/` | stale, lock, SLSA |
| `/.devcontainer/` | VS Code dev container |

### 16.2 Commands cheat sheet

```bash
# Author and preview site
docsify serve .

# PDF export
npm install && npm run convert    # writes pdf/readme.pdf

# Quiz-app dev
cd quiz-app && npm install && npm run serve    # http://localhost:8080
cd quiz-app && npm run build                   # dist/
cd quiz-app && npm run lint                    # ESLint

# Flask demo
cd 3-Web-App/1-Web-App/solution/web-app
pip install -r requirements.txt && python app.py   # http://127.0.0.1:5000

# Sparse-checkout without translation noise
git clone --filter=blob:none --no-checkout https://github.com/microsoft/ML-For-Beginners.git
cd ML-For-Beginners
git sparse-checkout init --cone
git sparse-checkout set --no-cone '/*' '!/translations' '!/translated_images'
git checkout main
```

### 16.3 Decision matrix: where to report or ask

| Situation | Channel |
|---|---|
| Bug in lesson content or broken link | GitHub Issue (use the issue template) |
| Security vulnerability | MSRC: [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report) |
| Translation quality problem | GitHub Issue; tag the language |
| Code-of-conduct concern | `[email removed]` |
| Feature request | GitHub Issue with `enhancement` label |
| Community help / classroom questions | Discord `#ml-for-beginners` at [aka.ms/foundry/discord](https://aka.ms/foundry/discord) |
| Teacher feedback | Form linked in `for-teachers.md` |
| Tooling/translation pipeline | Co-op Translator repo: [github.com/Azure/co-op-translator](https://github.com/Azure/co-op-translator) |

---

_Generated May 2026 from microsoft/ML-For-Beginners at 000d594. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
