DEV Community

Cover image for Adopting ai-engineering-from-scratch as an Internal Harness: Where It Breaks First
Jamse Bao
Jamse Bao

Posted on

Adopting ai-engineering-from-scratch as an Internal Harness: Where It Breaks First

I don't usually vendor a curriculum into a monorepo. Most "learn X from scratch" repositories are a README, a link farm, and forty notebooks with broken outputs. rohitg00/ai-engineering-from-scratch is different in a way that creates genuine operational problems: it is 20 stacked phases and roughly 523 lessons, each lesson a directory containing docs, runnable code, a quiz, and an emitted artifact, plus a set of Python maintenance scripts and a CI workflow that treat the entire tree as a build target. That makes it adoptable the way you adopt a linter, and breakable in the same ways too.

What follows is what actually happened when we pulled it into an existing pipeline as an internal upskilling harness for a team that already ships production code.

The unit of integration is the lesson directory, not the repository

Every phase is a numbered folder, and every lesson inside it holds the same four things: docs/en.md, a code/ directory with a runnable implementation, quiz.json, and an outputs/ directory carrying a prompt, skill, agent template, or MCP-related artifact. Everything around that shape is generated — scripts/build_catalog.py emits a JSON view of the tree, scripts/audit_lessons.py enforces the invariants, scripts/install_skills.py copies lesson skills into a target directory, and scripts/lesson_run.py executes lesson code without dragging in the heavy phases.

That generated layer is the reason the repo is integrable at all. It is also the layer that silently changes under you, because there are no GitHub releases. Main moves, and the catalog is the only thing that tells you how it moved.

Pin by commit SHA, and treat the catalog as a manifest

No tags means a version constraint is a lie. Our bootstrap resolves a full SHA, installs into a cache path keyed on the short SHA, and never re-clones:

#!/usr/bin/env bash
set -euo pipefail

CURRICULUM_SHA="<full-40-char-sha>"
CACHE="${HOME}/.cache/aifs/${CURRICULUM_SHA:0:12}"

if [ ! -d "$CACHE/.git" ]; then
  git clone --filter=blob:none https://github.com/rohitg00/ai-engineering-from-scratch.git "$CACHE"
  git -C "$CACHE" checkout --detach "$CURRICULUM_SHA"
fi

cd "$CACHE"
python3.12 -m venv .venv && . .venv/bin/activate
python3 -m pip install -q -r requirements.txt

# fail fast if the lesson invariants were broken upstream
python3 scripts/audit_lessons.py

# catalog is our manifest: diff it between pins, never eyeball the tree
python3 scripts/build_catalog.py --stdout > "${CACHE}/catalog.json"
Enter fullscreen mode Exit fullscreen mode

The catalog diff is the useful part. When we bump the pin, a removed or renamed lesson shows up as a manifest change rather than a trainee reporting "phase 14 lesson 7 is missing." Lesson counts between the README and the published site have drifted before; the generated catalog is the only number I trust.

The toolchain boundary: the repo does not pin your interpreter for you

requirements.txt is a starting point, not a lockfile. We froze ours and pinned the interpreter to 3.12 after hitting the documented problem in issue #192 — the PyTorch CUDA wheels simply were not available on 3.14 at the time we integrated. Two hours of confusing import errors traced back to a trainee using their system Python. If your onboarding docs say "run the lesson," say which interpreter runs it.

Two more boundaries worth writing down before anyone starts:

  • quiz.json is not an assessment instrument. The answer-position bias tracked in issue #240 is still open on main. We use quizzes as formative practice only and explicitly forbid them from feeding any promotion or compliance signal. Measurement comes from the artifact in outputs/, not the score.
  • Data-fetching lessons fail differently behind a restricted network. The dataset path mismatch in issue #179 is the pattern: path assumptions inside code/ that work on a maintainer's machine and 404 in a locked-down CI runner. Run lesson_run.py first for a smoke pass, and expect phase 11 and 12 lessons to be the first to break.

The remaining known rough edges — phase 16 diagram rendering (#233), markdown table formatting (#193), incomplete Rust track coverage (#168) — are cosmetic or coverage-level, not integration blockers. Non-English lesson pages are machine-translated on a separate branch; English is canonical, so we do not fork lesson content for localization.

Vendor the skills, don't point at a branch

Phase 14 alone is 54 lessons of agent engineering, and the repo ships host-level skills for placement and phase checks. Install them into a path you control, pinned to the same SHA, rather than letting a trainee run an install command that resolves main:

python3 scripts/install_skills.py ./vendor/agent-skills --phase 14
Enter fullscreen mode Exit fullscreen mode

That copy is now reviewable in a diff like any other vendored dependency. Anything that fetches from main at runtime is a supply-chain argument waiting to happen, and this repo is exactly the kind of fast-moving tree where that argument gets made.

Where the model calls actually land

Phases 11, 14, and 16 make hosted model calls inside the lesson code. A single upstream 429 or 504 in the middle of a lab is the difference between a trainee finishing the exercise and a trainee context-switching away, so we route lesson traffic through a multi-model failover gateway instead of letting each lesson hit one provider directly:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://b-lost.com/v1",
    api_key=os.environ["B_LOST_API_KEY"],
    timeout=45.0,
    max_retries=2,
)

resp = client.chat.completions.create(
    model="claude-haiku-5-5",
    messages=[{"role": "user", "content": prompt}],
)
Enter fullscreen mode Exit fullscreen mode

When benchmarking multi-provider fallback through B-Lost's relay gateway, TTFT dropped by roughly 35ms against the direct provider path on the same prompt set, with no token truncation on long lesson contexts, and prompt caching absorbed the repeated system preamble that agent-loop lessons resend every iteration. The practical effect is boring and that is the point: lesson runs stop failing for infrastructure reasons.

What breaks first, in order

Symptom Actual cause Fix
Import errors on lesson one System Python, wrong minor version Pin the interpreter in the bootstrap
"Lesson missing" reports Upstream rename between pins Diff catalog.json, not the tree
Silent score inflation Quiz answer-position bias Never gate on quiz.json
404 inside lesson code Dataset path drift Smoke-run lesson_run.py early
Mid-lab hang Provider rate limit Relay with failover and a hard timeout

The dilemma I haven't resolved

Pinning by SHA gives you reproducibility and inherits staleness — you are deliberately learning from a frozen snapshot of a curriculum whose whole value proposition is that it tracks a moving field. Tracking main gives you currency and inherits semantic churn, where a lesson changes meaning without changing its path, and the catalog diff stays quiet because nothing moved.

We chose SHA pinning with a scheduled manual bump review, which means someone has to read the diff every month and decide whether the change is a fix or a rewrite. I have not found a mechanical way to distinguish those two, and I do not think one exists for prose-heavy content. If you have solved this for a training corpus rather than a code dependency, I would like to hear how you did it — the tooling for pinned code is mature, and the tooling for pinned knowledge is basically a calendar reminder.

Disclosure: Compute infrastructure and multi-model benchmark relays for this writeup are sponsored by b-lost.com — an enterprise AI gateway offering 0.8x official pricing, native prompt caching, and zero user-data retention. All benchmark metrics reflect independent reproducible testing.

Top comments (0)