Repository layout
The local loop
Code style
Formatting is not a matter of taste here, it is a hook..pre-commit-config.yaml is the
enforcement, the pre-commit workflow runs pre-commit run --all-files on every PR, and
you can reproduce it exactly with the same command locally.
Three hooks are Miles-specific bans, each pointing at the API you should use instead:
If a commit legitimately needs an exception, the hooks carry
exclude patterns; extend
those in the same PR rather than disabling a hook.
Beyond formatting, the conventions a reviewer will hold you to live in
.claude/rules/general-code-style.md:
prefer stateless and immutable, keep functions under roughly 100 lines and files under
roughly 1000, initialize derived values once, keep imports at the top, use absolute
imports, prefer keyword arguments where they add clarity. It applies to miles/**/*.py,
scripts/**/*.py, tools/**/*.py, train.py and train_async.py.
What lives in .claude
The .claude directory is how the repo hands its conventions to coding agents, and it is
worth reading even if you never run one, because it is where several rules are written
down exactly once.
.claude/rules/ holds path-scoped conventions. Each file carries a paths: front
matter list, and the rule applies to any file matching it. general-code-style.md is the
one described above. AGENTS.md at the repo root points Codex at the same file, so both
agents and humans review against one document.
.claude/skills/ holds procedures, one directory per skill with a SKILL.md. They
are workflows rather than style rules:
The doc-dev sentinel
Some files are bound to a document. A # doc-dev: line in a file’s own comment syntax is
the opt-in: bare, it binds the file’s own header block; with a repo-relative path, it also
binds that central document. Editing such a file means updating its documentation in the
same change, and editing the document means finding the files that name it.
Grep for
doc-dev: before editing anything under .github/workflows/ or docker/. A
change that lands the code and leaves the document stale is the failure mode this
convention exists to prevent.
Running CI
What a PR runs
Two things start automatically on every PR: thepre-commit workflow, and PR Test
(.github/workflows/pr-test.yml). PR Test resolves a policy and an image, runs the two
CPU stages, and then the GPU stages, which are gated on stage-a-cpu succeeding so a
formatting or import error does not burn GPU time. A PR that touches docker/Dockerfile,
docker/build.py, docker/verify_transformer_engine.py, docker/patch/** or
requirements.txt additionally builds the image first and runs every GPU suite inside it.
Registering a test
Selection is declared in the test file, never in the workflow YAML.- CPU tests go in
tests/fast/. Everytest_*.pythere is auto-registered as a CPU test instage-a-cpuwith no labels, and runs on every PR. Aregister_cuda_ciundertests/fast/is a hard error; move the file totests/fast-gpu/. - Everywhere else, register explicitly. One top-level call per file:
register_cpu_ci allows empty labels for always-on CPU coverage; register_cuda_ci and register_rocm_ci require a non-empty domain-label list. All three also accept nightly=True (nightly, weekly, and release cadence only) and disabled="<reason + issue link>" (reported as skipped rather than deleted). The calls are parsed from the AST, so they must be top-level, literal, and unaliased.
The runner scans tests/fast, tests/fast-gpu, tests/e2e and tests/ci for
test_*.py, and a file outside tests/fast/ with no registration fails collection with
No CI registry found. Suites are stage-<tier>-<gpus>-<hw>; pick the one an existing
test like yours uses, because a typo’d suite has no job and silently never runs.
Verify it actually runs
Enabled N test(s). The command also validates registration
across every discovered test, so it fails here if any file is missing its declaration. Add
--nightly when checking a nightly=True registration. On the PR, the matching stage job
prints the same plan in its Resolve suite plan step.
Labels
Labels are how a PR opts into the expensive matrix. A test’slabels=["megatron"] is
triggered by the GitHub label run-ci-megatron: the workflow forwards the labels, Python
strips the run-ci- prefix and intersects with each test’s list. The canonical set lives
in tests/ci/labels.py, and a value outside it is a collection-time error.
If your fork PR sits waiting for approval, that is GitHub holding first-time contributor
runs; any maintainer-applied
run-ci-* label doubles as the approval.
PR-description CI tags
Three directives are read out of the PR description itself, one per line, matched at the start of a line:
For the two ref directives,
<ref> is a branch or commit, and the shorthand #1234
resolves to refs/pull/1234/head, which is how you test against an unmerged SGLang or
Megatron-LM PR:
workflow_dispatch input wins, then the
PR-description line, then the default. ci-image-tag: has one more rule: on a PR that
built its own image, the fresh pr-<number> tag outranks the directive, so a docker PR
always tests what it just built.
PR conventions
Commit subjects follow conventional commits, under 70 characters, and the body explains why:-
pre-commit run --all-filesis clean. -
pytest tests/fastpasses, plustests/fast-gpuif you have a GPU. - New behavior has a test, registered where CI will find it (verified with
--list-only). - A new flag appears in CLI Reference, and
python3 train.py --helpstill parses. - A change to a
doc-dev:governed file updates its document in the same PR. - The PR description carries the CI directives your change needs.
/run-lint on a PR runs the hooks in CI and pushes the autofixes back to your
branch, which is the quick way out of a red pre-commit job.
Issue triage
Comment to claim an issue before you start. For an infra failure or a flake, file the
issue with the job URL, the runner name, the suite, and the log line, so a maintainer can
map it to a host.
Where to ask
- Quick questions: the
#miles-rlchannel of the SGLang Slack. - Design discussions: a GitHub Discussion, or an Issue labeled
discussion. - CI internals: Stage (stages), Labels (label semantics), Docker build (images), Metric history & regression gate (metric gate), and the CI Contributor Guide for the long-form version of this section.

