GitHub
All wiki pages

Architecture

The short version, for a contributor who wants the shape of the system without reading every source file. For full depth, the repo's own docs/ carries the detailed versions: design.md for pedagogical framing, system_design.md for mechanics, deep-dive.md for a step-by-step trace of what actually executes.

From a module to a real, importable symbol

Each module has two forms of the same content:

  • data/src/NN_name/NN_name.py: the source of truth. This is what gets edited, whether by a maintainer authoring the curriculum or (indirectly, via the generated notebook) a student solving it.
  • data/modules/NN_name/: a stub notebook, generated from the source via Jupytext, with solution cells stripped. This is what a student actually opens and edits in Jupyter.
  • data/solutions/NN_name/: the fully-solved reference notebook, gitignored, maintainer/CI-only. Exists so the curriculum's correctness can be verified independent of any student's in-progress work.

tren module complete runs a four-step pipeline against whichever notebook is relevant (a student's data/modules/ notebook, or, during maintainer curriculum verification, the data/solutions/ reference):

  1. Unit tests: runs the module's own tests against the source file directly, no export needed yet
  2. Notebook syntax check: catches a syntax error in the student's notebook before it can produce a broken export
  3. Export: nbdev turns the notebook's #| export-tagged cells into real files under trentorch/, following each module's #| default_exp target
  4. Integration tests: runs against the just-exported package, the first point that imports from trentorch rather than the raw source

Only complete actually updates what a student can import; tren module test runs the same checks without exporting.

The CLI itself

platforms/cli/ is split by what it's for, not by file type:

  • cli_platform/: the CLI bootstrapping itself: setup, system maintenance, dev/CI tooling
  • processes/: what a student does once inside the workflow: the module loop, milestones, benchmarks, conversion

The entry point is tren = platforms.cli.main:main (see pyproject.toml), wired up by bin/tren.

CI pipeline

.github/workflows/validate.yml runs the whole curriculum on every push, as seven stages:

StageWhat it checks
1 · Inline BuildBuilds the package from data/src/ progressively, module by module: the maintainer's curriculum-correctness check
2 · Unit TestsPer-module unit tests
3 · IntegrationCross-module integration tests
4 · CLI TestsThe tren CLI's own test suite
5 · E2E TestsEnd-to-end user journey tests
6 · Fresh InstallA Docker-based simulation of a brand-new student cloning and installing from scratch
7 · User JourneyEvery milestone, run against Stage 1's already-built package, then a real tren system reset verified to actually clear state

Stages 2 through 5 and 7 only depend on Stage 1's build artifact, not on each other, so they run in parallel rather than in a chain.

Why the pipeline is fast

As of the 2026-08-27 optimization pass, the full pipeline runs in well under 4 minutes, down from over 8. The short version of how:

  • Found and fixed a real bug, not just a slow spot: completing certain modules during automated curriculum verification was silently triggering a full, unintended milestone run, a correctness bug that happened to also be the single biggest time sink.
  • Matched test scope to what's actually being verified. TrenTorch's Conv2d is deliberately naive (nested Python loops, that's the pedagogical point), so several tests were running it at full MNIST/CIFAR scale just to check output shapes, which don't depend on input size at all. Shrinking those inputs lost no real coverage.
  • Made CLI startup lazy. The CLI was importing every command's dependencies (including NumPy and the framework itself) on every single invocation, regardless of which subcommand actually ran. Deferring those imports to where they're actually used cut CLI startup time by roughly 3x.
  • Right-sized one real training demo under CI. A milestone's default demo trains for 50 epochs to show a convincing curve to a human; CI only needs to confirm it runs end-to-end, so it uses 5 epochs there while a real student still gets the full 50.
  • Ran Stage 1's per-module loop in-process instead of spawning two fresh Python subprocesses per module.

Full detail, fix by fix, is in maintainer_use/CHANGELOG.md.

Where to read next