How Roadmap Status Tracking Works in AI Engineering from Scratch: The Emoji-Based System Explained

The curriculum uses three Unicode emojis (โœ… for Complete, ๐Ÿšง for In Progress, โฌš for Planned) stored directly in ROADMAP.md, which site/build.js parses into structured JSON to automatically update the website, README badges, and lesson statistics.

The AI Engineering from Scratch repository maintains a public curriculum roadmap using a lightweight, file-based status tracking system. Instead of external databases or complex project management APIs, the project embeds simple visual markers directly in markdown tables to indicate completion states. This design allows contributors to update progress by editing a single file while automated scripts propagate those changes across the website and documentation.

Where the Status Emojis Live in ROADMAP.md

ROADMAP.md serves as the single source of truth for all curriculum progress. The emoji definitions appear in a legend at the top of the file (lines 9-10), establishing โœ… for Complete, ๐Ÿšง for In Progress, and โฌš for Planned.

Phase headers include the status emoji after an em-dash:


## Phase 0: Setup & Tooling โ€” โœ… (~14 hours)

Individual lessons use markdown table rows with the emoji in the third column:

| 01 | Dev Environment | โœ… | ~75 min |

How build.js Parses the Emoji Statuses

The parseRoadmap() function in site/build.js (lines 36-57) converts these visual markers into machine-readable data using two specific regex patterns.

For phase headers, the pattern matches the phase number and trailing emoji:

const phaseMatch = line.match(/^##\s+Phase\s+(\d+).*?โ€”\s*(โœ…|๐Ÿšง|โฌš)/);
if (phaseMatch) {
  const phaseId = parseInt(phaseMatch[1]);
  const statusEmoji = phaseMatch[2];
  currentPhaseStatus = statusEmoji === 'โœ…' ? 'complete'
                     : statusEmoji === '๐Ÿšง' ? 'in-progress'
                     : 'planned';
  // ...
}

For lesson rows, the pattern extracts the lesson name and status from table formatting:

const lessonMatch = line.match(/^\|\s*\d+\s*\|\s*(.+?)\s*\|\s*(โœ…|๐Ÿšง|โฌš)\s*\|/);
if (lessonMatch) {
  const lessonName = lessonMatch[1].trim();
  const statusEmoji = lessonMatch[2];
  const status = statusEmoji === 'โœ…' ? 'complete'
              : statusEmoji === '๐Ÿšง' ? 'in-progress'
              : 'planned';
  // ...
}

The function returns a nested object structure mapping each phase to its status and a dictionary of lesson statuses:

{
  "Phase 0": {
    "phaseStatus": "complete",
    "lessons": {
      "Dev Environment": "complete",
      "Git & Collaboration": "complete"
    }
  }
}

Status Propagation to the Website and README

Once parsed, the status data flows through several build steps:

  • HTML Generation: The parseReadme function (lines 78-95 in site/build.js) reads the README lesson tables, matches each lesson to the roadmap entry, and copies the computed status onto the lesson object.

  • site/data.js: The build script writes a generated JSON file consumed by the frontend, where each lesson object includes a "status" field of "complete", "in-progress", or "planned".

  • README Synchronization: The syncCounts logic updates the lesson count badge in README.md to reflect current statistics, ensuring the public repository view matches the roadmap state.

Practical Examples

Adding a New Lesson

To add a lesson to the roadmap with planned status:

  1. Open ROADMAP.md and insert a table row:

    | 27 | Advanced Embeddings | โฌš | ~60 min |
  2. Run node site/build.js (or let CI automate this). The new lesson appears in site/data.js with "status":"planned" and renders the empty square icon on the website.

Programmatic Status Lookup

You can use the parsing logic directly to check status programmatically:

const fs = require('fs');

// Load the parsing function from build.js
const { parseRoadmap } = require('./site/build.js');

const roadmap = parseRoadmap(fs.readFileSync('ROADMAP.md', 'utf8'));
const phase = roadmap['Phase 5'];

console.log('Phase 5 status:', phase.phaseStatus); // โ†’ "complete"
console.log('Lesson status:', phase.lessons['Text Processing โ€” Tokenization, Stemming, Lemmatization']);
// โ†’ "complete"

Rendering Status Badges

The frontend uses the status strings to render visual indicators:

<span class="status-badge complete">โœ…</span>
<span class="status-badge in-progress">๐Ÿšง</span>
<span class="status-badge planned">โฌš</span>

Summary

  • Single source of truth: Only ROADMAP.md requires manual editing; the website and README regenerate automatically via site/build.js.
  • Three-state system: โœ… maps to "complete", ๐Ÿšง to "in-progress", and โฌš to "planned".
  • Regex parsing: Lines 36-57 of site/build.js use pattern matching to extract statuses from phase headers and lesson table rows.
  • Deterministic output: Unicode emojis ensure identical parsing across all platforms and operating systems.

Frequently Asked Questions

What happens if I use the wrong emoji in ROADMAP.md?

If you use an emoji not in the set [โœ…๐Ÿšงโฌš], the regex patterns in site/build.js will fail to match that line, causing the entry to be omitted from the generated site/data.js. The build process will effectively treat that lesson or phase as having no status, and it won't appear in the website's progress tracking until corrected.

Can I modify the status emojis to use different characters?

You would need to update three locations: the legend in ROADMAP.md (lines 9-10), the regex patterns in site/build.js (lines 36-57), and the mapping logic that converts emoji matches to string values ('complete', 'in-progress', 'planned'). The system is designed to be strict about the current Unicode characters to ensure consistency across the repository.

How does the README badge stay synchronized with the roadmap?

The syncCounts functionality within site/build.js automatically calculates the total number of lessons and their completion status after parsing ROADMAP.md. It then updates the badge URL in README.md to reflect current statistics, ensuring that the repository's front page always displays accurate progress without manual editing.

Is this emoji-based system scalable for larger curricula?

According to the source code design, the system scales linearly with the number of lessons because parseRoadmap() iterates through ROADMAP.md once in O(n) time. Since it uses simple string matching rather than complex parsing libraries, performance remains consistent even with hundreds of lessons. The only limitation is markdown file size, which GitHub handles efficiently up to several megabytes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too โ†’