AI Engineer — Role-Based Learning Hub

A modular collection of role-specific, project-driven curriculum tracks. Each track targets a distinct job description, stands alone as a complete learning path, and opens as its own book with a focused sidebar and search.

Published at https://ai-engineer-zt0.pages.dev/ — built from master on every push.


Tracks

TrackFocus
LLM Inside-Out MasteryVocabulary → transformers → model selection → local inference → serving → RAG → agents → eval → security → startup
LLM Inference EngineerTokenization → transformers → training → RAG → inference serving
CV EngineerClassical CV, PyTorch/TF, detection & segmentation, MLOps
Senior ML EngineerFeature stores, retrieval, ranking, recsys, experimentation, MLOps
Model Accuracy & AI PerformanceFramework internals, quantization, compilers, NPU deployment, profiling
Head of Software Engineering — GPUGPU architecture, CUDA, compilers, drivers, runtimes, scheduling
Rack Management — Senior/Staff SWERack-scale AI systems, Redfish/IPMI/SNMP, BMC/PDU/CDU/PCIe, provisioning, K8s, telemetry, firmware/RAS, secure multi-tenancy
AI SpecialistOperational digital twin (JD1) + inference optimization & accelerators (JD2)
Apache Committer / PMC EngineerASF governance, JVM systems, review culture, release engineering
Security EngineerAppSec, OS & sandboxing, cloud, vuln research, IR, AI/agent security
Principal Data Infrastructure EngineerDistributed data platform: Kafka/Kinesis, Flink, Spark, EMR, Iceberg/Delta/Hudi, Trino/Athena, Cassandra, Scala/Cats/ZIO, governance & reliability
Red Team EngineerAdversary emulation, engagement lifecycle, OS internals, AD/Kerberos, C2, cloud/container, social engineering, RE, purple team — Mandiant consulting track
Principal Azure Cloud Engineer & ArchitectARM control plane, Terraform/CDKTF IaC, Entra ID/OAuth2/OIDC/JWT, RBAC & Policy, landing zones, VNet/NSG/routing, ACR/AKS, CI/CD + OIDC federation, APIM, Service Bus/Event Grid, Functions/Durable, Key Vault/Managed Identity, KQL, reliability & FinOps
Senior AI Engineer (LLMs/VLMs/Agents)From scratch: tokenizer → transformer/attention → autograd → VLMs → LoRA/QLoRA/quantization → RLHF/DPO → sampling & constrained decoding → vLLM-class serving (PagedAttention) → distributed training → RAG/ANN → agents & multi-agent → neurosymbolic → embodied/VLA → eval/guardrails → MLOps (MLflow) → CUDA → capstone
Agentic AI Engineer (Infra & Platforms)Agent infrastructure from scratch: reliability/cost math → ReAct/ReWOO loop → tool calling & JSON-Schema → MCP servers → context engineering → RAG + GraphRAG/LightRAG/RAPTOR → multi-agent → durable execution (Temporal-class) → sandboxing → prompt-injection defense → LLM-as-judge evals → async services → multi-tenancy → cost/observability → coding agents → voice → enterprise-platform capstone. Part II — Frameworks Deep Dive: LangGraph, CrewAI, AWS Bedrock AgentCore, OpenAI Agents SDK, Google ADK, AutoGen/Microsoft Agent Framework, and the Amazon Bedrock foundation-model platform. Part III — Cloud AI Platforms, MLOps & Production Infra: SageMaker/Vertex AI/Azure ML, MLOps (tracking/registry/CI-CD/drift), data & feature engineering (feature stores/Dataflow/BigQuery ML/Databricks), Kubernetes/OKE SRE. Part IV — GenAI Frameworks & ML Foundations: LangChain core, Hugging Face, Cohere, ML/DL foundations (TF/PyTorch, supervised/unsupervised/RL). Part V — Eval-Driven Development for software-delivery agents. Every phase is a faithful stdlib miniature + four principal-depth deep-dive docs (Deep Dive / Principal Deep Dive / Core Contributor Notes / Staff Engineer Notes)
Enterprise AI & Agentic Platform — Engineering & ArchitectureThe senior technical authority for a Tier-1 bank's AI & Agentic Platform, two-in-a-box with the Platform Product Owner, under CBUAE regulation. Builds the substrate a whole bank's agents run on: the five-layer stack (Action Gateway, Agent Kernel, Control Plane, Knowledge Foundation, Users & Channels) plus the cross-cutting model, identity and infrastructure layers. Platform availability & error-budget math → the agent kernel (lifecycle, tiered memory, externalized state, consistent-hash session affinity) → the multi-protocol stack (MCP tool estate with versioning and authorization-aware discovery; A2A/ACP delegation with depth, cycle, tenancy and classification admission) → the LLM gateway (routing, fallback, semantic caching, token accounting, tenant isolation) → serving economics (PTUs vs PAYG, vLLM/KV-cache, batching) → knowledge foundation (hybrid retrieval) and FIBO/OWL/SHACL/SPARQL financial knowledge graphs → agent & workload identity (NHI, OAuth 2.1, RFC 8693 token exchange, SPIFFE, mTLS, JIT credentials) → zero trust, KYA and policy-as-code → the action gateway (idempotency, sagas, breakers, hash-chained audit) → runtime guardrails (PII/MNPI, injection defence, HITL, OWASP LLM Top 10) → integration fabric (ISO 20022, Kafka, outbox, data products) → cloud backbone (Terraform, AKS, mesh, private networking) → SRE for non-deterministic workloads (SLOs, burn-rate alerting, OTel GenAI, FinOps) → CBUAE/model-risk evidence packs → two-in-a-box operating model → a bank-grade capstone. Every phase is a runnable stdlib miniature plus six teaching docs
Elite AI-Lab SWE Interview ProgramNot a track — an executable interview-prep program for OpenAI/Anthropic/DeepMind-class SWE loops. Phase-0 research with confirmed/reported/inference labelling → a timed 3-hour baseline diagnostic that assigns a level per track → a 26-week plan built from the measurement. Seven tracks: a stage-gated progressive coding harness (15 problems, gate N+1 hidden until gate N passes — versioned KV store, token-stream differ with rollback), Python internals proven by runnable experiments (generators, async/TaskGroup, the GIL race that modern CPython hides, __slots__/memoryview measured), distributed design with back-of-envelope calculators and 12 critiqued design artifacts, inference infra (KV-cache math, roofline, continuous batching, autoscaling on token/queue signals) with gpu_math.py, a 48-hour take-home rehearsal plus a deep-dive interrogation harness that reads your actual diff, staff-altitude behavioral, and agent-driving. Weekly scored mocks on a no-hire → strong-hire-at-staff scale, spaced repetition at 1/3/7/21 days
Systems From First PrinciplesNot a curriculum — a 34-month, 15-project build-and-measure journey that trains you to reconstruct foundational systems from their constraints, then measure, break, modify and publish them. Transformer (RoPE, cost model, KV cache) → ANN index (HNSW, recall/QPS, the two-factor speedup model) → vector DB (WAL, filtering cliff, compaction) → LSM engine (Bloom theory vs measurement, the three amplifications) → distributed KV (Raft, replayable fault injection, linearizability checking) → MapReduce (stragglers, speculative execution) → stream processor (watermarks, exactly-once effects) → recommender + simulator + A/B platform (popularity bias, offline-vs-online divergence) → language and bytecode VM with GC → OS kernel (syscall/context-switch cost, Bélády's anomaly) → tensor framework and autodiff → hardware-aware ML (tiling, roofline, a systolic-array simulator) → an integrated system answering one research question, written up as a paper. Every project runs the same 14-step loop: naive design before reading the paper, predicted failure, instrumentation, baseline, falsifiable hypothesis, controlled experiment, failure analysis, report. Includes five executed tools (bench.py, roofline.py, metrics.py, annlab.py, bloom.py), a worked research-notebook entry with real measured numbers, a 12-category scorecard, and a strict AI-assistant policy
Frontier Pre-Training LeadThe job Google DeepMind's Gemini pre-training lead actually does: turn a compute budget into the best servable model. FLOPs/memory algebra (C = 6ND) → scaling laws (Kaplan → Chinchilla → IsoFLOPs, robust fitting, bootstrap forecasts, optimal ladder design) → Mixture of Experts from scratch (routing, load-balance & z-loss, capacity/dropping, total-vs-active, the all-to-all wall). Includes a full dissection of Vlad Feinberg's interview and his Gemini Pretraining talk — MoE, MFU, distillation, quantization, pipelined prefill and the Flash 2.0 war story, explained from zero background with runnable code

How to Use This Hub

Search across every book from the box at the top of this page — press s or / to jump to it, narrow to one track with the dropdown, and share a result set with the #q= link that appears in the address bar. Inside a track, that track's own sidebar search is the faster tool.

  1. Pick the track that matches your target role and open its book.
  2. Start with the track's Overview for the full roadmap and weekly schedule.
  3. Work through phases sequentially — each phase gates the next.
  4. Use each track's Interview Prep and System Design chapters as running references.
  5. Use the ← All Roles link at the top of any track's overview to come back here.

Cross-Track Skills (Shared Foundations)

Regardless of which track you pursue, these skills underpin every role:

  • Python & systems fluency — typing, packaging, profiling, concurrency.
  • Linear algebra, probability, and optimization — the math beneath every model.
  • PyTorch internals — autograd, modules, data pipelines, distributed basics.
  • Production engineering — testing, CI, containers, observability.
  • System design — every track ends in design walkthroughs for its domain.

Published · commit ec521c1 · 2026-08-08 20:32 UTC

How Global Search Works

This page explains the search box on the hub landing page — the one that searches every book at once, as opposed to the per-book search inside each track. It assumes no prior knowledge of search engines, mdBook internals, or static site deployment, and it goes all the way down: what the index actually contains, why it is shaped the way it is, the exact ranking formula, and every failure mode that had to be designed around.

Nothing here is a dependency you must install. The whole feature is one build script, one JavaScript file, and one stylesheet.

Table of Contents


1. The problem

This site is not one book. It is a hub book plus one independent mdBook per role track, each with its own book.toml, its own SUMMARY.md, and its own build output under dist/book/<slug>/. That structure is deliberate: each track stands alone, with a focused sidebar and a search scoped to its own material.

The cost of that structure is that mdBook's built-in search is scoped to one book. Standing on the hub landing page, there was no way to ask "which track covers PagedAttention?" without opening books one at a time and searching each. With 18 books and 23,418 indexed sections, that is not a workable way to find anything.

The goal: one search box on the landing page, covering everything, on a static site with no server, no database, and no search service — and with new tracks appearing in it automatically, since new tracks get added regularly.

2. What mdBook's search already is

Before building anything, it is worth knowing exactly what mdBook already produces, because the whole design is built on reusing it.

When search is enabled (the default), mdBook builds a client-side search index at build time and writes it next to the HTML as searchindex.js. The browser loads it and searches happen entirely in the page — there is no server involved at any point. The engine is elasticlunr.js, a fork of lunr.js.

The unit of indexing is not the page. mdBook splits each page at its headings, so one document in the index is roughly "one section under one heading". That is why a result can deep-link to page.html#some-heading rather than dumping you at the top of a long page.

2.1 Inside searchindex.js

The file is a single assignment:

window.search = Object.assign(window.search, JSON.parse('{ ...the whole index... }'));

The JSON has two parts that matter here:

FieldWhat it holds
doc_urlsArray of page.html#anchor strings, one per indexed section
index.documentStore.docsMap of document number → { title, body, breadcrumbs }

title is the heading text, body is the section's text content, and breadcrumbs is the trail of ancestor headings joined with » — e.g. Track D — ML and Inference Infrastructure » The Eight ML-Infrastructure Designs » m02 — The KV Cache Tier.

The rest of the file — the large majority of it — is elasticlunr's inverted index: a token trie mapping every stemmed term to the documents containing it, with term frequencies for scoring. That is the part that makes search fast, and it is also the part that makes the file enormous.

2.2 The size problem, measured

For this repo, as built:

QuantitySize
All source markdown21.9 MB
All 18 mdBook searchindex.js files119.8 MB
Just the section bodies from those indexes18.25 MB

The index is roughly 5× the source text, and the document store — the actual words — is only about 1× of it. The other 4× is the token trie.

That ratio is the single most important fact in this design. It rules out the obvious approach and points directly at the one that was taken.

3. Approaches that were rejected

Merge the elasticlunr indexes into one. This is the intuitive answer, and it fails on arithmetic: 119.8 MB of index, and elasticlunr indexes cannot be concatenated anyway — merging means re-indexing every document, so the browser would have to build a 120 MB structure at page load. Rejected.

Load each book's index lazily and search them one at a time. Correct results, but the largest single book's index is 18 MB on its own. Searching "everything" would still mean pulling most of the 119.8 MB. Rejected.

A search service (Algolia, Typesense, …). Works well, and is the right answer for many sites. It means an external account, an API key in the build, an upload step on every deploy, and content leaving the repo. For a personal curriculum site that must also work when opened straight off disk, that is a large amount of moving machinery. Rejected.

Pagefind. The strongest alternative, and worth naming explicitly: it is purpose-built for exactly this problem, shards its index so the browser downloads only the fragments a query needs, and would have handled multi-book merging. It was not adopted because it adds a binary/npm dependency to the build for a corpus where the entire document store is 18 MB — small enough to handle directly — and because doing it by hand keeps the whole mechanism inspectable in ~400 lines. If this corpus grows by an order of magnitude, Pagefind is the migration to make.

What was chosen: throw away the token trie, keep the document store, and match in the browser. The trie is what makes elasticlunr fast at scale; at 23,418 sections a plain scan is fast enough, as measured below.

4. The design

4.1 Two tiers

The index is split so that the first keystroke is never waiting on a large download.

Tier 1 — headings (search/headings.js): every section's title, breadcrumb trail, page URL, anchor and owning book, for all 18 books. Loaded eagerly on page load. 2.00 MB raw / 0.41 MB gzipped. This alone gives instant search across every heading in the site.

Tier 2 — bodies (search/body/<slug>.js): the section text, one shard per book. Loaded in the background smallest book first, after the headings land. 18.25 MB raw / 6.26 MB gzipped across 18 shards. Results re-rank as each shard arrives, and the status line shows loading full text 7/18… so the incompleteness is visible rather than silent.

Full-text loading can be turned off entirely with the full text: on/off toggle next to the status line; the choice is remembered in localStorage. With it off, the feature costs 0.41 MB and still searches every heading.

4.2 Columnar layout and interning

Tier 1 is loaded on every visit, so its size is worth optimising. Two transformations cut it by more than half.

Columnar, not row-wise. Instead of an array of {url, title, breadcrumbs, book} objects, the file holds parallel arrays: p, a, t, r, b. Every repeated JSON key name disappears.

Interning the repetitive fields. A page contributes many sections, and every one of them repeats the same page URL and nearly the same breadcrumb trail. So the file holds two lookup tables — pages and trails — and each section stores an integer index into them. The measured redundancy:

CountRatio
Sections23,418
Unique page URLs1,79913.0×
Unique breadcrumb trails1,71613.6×

Result: 5.27 MB → 2.00 MB raw, and 0.75 MB → 0.41 MB gzipped.

Interning pays a second dividend at runtime. Matching is case-insensitive, which means lowercasing the searchable text once at load. With interning that is ~1,716 trail strings instead of 23,418 — the same win, in CPU.

Trails are stored with the section's own title stripped off the end. mdBook's breadcrumb ends with the section itself, and echoing the heading back directly underneath it is noise. (See §8 — this needed more care than it first appears.)

4.3 Why the index ships as .js, not .json

The index files are JavaScript that assign into window.__hubSearch, and the client loads them by injecting <script> tags — not by fetch()ing JSON.

The reason is file://. Browsers treat local files as opaque origins and refuse fetch() against them. A JSON index would make global search dead whenever dist/book/index.html is opened directly from disk rather than served over HTTP — and these books do get opened from disk. A <script> tag has no such restriction.

This is not a novel trick; it is precisely why mdBook itself ships searchindex.js rather than searchindex.json, and why per-book search keeps working off disk.

The payload is still JSON — each file is JSON.parse('…') on a string literal rather than an inline object literal, because JSON.parse on a large string is markedly faster than having the JS engine parse an equivalent object literal.

5. The build step

All of it lives in tools/build-search-index.mjs, run by build.sh after every book has been built.

Ordering matters: the hub's build-dir is the site root dist/book/, and mdBook wipes its build directory at the start of a build. The hub must therefore build first (or it would delete every role book underneath it), and the search index must be written last (or the hub build would delete it).

5.1 Discovering books

Nothing is hardcoded. The generator globs for book.toml at depth 1 and 2 below the repo root, skipping build output and dependency directories, and reads each one for its title, src and build-dir. The build-dir is what maps a book to its slug on the site (../dist/book/red-team-engineerred-team-engineer; the hub's own ../dist/book → the empty slug, the site root).

build.sh discovers books the same way, so the two can never disagree about what the site contains.

One extra condition: a directory needs a SUMMARY.md as well as a book.toml to count. A scaffolded track that has a config but no table of contents yet is skipped with a notice, because mdBook aborts on it and would take the whole deploy down.

Optionally, a book can override the short name shown on its result badges — the automatic rule (take the part before the em-dash) turns "Software Engineer — Rack Management (Senior / Staff)" into the uselessly generic "Software Engineer":

[hub]
short-title = "Rack Management"

mdBook ignores unknown top-level tables, so this costs the build nothing.

5.2 Reading each book's index

searchindex.js has a content hash in its filename and its exact wrapper has changed across mdBook versions, so rather than parse it with a regex the generator executes it in a Node vm context with a stub window, and reads back what it assigned:

const context = vm.createContext({ window: { search: {} } });
vm.runInContext(fs.readFileSync(indexPath, 'utf8'), context, { timeout: 30_000 });
return context.window.search;

This works with any mdBook version's wrapper and needs no unescaping. The input is a file generated seconds earlier by the same build, so there is no untrusted code here.

Section bodies are whitespace-collapsed and capped at MAX_BODY_CHARS = 3000 characters on a word boundary — enough for matching and teasers on a section, without letting one enormous appendix dominate a shard.

5.3 What gets written

Everything lands under dist/book/search/:

FileContents
manifest.jsPer book: slug, full title, short title, offset/count into the section columns, shard filename, byte size
headings.jspages, trails lookup tables + the p/a/t/r/b section columns
body/<slug>.jsSection bodies for one book, aligned to that book's slice of the columns

The offset and count in the manifest are what let a shard be a plain array: book n's bodies map onto sections offset … offset + count - 1. The manifest's bytes field is what the client sorts on to load smallest-first.

The generator prints a per-book section count and the raw/gzip sizes on every build, so a regression in index size is visible in the deploy log.

6. The client

hub/global-search.js, loaded via additional-js in the hub's book.toml, mounting into a <div id="global-search"> in the hub's README.md. It is plain ES5-style script — no build step, no framework, no bundler.

6.1 Loading

manifest.jsheadings.js → background shards. Each is a script injection whose promise resolves once the file has assigned its slot on window.__hubSearch; failure to load is reported in the status line rather than left silent.

A query typed while the index is still downloading is picked up and re-run the moment the headings land — otherwise an early typist gets a permanently empty result list.

6.2 The ranking formula

Every term must appear somewhere in a section for it to match at all (AND, not OR). Per term, per field:

FieldPoints
Section title10
Breadcrumb trail3
Body text1

Then, per result:

BonusPoints
Whole query as a phrase in the title+20
…in the trail (if not in title)+8
…in the body (if not in title or trail)+6
Title equals the query exactly+25
Shallow breadcrumb (max(0, 4 − depth))+0 … +4

The shallow-breadcrumb bonus is a deliberate bias toward general pages: given a phase overview and a sub-sub-section that both match, the overview is usually the better landing point.

Ties break on document order, which keeps results from the same page adjacent. The top MAX_RESULTS = 200 are kept, PAGE_SIZE = 25 render at a time, and the search itself is debounced 110 ms behind typing.

Sections whose shard has not loaded yet simply score 0 on the body field — they still match on title and trail, and re-rank once their book arrives.

6.3 Teasers and highlighting

A teaser is a TEASER_CHARS = 190 window of the body centred on the first matching term, trimmed to word boundaries and ellipsised on both sides.

Highlighting deliberately does not build an HTML string and inject it. It locates match ranges on the lowercased text, then constructs DOM text nodes and <mark> elements around those offsets. Escaping is therefore never a concern, and searching for something like amp cannot corrupt the output by matching inside an HTML entity.

6.4 Interaction

  • s or / focuses the box. mdBook binds those keys to its own search, so the handler is registered in the capture phase and stops propagation.
  • Arrow keys walk the results; Enter opens the selected one, or the first if none is.
  • The book dropdown restricts matching to a single track.
  • The query is mirrored into the URL as #q=…, so a result set can be linked or bookmarked; the page reads it back on load.

7. Performance, measured

On the full 23,418-section corpus with all 18 body shards loaded, a query takes 8–14 ms end to end — scan, score, sort, render. That is well inside the 110 ms debounce, so typing never queues up work.

The scan is String.prototype.indexOf over pre-lowercased strings. Lowercased copies of the bodies roughly double their memory (~36 MB resident with everything loaded); the alternative — lowercasing 18 MB per keystroke, or a case-insensitive regex scan — is what the memory is bought with.

8. Failure modes and the fixes

Every one of these was hit during development. They are recorded because each is a trap that reappears in any similar feature.

fetch() is blocked on file://. The original implementation fetched JSON and worked perfectly over HTTP. Opened from disk it showed "Search index unavailable" while per-book search kept working right beside it. Fixed by shipping the index as scripts (§4.3). A DOM test harness could not have caught this — it stubbed fetch, so it never modelled the restriction. A real browser did.

Two search boxes on one page. mdBook's own search bar sat above the global one on the hub. The hub book is a single page, so its index holds four sections — a search for "llm" there returns one hit from the page's own table, which reads exactly like the global search being broken. mdBook's search UI is now hidden on the hub only; per-book search is untouched.

Invisible highlights. <mark> inherited the body text colour. Every mdBook theme's highlight colour is a pale wash, so matched words in teasers rendered as solid blocks with the word invisible inside. Only a screenshot showed this — the DOM was correct. The mark colour is now pinned to dark ink, legible on all four themes.

Breadcrumbs echoing the title. Stripping one trailing crumb was not enough: a page whose H1 matches its SUMMARY.md entry contributes the same text twice, so the trail still repeated the heading. Trailing crumbs are now popped until they stop matching — verified at 0 duplicates across all 23,418 sections.

U+2028 in generated JavaScript. Line/paragraph separators are legal inside JSON but were only legalised inside JS string literals in ES2019. The generator escapes them — and the escaping code must itself spell them \u2028 / \u2029 rather than embedding the literal characters, which silently terminated the regex literal they were written into.

mdBook wipes its build directory. The hub builds into the site root, so build order is load-bearing: hub first, role books after, search index last. Rebuilding the hub alone during development deletes every other book.

Unhashed assets and edge caches. additional-js files are not content-hashed by mdBook, so a browser can hold a stale global-search.js across a deploy. A hard reload fixes it. Separately, immediately after a deploy a CDN edge can still serve the previous HTML for a short window — during verification one request returned the old page while a simultaneous one returned the new.

9. Adding a new book

Drop a directory containing book.toml and SUMMARY.md at depth 1 or 2 of the repo, with build-dir = "../dist/book/<slug>". That is the whole procedure.

build.sh discovers and builds it, the verification step derives its expected output path from its own build-dir, and the generator indexes it into the global search. There is no list of books to update anywhere.

10. File map

PathRole
tools/build-search-index.mjsBuild-time generator: discovery, parsing, packing, output
hub/global-search.jsThe widget: loading, ranking, rendering, keyboard
hub/global-search.cssStyling in mdBook theme variables; hides mdBook's own search on the hub
hub/README.mdContains the <div id="global-search"> mount point
hub/book.tomladditional-css / additional-js wiring
build.shBook discovery, build order, output verification, index generation
dist/book/search/**Generated output — not committed

11. References