StepTronOSS is a training framework where the configuration is the interface
A lightweight, AI-native training framework for large language models. Designed for fast iteration, reproducible experiments, and modular configuration across SFT, RLVR, and evaluation workflows.
At a glance
- What is it?
- StepTronOSS is a lightweight framework for large language model training from StepFun, and its central design choice is that experiments are declared as Python config classes rather than as argument soup, validated before they run and inspectable with a cfshow command. It can run with PyTorch as its only dependency, with acceleration kernels added only when you want them.
- Who is it for?
- Adopt StepTronOSS if you are running SFT or evaluation experiments and want them declared, validated and reproducible rather than assembled from command line arguments, since the config layer and the cfshow tool are the substance of the project. Skip it if you need a turnkey production training stack with a stable release, since the package version is 0.0.1, the default branch is dev, and the project status list still has RLVR implementation unchecked.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 50 days ago.
- What is it written in?
- Mainly Python, 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
The configuration is the product
StepTronOSS is described as a lightweight training framework for large-scale language models with a focus on modular configs, reproducible experiments and fast iteration across SFT, RLVR and evaluation workflows.
The key capability is listed first: config-driven experiments with dynamic validation, through cfshow and sanity_check. And the Zen section, which is the framework's statement of its principles, opens with the line that explains the rest: keep configs stateless and let runtime objects carry state.
The Zen section lists four principles. Declare config structure at class level and fill values in __init__. Use Ref("..path") for cross-node linkage. Call sanity_check() and to_dict() for validation and serialization. And keep the configs stateless.
That is a short list, and it is the whole architecture.
The example is what makes it concrete. Before, you have a class whose __init__ takes parameters with defaults. After, the parameters move to a Config subclass declared as class attributes with type annotations, the Config subclass gains a build method that constructs the runtime object from itself, and it can gain a sanity_check method that asserts things about the values.
# Before
class A:
def __init__(self, param_a: int, param_b: float = 1.0):
pass
# After
from configurize import Config
class AConfig(Config):
param_a: int
param_b: float = 1.0
def build(self):
return A(cfg=self)
def sanity_check(self):
super().sanity_check()
assert self.param_b > 0
class A:
def __init__(self, cfg: AConfig):
passSo the runtime class keeps its constructor but takes the config object, and the config object is what the framework reads, validates, serialises and lets you override from the command line.
The payoff is that a config is a data structure rather than a call. It can be inspected, printed, diffed between runs, validated before any GPU time is spent, and linked to other configs with a path reference. The Ref mechanism exists because a multi-node experiment has several configs that need to point at each other, and a path reference expresses that without creating a circular import.
The dependency list shows the config library is external, with configurize pinned at 0.2.0, so the config layer is a separate project that StepTronOSS consumes rather than something it wrote.
cfshow is the tool that makes the config approach work
The cfshow command is what turns a config system from a design idea into something usable day to day, and it does two things.
The first is showing the experiment overview and running the sanity check:
# Overview the experiment config and run sanity_check
uv run cfshow playground/rlvr/qwen3_1p5b_rlvr_math.py
# Inspect a specific subtree (e.g., actor config)
uv run cfshow playground/rlvr/qwen3_1p5b_rlvr_math.py -k actor_model_cfgThe second is inspecting a specific subtree, here the actor model config, with the -k flag. On a framework where an experiment is a tree of configs, being able to ask for one branch of that tree is the difference between a usable tool and a firehose.
The sanity check is the other half. Because the framework calls sanity_check() as part of the config contract, a config can assert invariants about itself, and running that check before a training job starts means a bad configuration is a two-second failure instead of a twenty-minute one after the model has loaded onto the GPUs.
That is a real saving in a cluster environment where a job queue means you wait minutes for anything to start, and where a configuration error that is only discovered after model loading has already occupied the hardware.
The overriding of experiment parameters from the command line follows from the same design, since the config is data:
# Single-task experiments (e.g., SFT)
uv run torchrun playground/sft/your_exp.py
# Multi-task experiments (e.g., RL)
export STEPTRON_MEET_DIR=/path/to/shared
uv run tools/mp_run.py playground/rlvr/qwen3_1p5b_rlvr_math.py
# mp_run is also compatible with single-task experiments
uv run tools/mp_run.py playground/sft/your_exp.py
# Override experiment params (example: enable timer logging)
uv run tools/mp_run.py playground/rlvr/qwen3_1p5b_rlvr_math.py profiler_cfg.timing_log_level=1The last line is the one to note. You pass a dotted path and a value, here profiler_cfg.timing_log_level=1, and that reaches into a nested config and changes one field. There is no argparse definition of that flag anywhere, because the config tree defines the addressable surface.
That is also how the multi-task orchestration is invoked, with the launch tool taking the same config path and the same override syntax, so the difference between a single-task run and a multi-node run is which launcher you call rather than how you describe the experiment.
Multi-node launch is scripts generated from the config
The distributed story is described in two parts, and the first part is the unusual one.
Rather than only offering a launcher, the framework generates per-replica shell scripts based on resource_cfg.task_specs:
# Example: generate scripts under /mnt/entrypoints/<exp_name>/<exp_id>/
uv run tools/build_scripts.py playground/rlvr/qwen3_1p5b_rlvr_math.py /mnt/entrypoints/And the output layout is a directory tree:
/mnt/entrypoints/<exp_name>/<exp_id>/
cpu/
0.sh
gpu/
0.sh
1.sh
...So the config declares what tasks exist, and the tool turns that into numbered scripts per node type. The notes explain the two details that matter. Script indices are cumulative within each node type, so all GPU tasks share a single 0 to N index range. And each script exports task environment variables, including the task-scoped EXP_ID and NNODES, then invokes the command assembled by mp_run. Extra command line arguments are passed through to the experiment, just as with mp_run.py.
The cumulative indexing is the bit worth understanding. If you have three CPU tasks and eight GPU tasks, you get one CPU script numbered 0 and eight GPU scripts numbered 0 through 7, and the numbering is per node type rather than global. That means the scripts for a given node type can be launched together on the machines of that type without renumbering.
The runtime environment for the rendezvous is where Redis comes in. Distributed rendezvous spins up a per-experiment Redis server using a shared filesystem directory. The STEPTRON_MEET_DIR environment variable points at a shared directory visible and writable by all nodes, and that directory stores the rendezvous file which publishes the Redis server port. The CANNOT_BE_REDIS_SERVER=1 variable is set on ranks that must not start Redis, because they will wait for another rank to start it, and the note is that if every rank sets this, rendezvous will eventually time out.
That is a slightly unusual design, using a file in a shared filesystem to bootstrap a Redis instance that then serves as the rendezvous point, but it keeps the number of things you have to open on a cluster down to one shared filesystem and one UDP port.
Redis also appears in the installation instructions, where it is installed alongside the Python dependencies.
Acceleration is opt-in and switched on in one call
The optimisation kernels section is explicitly conditional. It is only needed when you want maximum GPU performance and kernel-level speedups.
Two kernels are named. flash-attn is installed manually with:
uv pip install flash-attn --no-build-isolationand grouped_gemm with:
uv pip install --verbose git+https://github.com/fanshiqing/grouped_gemm@mainThe no-build-isolation flag on flash-attn is the practical detail, since flash-attn compiles a CUDA extension and the isolated build environment does not have the right toolchain or the right torch available.
Then the enabling is a single call:
from steptronoss.utils.optimizable import set_optimization
set_optimization(
default="torch_compile",
AttentionCore="flash-attn",
grouped_gemm="nv_grouped_gemm",
)So the framework ships an optimizable module with a set_optimization function that takes a default and per-module overrides. The default here is torch_compile, so compiling is the baseline and the two specialised kernels are opt-in on top of it.
The important architectural point is that the choice is made in code rather than in the config. The Zen section says the configs are stateless and the runtime objects carry state, and this is an example of that: the optimisation level is a property of the running process, not a field in the experiment configuration, because it determines what gets compiled rather than what gets trained.
The overall dependency story is worth noting against the claim that it runs with only PyTorch. The dependency list includes aiohttp, aioredis, boto3, configurize, diskcache, einops, fastapi, hjson, ijson, loguru, megfile, msgpack and nltk, so the base install pulls in a fair amount, but the acceleration kernels are the part that needs a compiler and a GPU toolchain, and that part is what you add when you need it.
The project also ships a Triton kernel implementation, which is the item checked in the status list.
The status list tells you what is finished
There is a project status list at the end of the documentation, and it is the most useful thing in it for anyone deciding whether to use this.
Checked are SFT experiments, reference configs, eval, and the Triton kernel implementation. The reference configs are named as Qwen3 8B at playground/pretrain/qwen3/qwen3_8.py and Step3.5 Flash at playground/pretrain/step3p5/step3p5_flash.py.
Unchecked is the RLVR implementation.
That single unchecked item is significant, because RLVR is one of the three workflows the framework claims to cover in its opening description. The RLVR example config does appear in the documentation, in every cfshow and mp_run example, so the configuration surface for it exists, but the implementation behind it is marked as not done.
The reference configs are the other item to look at. A reference config for a specific model on a specific architecture is a much better starting point than an empty template, and the fact that there is one for Step3.5 Flash as well as Qwen3 8B suggests the framework is aimed at StepFun's own models as well as the open ones.
The AI native framing is the last section, and it is about the workflow rather than the code. StepTronOSS enables an AI-native workflow, its modular architecture supports easy verification and iterative development, and tools like cfshow provide dynamic config inspection and validation. The repository ships an AGENTS.md to guide agents in contributing to code changes, and the documentation suggests trying a prompt of the form write an exp of qwen3 8B sft, optimizer use muon.
That last example is telling about what the framework is for. Writing an experiment configuration is a structured, well-understood task with a typed address space, which is close to ideal for a coding agent, and the config system is what makes it addressable rather than free-text.
The repository, the tools and the docs
The top-level entries describe a project with a real engineering setup around it.
There is a steptronoss/ directory for the package itself, a playground/ directory for the example experiments including the sft and rlvr directories referenced throughout the documentation, a tools/ directory holding mp_run.py and build_scripts.py, and a benchmarks/ directory. There is a docs/ directory with the launch guide in English and Chinese, the SFT data preparation guide in English and Chinese, and a modules document describing the API.
The site build is mkdocs with a mkdocs.yml at the root, and the README links to the docs directly by file path rather than by rendered link, which means the documentation is browsable on GitHub as well as on the site.
The tooling is a modern Python stack. There is a pyproject.toml with uv and a uv.lock, a tox.ini for the test matrix, a .pre-commit-config.yaml, a Makefile, a Dockerfile and a .devcontainer/ directory. Codecov is configured through a codecov.yaml. The package metadata names the project SteptronOss at version 0.0.1, requires Python 3.10 or newer below 4.0, and lists the classifiers for 3.9 through 3.13. The author is stepfun-ai and the description field still carries the boilerplate from the template it was generated from, which is a small sign of a project that started from a uv project template.
The default branch is dev rather than main, which together with the 0.0.1 version and the unchecked RLVR item says the same thing: this is a framework under active development where the interfaces are still settling.
For that reason the reference configs are the thing to read first, along with the launch guide. A framework at this stage is best learned from what people have already built with it.
Editorial conclusion
Adopt StepTronOSS if you are running SFT or evaluation experiments and want them declared, validated and reproducible rather than assembled from command line arguments, since the config layer and the cfshow tool are the substance of the project. Skip it if you need a turnkey production training stack with a stable release, since the package version is 0.0.1, the default branch is dev, and the project status list still has RLVR implementation unchecked. Verify first that your workload is SFT or evaluation rather than RLVR, that you have Redis available because the distributed rendezvous depends on it, and how much you want to depend on the framework, because the default branch and the pre-1.0 version mean the interfaces are still moving.
Frequently asked questions
What is StepTronOSS and what is its central design idea?
It is a lightweight training framework for large-scale language models with a focus on modular configs, reproducible experiments and fast iteration across SFT, RLVR and evaluation workflows. Its Zen section states the principles: keep configs stateless and let runtime objects carry state, declare config structure at class level and fill values in __init__, use Ref("..path") for cross-node linkage, and call sanity_check() and to_dict() for validation and serialization.
How do I inspect and override an experiment configuration in StepTronOSS?
Use `uv run cfshow` on a config path to see the experiment overview and run the sanity check, and add `-k` with a subtree name such as actor_model_cfg to inspect one branch. To override a value, pass a dotted path and a value to the launcher, for example `profiler_cfg.timing_log_level=1`, and the same override syntax works with tools/mp_run.py for multi-node runs.
Which parts of StepTronOSS are finished?
The project status list marks SFT experiments, reference configs, evaluation and the Triton kernel implementation as done, with reference configs for Qwen3 8B at playground/pretrain/qwen3/qwen3_8.py and Step3.5 Flash at playground/pretrain/step3p5/step3p5_flash.py. The RLVR implementation is the item that is not yet done, even though the framework covers SFT, RLVR and evaluation workflows in its overview.
Official sources
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.
[](https://hysenlabs.com/projects/stepfun-ai-steptronoss)Was this useful?