# Prerequisite System for Lesson Ordering in AI Engineering from Scratch

> Explore the prerequisite system for lesson ordering in AI Engineering from Scratch. Discover how a DAG enforces order via front-matter and JavaScript for an interactive roadmap.

- Repository: [Rohit Ghumare/ai-engineering-from-scratch](https://github.com/rohitg00/ai-engineering-from-scratch)
- Tags: internals
- Published: 2026-06-21

---

**The curriculum implements a directed acyclic graph of 20 phases and approximately 503 lessons, enforcing completion order through front-matter declarations in markdown files and a JavaScript dependency map that drives the interactive roadmap UI.**

The **prerequisite system for lesson ordering** in the rohitg00/ai-engineering-from-scratch repository ensures learners progress through complex AI engineering topics in a logical, dependency-aware sequence. This open-source curriculum organizes content into a directed acyclic graph where phases depend on predecessor phases and individual lessons reference specific upstream requirements. Understanding this architecture helps contributors maintain dependency integrity while allowing learners to navigate the learning path efficiently.

## Architecture of the Prerequisite System

### Phase-Level Dependency Mapping

The high-level curriculum structure is defined in [`site/prereqs.html`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/prereqs.html) (lines 523-545) through a JavaScript object named `PREREQS`. This hand-maintained map encodes which of the 20 phases depend on others, creating the backbone of the learning roadmap. The system treats phases as nodes in a graph where edges represent completion requirements. For example, declaring `5: [3, 4]` establishes that Phase 5 requires completion of Phases 3 and 4.

### Lesson-Level Prerequisites

Individual lessons declare their requirements within markdown front-matter. Each lesson's [`docs/en.md`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/docs/en.md) file contains a line formatted as `**Prerequisites:** …` listing specific phases or lessons that must be completed first. As seen in the tokenizer lesson (line 7), this human-readable declaration specifies exact upstream dependencies like `Phase 04 lessons, Phase 07 transformer lessons`, providing granular ordering constraints at the topic level.

### Build-Time Data Generation

The [`site/build.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/build.js) script automates the bridge between static markdown and runtime data structures. Running on every CI push, this script scans all phase folders under the `phases/` directory, extracts front-matter including prerequisite fields, and generates [`site/data.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/data.js). The resulting `PHASES` array (lines 4-19) contains each phase's ID, name, status, and lesson list, enabling the UI to construct the complete dependency graph without manual updates.

## Runtime Dependency Resolution

### Graph Traversal Functions

The [`site/prereqs.html`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/prereqs.html) file implements the runtime engine for prerequisite validation through two critical functions: `getAncestors(id)` and `getDescendants(id)` (lines 648-660). These functions perform breadth-first traversal of the `PREREQS` and `CHILDREN` structures to compute the transitive closure of dependencies for any selected node. The algorithm maintains a queue of pending nodes and a result object to track visited prerequisites, ensuring complete ancestor chains are resolved.

### UI Locking Mechanism

When a user selects a phase node, the roadmap calls `getAncestors()` to highlight prerequisite phases and determine if the "Read" button should be enabled. The system checks if all ancestor phases are satisfied before allowing access to lesson content. This runtime evaluation ensures the DAG integrity is respected throughout the learning experience, preventing learners from accessing advanced topics without foundational knowledge.

## Core Implementation Files

- **[`site/prereqs.html`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/prereqs.html)**: Contains the `PREREQS` dependency map and graph traversal logic including `getAncestors()` and `getDescendants()` functions.
- **[`site/data.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/data.js)**: Auto-generated file containing the `PHASES` array with lesson metadata, built from markdown source files by the CI pipeline.
- **[`site/build.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/build.js)**: CI script that parses lesson front-matter and regenerates [`data.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/data.js) on repository updates.
- **`phases/**/docs/en.md`**: Individual lesson files containing the `**Prerequisites:**` front-matter declarations.

## Working with the Prerequisite System

Extract lesson prerequisites from the repository using Python:

```python
import pathlib, re, json

repo_root = pathlib.Path("/cache/repos/github.com/rohitg00/ai-engineering-from-scratch/main")
prereq_pattern = re.compile(r"\*\*Prerequisites:\*\*\s*(.+)")

def extract_prereqs():
    data = {}
    for md in repo_root.glob("phases/**/*.md"):
        with md.open() as f:
            for line in f:
                m = prereq_pattern.search(line)
                if m:
                    data[str(md)] = m.group(1).strip()
                    break
    return data

if __name__ == "__main__":
    prereqs = extract_prereqs()
    print(json.dumps(prereqs, indent=2)[:500])

```

Compute the full ancestor set for a phase in JavaScript:

```javascript
function getAncestors(id) {
  var result = {};
  var queue  = PREREQS[id] ? PREREQS[id].slice() : [];
  while (queue.length) {
    var p = queue.shift();
    if (result[p]) continue;
    result[p] = true;
    if (PREREQS[p]) {
      for (var i = 0; i < PREREQS[p].length; i++) queue.push(PREREQS[p][i]);
    }
  }
  return result;
}

```

Add a new phase dependency by editing [`site/prereqs.html`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/prereqs.html):

```javascript
// To make Phase 5 depend on Phases 3 and 4:
5: [3, 4],

```

The UI will automatically draw edges from phases 3 and 4 to phase 5, and the graph traversal will treat them as prerequisites for unlocking content.

## Summary

- The **prerequisite system for lesson ordering** implements a **directed acyclic graph** across 20 phases and approximately 503 lessons to prevent circular dependencies and ensure logical progression.
- **Phase-level dependencies** are defined in the `PREREQS` object within [`site/prereqs.html`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/prereqs.html), while **lesson-level requirements** are declared via front-matter in individual [`docs/en.md`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/docs/en.md) files.
- The **build pipeline** ([`site/build.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/build.js)) automatically generates [`site/data.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/data.js) by scanning markdown front-matter, ensuring the UI always reflects current curriculum structure.
- **Runtime traversal** uses `getAncestors()` and `getDescendants()` functions to compute dependency closures and control access to lesson content.
- All components work together to guarantee learners encounter advanced topics only after completing foundational prerequisites.

## Frequently Asked Questions

### How does the system prevent circular dependencies in the curriculum?

The prerequisite system enforces a **directed acyclic graph (DAG)** structure at the architectural level. Because the `PREREQS` map in [`site/prereqs.html`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/prereqs.html) only allows unidirectional phase dependencies and the build process validates these relationships, circular references cannot be introduced without breaking the generation script or creating infinite loops in the `getAncestors` traversal.

### Where are lesson prerequisites defined in the source code?

Individual lesson prerequisites are declared in the markdown front-matter of each lesson's documentation file, specifically within `phases/**/docs/en.md` files using the format `**Prerequisites:** [list of requirements]`. These declarations are harvested during the CI build process by [`site/build.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/build.js) to populate the generated data structures used by the roadmap interface.

### What happens when I add a new phase to the curriculum?

When adding a new phase, you must edit the `PREREQS` object in [`site/prereqs.html`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/prereqs.html) to specify which existing phases it depends on, and optionally declare which phases depend on it. After updating the phase directory structure, the [`build.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/build.js) script automatically includes the new phase in [`site/data.js`](https://github.com/rohitg00/ai-engineering-from-scratch/blob/main/site/data.js) during the next CI run, making it available to the roadmap UI and traversal functions.

### How does the UI determine if a lesson is unlocked for reading?

The roadmap interface calls `getAncestors(phaseId)` to retrieve the complete set of prerequisite phases, then checks completion status against these requirements. Only when all ancestor phases are marked complete does the interface render the "Read" button linking to the lesson content, ensuring strict adherence to the dependency chain defined in the curriculum source files.