config-conventions
Skill2.1k starsChanged 20 days agoApache-2.0View on GitHub
Configuration conventions for NeMo-RL. YAML is the single source of truth for defaults. Covers BaseModel/TypedDict usage, dataclass for internal classes, exemplar YAML updates, and forbidden default patterns.
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 1 is distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 17
Use the right tool for the job.
- Very specific: line 30
Prefer BaseModel for new user-facing config classes, and when converting an existing TypedDict as part of the v1 → v2 migration.
- Very specific: line 38
When in doubt: *is this class populated from a user-edited YAML?* If yes → BaseModel (or legacy TypedDict).
- Very specific: line 60
TypedDict: use typing.NotRequired[...] to mark optional attributes.
- Very specific: line 91
When adding a new config key to a BaseModel or TypedDict subclass, document:
- Very specific: line 102
If a recipe YAML does not have a defaults key, run:
- Very specific: line 112
When accessing a NotRequired field, use an in check or .get(key) / .get(key, None).
- Very specific: line 140
If a NotRequired field is absent, the code should handle that explicitly — not paper over it with a magic default.
- Very specific: line 179
If a config block has a known set of fields, model it as a BaseModel (or, pre-migration, a TypedDict) — do not type it as dict[str, Any] …
- Very specific: line 183
If the block must also pass arbitrary keys through to another system, use BaseModel(extra="allow"): the known fields get types + …
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Configuration Conventions
Core Rule
Defaults must not be scattered at call sites. A default for a config value must live in exactly one place; readers should never have to grep through algo code to discover what value was actually used. Where that one place is depends on the schema type — see "Where Defaults Live" below — but it is never a cfg.get("k", default), a function-parameter default, or a magic constant inside the consumer.
Class Choice: BaseModel vs. dataclass vs. TypedDict
We are gradually migrating the config schema from typing.TypedDict (v1) to pydantic.BaseModel (v2). Both styles coexist in the codebase today, and the migration is tracked by tests/unit/test_config_v2.py against the reference configs in tests/unit/reference_configs/ (these will be removed when the migration is complete).
Use the right tool for the job. v2 (the new convention):
pydantic.BaseModel— v2, user-facing config (the new default). Any class the user touches via YAML — currently the top-levelMasterConfigof each algorithm (grpo,dpo,sft,rm,distillation,eval) and a few shared schemas likeClippedPGLossConfig— is aBaseModeldeclared withextra="allow"so unknown keys don't break older configs:from pydantic import BaseModel class MasterConfig(BaseModel, extra="allow"): policy: PolicyConfig grpo: GRPOConfig ...Prefer
BaseModelfor new user-facing config classes, and when converting an existingTypedDictas part of the v1 → v2 migration.@dataclass— v2, internal classes (not loaded from YAML). For purely in-process data containers — worker metadata, datum specs, internal state passed between Python components — use@dataclass(e.g.nemo_rl/distributed/worker_groups.py,nemo_rl/data/interfaces.py,nemo_rl/data_plane/interfaces.py). Do not useBaseModelorTypedDictfor these — they're not config and shouldn't pretend to be.
v1 (legacy, being migrated away):
typing.TypedDict— v1, legacy / not-yet-migrated user-facing config. Some nested sub-configs are stillTypedDict. Continue to maintain them with the same defaults rules below until they are migrated toBaseModel. Usetyping.NotRequiredto mark optional attributes. Do not add newTypedDict-based config classes.
When in doubt: is this class populated from a user-edited YAML? If yes → BaseModel (or legacy TypedDict). If no → @dataclass.
New code follows v2 directly
Any newly added class must follow the new convention from the start:
- New user-facing config →
pydantic.BaseModel(withextra="allow"when user configs may carry extra/obsolete keys). Do not add newTypedDict-based config classes. - New internal class →
@dataclass.
TypedDict edits should only happen on existing, not-yet-migrated classes — either to extend them or as part of converting them to BaseModel.
Access Config Directly
For required attributes, read the value and assume it is present — don't introduce a fallback at the call site.
- v2 (BaseModel): attribute access —
master_config.policy.precision. The BaseModel class itself supplies any default for the field; the call site reads it as-is. - v1 (TypedDict, omegaconf-loaded dict): key access —
policy_cfg["precision"]. The exemplar YAML supplies the default; the call site reads it as-is.
In both cases, missing required values should fail loudly at load/access time rather than being silently papered over.
Express Optionality
- TypedDict: use
typing.NotRequired[...]to mark optional attributes. - BaseModel: declare the field as
Optional[...] = None(orT | None = None).
Optional attributes may be absent/None; code may check for their presence. Never substitute a non-None default at the access site (see "Accessing NotRequired Fields" below).
Where Defaults Live
The location of defaults depends on the schema type:
v2 —
pydantic.BaseModel(user config): the default lives on the BaseModel field as a Python value. The BaseModel class is the centralized source of truth for user-facing defaults — exemplar YAML serves as documentation / override examples, not as the canonical default store. Example (fromClippedPGLossConfig):class ClippedPGLossConfig(BaseModel, extra="allow"): disable_ppo_ratio: bool = False ratio_clip_min: float = 0.2 ratio_clip_c: Optional[float] = None # None to disable reference_policy_kl_penalty: float = 0.01- v1 —
typing.TypedDict(legacy user config, pre-migration): the default lives only in the exemplar YAML underexamples/configs/*.yaml. There is no class-level default — Python code must read the value from the loaded dict without supplying a fallback. @dataclass(internal class, not loaded from YAML): usually no defaults at all. Fields are populated by the producing code path; a stray= None/field(default=...)is a smell unless there's a clear reason (e.g., forward-compat for an optional field added mid-migration).
In all three cases:
- Exemplar configs under
examples/configs/*.yamlinclude documented defaults. For v1 TypedDict configs they are the source of truth; for v2 BaseModel configs they serve as documentation and reasonable starting points, with the BaseModel class itself being authoritative. - Recipe YAMLs under
examples/configs/recipes/**/*.yamlare runnable snapshots and may omit documentation. - Defaults at call sites (
cfg.get("k", default), function-parameter defaults, magic constants) are never allowed — see "Forbidden Patterns" below.
Documenting New Config Keys
When adding a new config key to a BaseModel or TypedDict subclass, document:
- The key's purpose
- Valid values/types
- Recommended default (if applicable)
Reflect the default in the exemplar YAMLs under examples/configs/*.yaml. If the change affects an exemplar covered by tests/unit/test_config_v2.py, also update the matching tests/unit/reference_configs/*.yaml so the v1→v2 migration check stays green.
Recipe YAMLs Must Set defaults
Recipe YAMLs under examples/configs/recipes/**/*.yaml must set defaults: <exemplar>.yaml to inherit from one of the exemplar configs in examples/configs/*.yaml. This keeps recipes minimal — they only override what differs from the exemplar.
If a recipe YAML does not have a defaults key, run:
uv run ./tools/config_cli.py minimize <recipe.yaml>This will minimize the config and assign the appropriate defaults key.
Accessing NotRequired Fields
When accessing a NotRequired field, use an in check or .get(key) / .get(key, None). Never provide a non-None default — that hides behavior and defeats the purpose of making the field optional.
Do:
# .get() with None (not a hidden default)
stop_properly_penalty_coef = cfg.get("stop_properly_penalty_coef", None)
# Truthiness check for optional booleans
if master_config.grpo.get("skip_reference_policy_logprobs_calculation"):
...
# Nested NotRequired: check presence at each level explicitly
if "megatron_cfg" in policy_config and policy_config["megatron_cfg"]["enabled"]:
...Don't:
# Hidden boolean default — should come from YAML
disable_ppo_ratio = cfg.get("disable_ppo_ratio", False)
# Hidden non-trivial default — caller has no idea True is the fallback
normalize_rewards = grpo_config.get("normalize_rewards", True)
# Chained .get() with hidden defaults at each level
megatron_enabled = config.get("megatron_cfg", {}).get("enabled", False)If a NotRequired field is absent, the code should handle that explicitly — not paper over it with a magic default.
Forbidden Patterns
These are forbidden in both v1 and v2 — they all hide defaults at the call site instead of on the schema.
Don't (any schema type):
# Hidden default at the call site — should be centralized on the BaseModel
# field (v2) or in the exemplar YAML (v1)
precision = policy_cfg.get("precision", "bfloat16")
# Function parameter defaulting a config value
def build_policy(policy_cfg, precision: str = "bfloat16"):
...Do — v2 (BaseModel):
class PolicyConfig(BaseModel, extra="allow"):
# The BaseModel field is the centralized source of truth for the default
precision: str = "bfloat16"
# Call site reads the attribute directly
precision = master_config.policy.precisionDo — v1 (TypedDict, still dict-shaped after omegaconf load):
# Required attribute: expect it from the (exemplar or user) YAML, no fallback
precision: str = policy_cfg["precision"]
# Optional (NotRequired) attribute: check for presence, never invent a default
if "milestones" in scheduler_cfg:
configure_milestones(scheduler_cfg["milestones"])Avoid dict[str, Any] for Known-Field Config
If a config block has a known set of fields, model it as a BaseModel (or, pre-migration, a TypedDict) —
do not type it as dict[str, Any] and read keys with .get(k, default). A bare dict[str, Any] both loses
type-safety and pushes per-key defaults to the call site (the Forbidden Pattern above).
If the block must also pass arbitrary keys through to another system, use BaseModel(extra="allow"): the known
fields get types + centralized defaults, and unknown keys still come through (model_extra).
Don't:
class NonColocatedTeachersConfig(BaseModel, extra="allow"):
default_teacher_cfg: dict[str, Any] = Field(default_factory=dict) # known fields hidden behind Any
# ...so defaults end up scattered at the call site:
tp = cfg.get("tensor_model_parallel_size", 1)
precision = cfg.get("precision", "bf16")Do:
class TeacherResourceConfig(BaseModel, extra="allow"): # extra="allow" keeps the passthrough escape hatch
tensor_model_parallel_size: int = 1
precision: str = "bf16"
micro_batch_size: int = 4
# ...
class NonColocatedTeachersConfig(BaseModel, extra="allow"):
default_teacher_cfg: TeacherResourceConfig = Field(default_factory=TeacherResourceConfig)See also: @docs/design-docs/design-and-philosophy.md (Configuration Schema: BaseModel, dataclass, and TypedDict section).
Trending
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Who's talking about NVIDIA-NeMo/RL
- vllm-project/vllm“[RFC]: Native Weight Syncing APIs”GitHub · Jan 7, 2026 · 14 reactions
- @sungkim.bsky.social“Nvidia has open-sourced the Llama-Nemotron-Super-V1.5 post-training Synthetic Data: …”Bluesky · Jul 31, 2025 · 4 likes
- vllm-project/vllm“[Bug]: Accuracy Discrepancy in Qwen-7B-Chat Evaluation: vLLM Logprobs Differ from SGLANG, Impacting …”GitHub · Jun 25, 2025 · 3 reactions
- huggingface/trl“Async-GRPO: Decouple rollout generation and reward computation/model update for faster training”GitHub · Nov 27, 2025 · 2 reactions
- Alvorecer721/Nemo-RL“fix(data): eval-path processors render a duplicated default system block (two chat-template calls)”GitHub · Sep 17, 2026 · 1 reactions
The biggest 5 of 52 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 52
Talked about on GitHub and Bluesky (52 times).
On GitHub · 50
- Jan 7, 2026[RFC]: Native Weight Syncing APIs — vllm-project/vllm14 reactions · 11 comments
- Jun 25, 2025[Bug]: Accuracy Discrepancy in Qwen-7B-Chat Evaluation: vLLM Logprobs Differ from SGLANG, Impacting Performance — vllm-project/vllm3 reactions · 7 comments
- Nov 27, 2025Async-GRPO: Decouple rollout generation and reward computation/model update for faster training — huggingface/trl2 reactions · 3 comments
- Sep 17, 2026fix(data): eval-path processors render a duplicated default system block (two chat-template calls) — Alvorecer721/Nemo-RL1 reaction
- Jul 15, 2026docs(rl): add ModelExpress weight refit guide — ai-dynamo/dynamo1 reaction · 1 comment
45 more on GitHub
- Jul 9, 2026[roadmap] verl 26Q3 roadmap — verl-project/verl1 reaction · 5 comments
- Jan 8, 2026[Feat][RL][1/2] Native Weight Syncing API: NCCL — vllm-project/vllm1 reaction · 23 comments
- Oct 29, 2026feat: support FP32 LM-head output for NeMo RL / vLLM parity — NVIDIA-NeMo/Automodel0 reactions
- Oct 29, 2026Track softmax collapse and cancellation fixes in logprobs and losses — swiss-ai/Nemo-RL0 reactions
- Oct 27, 2026Support DAPO in async GRPO training — swiss-ai/Nemo-RL0 reactions · 1 comment
- Oct 25, 2026feat: preserve score heads — NVIDIA-NeMo/Gym0 reactions · 4 comments
- Oct 20, 2026Fix potential positional embedding tensor reuse for train/rollout 0-mismatch RL — NVIDIA/Megatron-LM0 reactions · 19 comments
- Oct 15, 2026feat(speechlm): support native RL checkpoints and frozen CTC export — NVIDIA-NeMo/Speech0 reactions · 20 comments
- Oct 15, 2026feat(audio): align ASR scoring and support explicit Ray launches — NVIDIA-NeMo/Skills0 reactions · 1 comment
- Oct 15, 2026feat(freezing): select exact parameters with FreezeConfig — NVIDIA-NeMo/Automodel0 reactions · 10 comments
- Oct 14, 2026fix(inference): support batch-invariant Mamba prefix caching — NVIDIA/Megatron-LM0 reactions · 7 comments
- Oct 11, 2026Latest 20 Papers - October 12, 2026 — xllm-io/daily-papers0 reactions
- Oct 8, 2026Latest 20 Papers - October 09, 2026 — xllm-io/daily-papers0 reactions
- Oct 8, 2026No VLLM DP path for EP>1 — swiss-ai/Nemo-RL0 reactions · 1 comment
- Oct 7, 2026Latest 20 Papers - October 08, 2026 — xllm-io/daily-papers0 reactions
- Oct 7, 2026Latest 15 Papers - October 08, 2026 — Hdksg10/DailyArxiv0 reactions
- Oct 7, 2026Support exporting MXFP8 values and scales from TE quantized tensors — NVIDIA/TransformerEngine0 reactions
- Oct 7, 2026Latest 15 Papers - October 07, 2026 — Ponkux/DailyArXiv-cp0 reactions
- Oct 7, 2026Latest 15 Papers - October 07, 2026 — ever-xing/DailyArXiv0 reactions
- Oct 2, 2026feat(swe): forward per-rollout sampling seeds to OpenHands — NVIDIA-NeMo/Gym0 reactions · 1 comment
- Oct 2, 2026feat: support episode-derived NeMo Gym request seeds — sdevare-nv/nv-OpenHands0 reactions
- Sep 28, 2026pjin/main-dev-20260928 — NVIDIA-NeMo/Gym0 reactions · 1 comment
- Sep 23, 2026feat(token-capture): add direct ledger manifest reader — NVIDIA-NeMo/Gym0 reactions · 1 comment
- Sep 22, 2026fix(peft): expose gather_output on output-layer substitutes — NVIDIA-NeMo/Megatron-Bridge0 reactions · 1 comment
- Sep 17, 2026Support vLLM version 0.29.0 — NVIDIA-NeMo/Gym0 reactions
- Sep 15, 2026feat(checkpoint): prefix token level recovery — NVIDIA-NeMo/Gym0 reactions · 1 comment
- Sep 13, 2026feat(checkpoint): add durable turn-level rollout recovery — NVIDIA-NeMo/Gym0 reactions · 1 comment
- Sep 10, 2026perf(data-plane): avoid local batch copies — rohitrango/NeMo-RL0 reactions · 2 comments
- Sep 4, 2026LLM Post training - Question regarding seq-mask-tis and global_valid_toks denominator scaling. — mlcommons/training0 reactions · 4 comments
- Sep 1, 2026decouple force_on_policy_ratio from step0 reforward. — google/tunix0 reactions · 1 comment
- Aug 26, 2026chore(customizer): enable configuring grpo hyperparams — NVIDIA-NeMo/nemo-helix0 reactions · 2 comments
- Aug 24, 2026fix(llm): preserve nvext through tool-call jail — ai-dynamo/dynamo0 reactions · 7 comments
- Aug 24, 2026Batch invariant nvls — NVIDIA/Megatron-LM0 reactions · 4 comments
- Aug 13, 2026[bug] nonlearnable params exist on different device than learnable parameters — NVIDIA-NeMo/Megatron-Bridge0 reactions · 5 comments
- Aug 10, 2026fold_weight crashes with AttributeError: 'NoneType' object has no attribute 'data' on Megatron models with tied word embeddings — NVIDIA/Model-Optimizer0 reactions · 1 comment
- Aug 4, 2026default port range to the 5000-5999 band — NVIDIA-NeMo/Gym0 reactions · 1 comment
- Aug 4, 2026nemo-gym / nemo-rl をライブラリレジストリに登録する — airas-org/airas0 reactions
- Jul 31, 2026Async colo upstreaming candidates — anlthms/RL0 reactions
- Jul 30, 2026[VDR][v0.5.0] Tutorials fail when followed verbatim — NVIDIA-NeMo/Gym0 reactions
- Jul 28, 2026test(vllm): cover upstream token metadata fast path — NVIDIA-NeMo/Gym0 reactions · 1 comment
- Jul 22, 2026NeMoRL: Container & Examples — eth-cscs/alps-extended-images0 reactions
- Jul 16, 2026Investigate torch.compile numerical differences between grad and no-grad RMSNorm forward passes — NVIDIA-NeMo/Automodel0 reactions · 1 comment
- Jul 13, 2026Support agentic training for SWE with TRTLLM rollout — hchings/RL0 reactions
- Jul 8, 2026fix: deterministic implementation of _float32_rms_norm_fwd — NVIDIA-NeMo/Automodel0 reactions · 6 comments
- Jun 10, 2026Nemotron Super RL is using Nano Parser — NVIDIA-NeMo/Nemotron0 reactions
On Bluesky · 2
- Jul 31, 2025Nvidia has open-sourced the Llama-Nemotron-Super-V1.5 post-training Synthetic Data: huggingface.co/datasets/nvi... Human Data:… — @sungkim.bsky.social4 likes and reposts
- Aug 23, 2025📦 NVIDIA-NeMo / RL ⭐ 683 (+3) 🗒 Python Scalable toolkit for efficient model reinforcement — @github-trending.bsky.social1 likes and repost
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- leroyguillaume/claude★ 7same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository21 other files it gives its agents.
- AGENTS.mdAGENTS.md
- build-and-dependencySkill
- cicdSkill
- contributingSkill
- copyrightSkill
- cp-to-mainSkill
- cp-to-releaseSkill
- error-handlingSkill
- launch-nemo-rlSkill
- linting-and-formattingSkill
- nemo-rl-auto-researchSkill
- nemo-rl-brev-etiquetteSkill
- nemo-rl-docsSkill
- nemo-rl-session-memorySkill
- pr-html-concise-publicSkill
- removing-outdated-configSkill
- review-prSkill
- review-pr-teamSkill
- review-pr-team-verify-followupSkill
- review-pr-team-with-htmlSkill
- testingSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

