Open-source project
trane-project/trane avatar
trane-project/trane

Trane: a Rust scheduler that practices hierarchical skills from plain-text courses

A deliberate practice engine for mastering complex skills

848 stars17 forksRustAGPL-3.0

At a glance

What is it?
Trane is a Rust library for deliberate practice that selects exercises from an infinite stream using the student's own mastery scores over a graph of dependent skills. It suits engineers who want to build or share a course for a complex craft, and its AGPL-3.0 licence and self-scored workflow narrow who can adopt it.
Who is it for?
Trane fits Rust developers who want to encode a craft with real prerequisites, share it as plain text, and let the scheduler decide what to drill next rather than tracking flashcards by hand. It does not fit anyone who needs objective grading, who does not want to write course files, or who cannot accept AGPL-3.0 terms in a closed product.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Exercise selection runs on the student's own mastery scores

Trane's core idea is that the learner rates themselves. The README describes the loop plainly: Trane shows the student an exercise they can practise, then asks them to score it based on their mastery of the skill the exercise tests. That score, not a fixed review interval alone, is what drives the system.

The two modules that implement this are named in the code tour. The `scorer` module defines how an exercise is scored based on the scores and timestamps of previous trials, and the `scheduler` module contains the logic for choosing which exercises to present next, described in the README as the core of Trane's logic. The `practice_stats` module stores the student's progress for later use by the scheduler, and the `review_list` module holds exercises the student wants to return to at a later time.

So the data flow is a feedback loop rather than a fixed deck. Exercises come from an infinite stream, the learner rates what they just did, the scorer weighs that rating together with when earlier trials happened, and the scheduler picks the next item. The `data` module holds the supporting structures, including student scores and exercise trials, and the filters that narrow down the units from which exercises are drawn.

The consequence for a user is that the quality of the output depends on the honesty and calibration of the self-scores. Nothing in the README describes an objective grader, so a student who rates everything as mastered collapses the pacing.

The dependency graph is what makes hierarchical skills possible

Most spaced repetition tools treat items as independent. Trane's design treats them as a graph. The `graph` module contains the definition of the graph of units and their dependencies that is traversed as a student makes progress, and the `data` module defines courses, lessons and exercises together with how their content and dependencies relate.

The README grounds this in the case that motivated the project. It was originally envisioned for practising jazz improvisation, and it describes a master improviser developing mastery over interconnected skills, citing breathing control, aural training and fine motor skills as separate abilities that together produce a distinct sound. Trane is built so students can express those relationships and let the system act on them.

The scheduling consequences are stated as well. New skills enter automatically once the skills they depend on have been sufficiently mastered, and skills that have already been practised are reinforced periodically. The `blacklist` module offers an escape hatch, defining units that should be ignored and marked as mastered during exercise scheduling, which is what you would use for material a student has covered elsewhere.

That graph is also the main authoring burden. A course that lists exercises without declaring dependencies degrades to a flat review queue, and the scheduler has nothing to unlock or gate.

Courses are plain text, progress lives in SQLite

The content format is deliberately boring, and that is the point. The README says Trane primarily works via plain-text files that are easily sharable and extendable, which lets students create their own material, use material created by others, and combine the two. A course is something you can read, diff, and put under version control, not a binary blob in a proprietary database.

The `course_library` module defines how a collection of courses gathered by a student is written and read to and from storage, and the `filter_manager` module saves and loads filters for later use, for example a filter to study only exercises for the guitar. The `course_builder` module provides utilities for making courses easier to build.

Progress is stored differently. The dependency list in `Cargo.toml` includes `rusqlite` with the `bundled` feature, `rusqlite_migration` for schema changes, `postcard` for binary encoding, and `vfs` with an `embedded-fs` feature, which points to a virtual filesystem layer for locating course files. `serde_json` and `serde` handle the serialisation side, and `noyalib` with a `compat-serde-yaml` feature suggests YAML compatibility for course files. The `Makefile` benchmark targets confirm the split, since they point at a `--library-dir` under `tests/` rather than at bundled course data.

`lib.rs` is the public API of the crate and the entry point for using it.

Adding the crate and the checks the project expects of a change

The README does not carry an installation snippet. It points to the quick start guide on the official project site and to a Tour of Trane video, and the badges link the crate to crates.io and the API documentation to docs.rs. The `Cargo.toml` gives the coordinates and the shape of the package:

toml
[package]
name = "trane"
version = "0.34.1"
edition = "2024"
description = "An automated system for learning complex skills"
license = "AGPL-3.0-or-later"

The crate is added as a normal Cargo dependency, and the entry point for using it is the public API defined in `lib.rs`. The README also documents a course authoring side, with the `course_builder` module offered to make building courses easier.

The `Makefile` in the repository root defines the checks that the project itself relies on, including formatting, clippy with warnings denied, and documentation builds that treat a missing doc comment as an error:

bash
lint:
	cargo fmt
	cargo clippy --all-targets --all-features -- -D warnings

The same file defines a `test` target that runs the suite in release mode, and two benchmark targets, `benchmark-small` and `benchmark-large`, that run a `trane-benchmark` binary against a library directory under `tests/` and name a specific advanced course path. Those benchmark invocations are also the clearest concrete example of how a course is addressed, as a path of lesson names such as `trane::music::improvise_for_real::jam_tracks::4::g_flat`.

Pacing rules that avoid both boredom and frustration

The README lists the principles Trane is built on: spaced repetition, mastery learning, interleaving and chunking. What matters is that the library applies them rather than merely citing them.

The clearest application is the constraint on difficulty. Trane makes sure that not too many very easy or very hard exercises are shown, to avoid both extremes of frustration and boredom. That is a scheduler policy, not a course authoring rule, so a course author does not have to hand-tune the sequence.

Reinforcement is also automatic. Skills that have already been practised come back periodically, and new skills are included once their dependencies are sufficiently mastered. The README compares the experience to grinding through a video game skill tree, then says the point of Trane is to allow that process to be applied to arbitrary skills rather than to game content.

The dependencies also pull in a wider toolchain. `rayon` is listed among the dependencies, which suggests the selection work is parallelised, and `parking_lot` with hardware lock elision is used for locking. `clap` with the derive feature handles command line arguments, `chrono` with serde support provides timestamps, and `ustr` with serde support handles string storage. The scheduler is doing per-trial date arithmetic and graph traversal on every selection.

Where Trane is the wrong tool

Three limits deserve a direct look.

The first is that scoring is manual. Trane asks the student to score each exercise, so the system cannot run unattended and cannot verify an answer. A skill with an objective right answer, a language exercise with unit tests or a musical interval drill with a reference tone, would need a different grading mechanism that the README does not describe.

The second is that the content is the author's job. The repository entries at the top level are a `src/` directory, a `tests/` directory, a `Makefile`, an `improvement_plan.md` and a `CONTRIBUTING.md`, and the `Cargo.toml` describes the package as a library, with the benchmark targets pointing at course directories under `tests/`. Courses are plain-text files that students create or take from others, so a new user has to either author a course or find one before the scheduler has anything to schedule.

The third is language. This is a Rust crate written for edition 2024, with its API exposed through `lib.rs` and the module layout the README documents. A web application or a mobile app cannot call it directly, and the project does not describe a service or wire protocol in the README, so wrapping it means writing a bridge.

The licence compounds the practical limit. The project is AGPL-3.0-or-later, and the README itself notes the library is used to build *Pictures Are For Babies*, a literacy tutor sold by subscription. Linking an AGPL library into a closed service carries obligations that a permissive licence would avoid, and that question needs a lawyer rather than a README.

How Trane differs from Anki style scheduling

The README positions Trane against Anki directly, calling out the difference as the main one between the two. Anki is named as software that already uses some of the same learning principles, so the shared ground is spaced repetition and the like. The claimed difference is the handling of complex and hierarchical skills, which the README presents as the feature at the core of Trane.

In practice the two models diverge at the point of what gets scheduled. A deck-oriented system works with a set of items whose relationships are mostly temporal, one item reviewed after another. Trane works over a graph where an item can be a prerequisite for another, which means a single mastered exercise can unlock several others, and a single badly rated exercise can hold a whole branch back. The `blacklist` and `filter_manager` modules add a course-level layer on top, marking known units as mastered and narrowing the pool to a subset.

Neither approach is strictly better. Deck scheduling is easier to set up and works well for vocabulary lists and facts with no ordering between them. Trane pays for its extra structure with an authoring cost: dependencies have to be declared, otherwise the hierarchy the scheduler is designed to exploit does not exist.

Fast release cadence on a 0.x line, with an AGPL-3.0 licence

The repository is not archived and the last push was on 2026-09-11. The recent releases are v0.34.1 on 2026-09-11, v0.34.0 on 2026-09-02 and v0.33.0 on 2026-09-01, so the project is shipping small version increments close together rather than a slow trickle. That is good for fixing content format and scheduling bugs, and it is a warning about API stability, since a 0.x crate makes no promise that a public interface stays put between minor versions.

The `Cargo.toml` also shows a serious toolchain: edition 2024 with a current dependency set, and a lint configuration that names a `coverage` cfg check, which indicates coverage instrumentation is a known build variant. The repository includes a `Makefile` with dedicated benchmark targets, so performance work on the scheduler is part of the project's own workflow rather than an afterthought.

The licence is AGPL-3.0-or-later, and it is worth being clear about what that means without giving legal advice. The strong copyleft reach of the AGPL matters most for network use, since the obligations attach to modified versions offered over a network. A team embedding the library in a distributed or hosted product needs to read the licence text and decide, while a team using it as a learning tool locally has a much easier question. The README notes the project is supported by subscriptions to *Pictures Are For Babies*, and the Lite version is described as free with the first 200 lessons, which shows one commercial arrangement built on top of the library.

Editorial conclusion

Trane fits Rust developers who want to encode a craft with real prerequisites, share it as plain text, and let the scheduler decide what to drill next rather than tracking flashcards by hand. It does not fit anyone who needs objective grading, who does not want to write course files, or who cannot accept AGPL-3.0 terms in a closed product. Before adopting, read the quick start guide linked from the README, check that your course expresses skills as a dependency graph rather than a flat list, and confirm that the pinned crate version 0.34.1 still matches the API you build against, since the project is still on a 0.x line.

Frequently asked questions

How do I install and start using the Trane library?

The README carries no install command, it links to the quick start guide on the project site and to the API docs on docs.rs. The crate is published as trane on crates.io at version 0.34.1, with lib.rs defining the public API used by an application.

Does Trane come with any courses or lesson content?

The README describes Trane as working via plain-text files that are easily sharable and extendable, and the Makefile benchmark targets point at library directories under tests/. Courses are therefore something a student creates or obtains from others rather than a bundled set.

How does Trane decide which exercise to show next?

The scheduler module holds the selection logic, and it works from the student scores and trial timestamps that the scorer module computes and practice_stats stores. The README states that the system avoids showing too many very easy or very hard exercises and periodically reinforces already practised skills.

What licence does Trane use and can I use it in a closed source product?

The package licence is AGPL-3.0-or-later, as stated in Cargo.toml and in the README. The AGPL carries network copyleft obligations for modified versions, so whether it fits a closed product depends on how the library is distributed and should be checked against the licence text.

Official sources

  1. Issues
  2. License: AGPL-3.0
  3. README
  4. Releases
  5. trane-project/trane on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/trane-project-trane.svg)](https://hysenlabs.com/projects/trane-project-trane)

Was this useful?