Skip to content

Configuration reference

One YAML file drives every stage of the pipeline. The schema lives in sommelier/config.py as pydantic models with extra="forbid" on every section, so an unknown or misspelled key anywhere in the file is a ConfigError (SOM201, exit 2), never a silently ignored setting. This page lists every field, its type, its default in code, and what it controls.

Three rules apply before any field is read:

  • Duplicate YAML keys are rejected. PyYAML would normally let the last duplicate silently replace earlier values. Sommelier fails with ConfigError instead, at any mapping depth, before schema or secret validation can observe an overwritten document.
  • Secrets are rejected. load_config scans both the raw YAML and the validated dump for secret-shaped values and sensitive key names. A hit raises SecurityPolicyError (SOM006, exit 5), because config files end up inside published artifacts. Patterns and allowlists are in Security.
  • artifact_root must stay relative and contained. Absolute paths and any .. component fail schema validation. Before a command uses the path, it resolves the configured root against the config directory and rejects symlinks that escape it. A checkout can move without editing the config, and a configured output cannot be aimed outside it by accident. The explicit release preflight --artifact-root override is a separate operator-selected scan target and may intentionally live elsewhere.
  • The resolved config is an artifact. Every run writes the validated config back out as config.resolved.yaml at the run root and records its SHA-256 digest as config_sha256 in every stage manifest and evaluation report. The comparison gate refuses to compare two evaluation reports unless they carry the same digest. Editing one field between the base eval and the adapter eval does not skew the numbers; it prevents the report from existing.

To validate a file without running anything:

uv run sommelier config validate --config examples/config.smoke.yaml

Add --write-resolved <dir> to also write config.resolved.yaml and inspect exactly what a run would record. See the CLI reference for the full command surface.

Why so many fields are pinned

Several fields are typed as a Literal with exactly one allowed value: data.dedupe_key, formatting.template_policy, formatting.target_format, train.scheduler, train.quantization, train.compute_dtype, eval.split, and eval.parser_version. These are the parts of the reference contract that the published evidence depends on. Pinning them in the type system means loosening one is a code change reviewed in the open, not a config edit that quietly changes what the numbers mean while the file still looks like a Sommelier config. The reasoning per field is in Design decisions.

Top level

The file must start with the schema declaration:

schema_version: sommelier.config.v2
Field Type Default Meaning
schema_version "sommelier.config.v2" required Identifies the config schema. Any other value fails validation, with one exception below.

Every section below is required except tracking, which defaults to disabled when omitted.

A file declaring sommelier.config.v1 still loads. The loader upgrades it in memory and emits a DeprecationWarning: the single dataset section becomes the one en entry under datasets, and train.languages and eval.slices resolve to English only. The resolved config written into the run directory is always the v2 form, so two runs of the same settings produce the same config_sha256 whether the file on disk was v1 or v2.

project

Field Type Default Meaning
name str required A label for the configuration. It travels in config.resolved.yaml; no stage branches on it.
artifact_root Path required Root directory for all run artifacts, relative to and resolved inside the config file's directory. Absolute paths, parent traversal, and escaping symlinks are rejected.
seed int 42 The single seed for the whole run: split shuffling in data prepare, the trainer seed in training, and the seed field recorded in manifests and reports.

model

Field Type Default Meaning
base_model_id str required Hugging Face model id of the base model, e.g. nvidia/Llama-3.1-Nemotron-Nano-8B-v1.
base_model_revision str required Revision to load model weights from. Required so the run records what it actually used.
tokenizer_revision str required Revision to load the tokenizer (and its chat template) from. Pinned separately because the prompt rendering depends on it.
allow_remote_code bool false Passed as trust_remote_code everywhere the tokenizer or model is loaded (formatting, evaluation, training).
remote_code_reason str \| null null Required whenever allow_remote_code is true; validation fails without it.

The allow_remote_code and remote_code_reason coupling exists so that executing repository code from the Hub is never a one-character change. Turning it on forces you to write down why, and the reason ships inside the resolved config with everything else.

datasets

A non-empty list of per-language dataset sources. Each entry:

Field Type Default Meaning
language str required Two-letter lowercase ISO 639-1 code (en, fr, he). At most one source per language.
dataset_id str required Source dataset id, e.g. Salesforce/xlam-function-calling-60k.
dataset_revision str required Dataset revision; stamped into every prepared example as source_revision.
query_column str "query" Column holding the user query, read when raw rows are exported from the source dataset.
tools_column str "tools" Column holding the tool schemas as a JSON string.
answers_column str "answers" Column holding the gold tool calls as a JSON string.
source_id_column str \| null null When set, names the source-dataset column holding the root row reference; like the other column fields it is read when raw rows are exported, mapping into the canonical source_example_id raw-row field. When null, this is the root source.

Exactly one source must omit source_id_column: the root source, which gets independent split assignment during data prepare. Every other source is paired, row by row, to root rows through the column this field names. The pairing exists so that a translated variant of a query can never land in a different split than its original, which would leak test content into training. How prepare enforces this is described in Data policy.

For a remote full run, every paired source must use an exact 40- or 64-character Hugging Face dataset commit. A Hebrew publication must contain the paired rows plus the translation summary, locked semantic-review template, finalized review, and publication manifest that bind those rows. main, a tag, or a direct translation-run staging override is rejected before preparation. Smoke runs may stage a matching diagnostic translation instead.

data

Field Type Default Meaning
n_train int 15000 Training split size.
n_validation int 1000 Validation split size.
n_test int 1000 Held-out test split size; the only split evaluation reads.
min_query_chars int 10 Rows with shorter queries are dropped (reason query_too_short).
max_query_chars int 2000 Rows with longer queries are dropped (reason query_too_long).
dedupe_key "normalized_query" pinned Deduplication key: the SHA-256 of the query after casefolding, stripping, and whitespace collapsing. Duplicates drop with reason duplicate_query.

One model-level validator guards this section: the three split counts must be positive, min_query_chars must be positive, and max_query_chars must be strictly greater than min_query_chars. If the surviving rows cannot fill n_train + n_validation + n_test, data prepare fails rather than shrinking a split. The full drop-reason taxonomy is in Data policy.

formatting

Field Type Default Meaning
system_prompt str required Prepended to the system message, followed by the canonical JSON of the available tools.
template_policy "tokenizer_chat_template" pinned Prompts are rendered by the tokenizer's own chat template, never by a hand-rolled format string.
target_format "json_tool_call" pinned The training target is the canonical JSON of the gold call and nothing else.

train

Field Type Default Meaning
epochs int 2 Training epochs over the train split.
per_device_batch_size int 8 Per-device micro-batch size.
gradient_accumulation_steps int 2 Accumulation steps; effective batch is the product of the two.
learning_rate float 2e-4 Peak learning rate.
scheduler "cosine" pinned Learning rate schedule.
warmup_ratio float 0.03 Fraction of steps spent warming up.
max_sequence_length int 2048 Token budget per rendered example. Truncation that would remove every target token is an error, never a silent trim.
quantization "nf4-4bit" pinned Base model quantization for QLoRA.
compute_dtype "bfloat16" pinned Compute dtype during training.
lora_rank int 16 LoRA rank.
lora_alpha int 32 LoRA alpha.
lora_dropout float 0.05 LoRA dropout.
target_modules list[str] required Projection modules the adapter attaches to. No default: the choice is model-specific and belongs in the record.
languages list[str] all configured Languages whose examples feed training. Empty or omitted resolves to every language under datasets, in configuration order; the resolved config always records the explicit list. Every entry must name a configured source.

None of these are ever adjusted at runtime. If training runs out of GPU memory, the failure is a ResourceError whose hint quotes your current per_device_batch_size, gradient_accumulation_steps, max_sequence_length, and remote.gpu and tells you to change one of them yourself. See Training and Errors.

eval

Field Type Default Meaning
split "test" pinned Evaluation only ever reads the held-out test split.
slices list[str] ["en"] Language slices to evaluate. Every entry must name a configured source under datasets; duplicates are rejected.
temperature float 0.0 Must be exactly 0.0 at run time; anything else raises EvaluationError.
do_sample bool false Must be false at run time; true raises EvaluationError.
max_new_tokens int 512 Generation budget per prompt. Must be positive.
parser_version "sommelier.parser.v1" pinned The parser identity recorded in every report; one of the fields the comparison gate matches on.

temperature and do_sample are plain types rather than Literals because their values are recorded in the decoding block of every evaluation report, which the comparison gate checks field by field. The eval stage still refuses to run with non-deterministic settings; it errors instead of coercing, so the config you wrote is always the config that ran.

remote

Field Type Default Meaning
enabled bool true Declares that this config targets remote execution. The current wrapper reads the GPU and planning estimates from this section but does not branch on this flag.
gpu str required Modal GPU type, e.g. A10G or L40S. Recorded in runtime metadata and quoted in out-of-memory hints.
data_timeout_seconds int 1800 Legacy-named planning estimate for data/format/tokenization; not an enforced stage deadline.
train_timeout_seconds int 14400 Legacy-named planning estimate for training; not an enforced stage deadline. A dependency-reported timeout may quote it for context.
eval_timeout_seconds int 7200 Legacy-named planning estimate for each evaluation arm; not an enforced stage deadline. The admission sum counts both arms.

The three names are retained for config compatibility. The current pipeline is one remote function: it installs no data, train, or eval watchdog. Instead, the driver sums the estimates into an outer-timeout admission floor: data + train + 2 × eval, or data + 2 × eval when evaluating an external adapter. A stage may exceed its estimate and continue as long as the provider-enforced outer function timeout has not expired. The English-only default full estimate totals 45,000 seconds; the Hebrew full estimate totals 81,000 seconds. Their documented launches use the provider maximum of 86,400 seconds. The driver rejects an outer timeout below the applicable planning sum or above the provider limit before loading data or models. Runtime metadata records per_stage_watchdogs_enforced: false so downstream reports cannot mistake the estimates for observed deadlines. Details are in Remote execution.

report

Field Type Default Meaning
retain_raw_generations bool true Declared in the schema; the v1 pipeline always writes raw generations regardless, because the evidence requires them.
redact_fields list[str] [] Key names to replace with [redacted] anywhere in the evaluation and comparison reports before they are written.

tracking

The only optional section. Omitting it is equivalent to writing enabled: false.

Field Type Default Meaning
enabled bool false Opt-in experiment tracking. Disabled is a strict no-op; nothing is imported.
provider "wandb" pinned The only supported provider. Enabling it without wandb installed is an ExternalDependencyError.
project str "sommelier" Tracking project name. The run URL, when one exists, is recorded in the run manifest.

The example configs

Runnable English-only smoke/full defaults plus a Hebrew v3 smoke/full pair ship in examples/, plus config.invalid.yaml, which exists to demonstrate a validation failure (n_train: -100). All four use the Nemotron-Nano-8B base, immutable base/tokenizer/root identities, seed 42, the same tool-calling prompt, QLoRA objective, and target modules. The v3 pair adds a Hebrew paired source, tokenizer-cost evidence, and the following full-run budgets:

Setting config.smoke.yaml config.full.yaml
Purpose Prove the chain end to end, cheaply Runnable English-only v1/default full run
Languages / eval slices en / en en / en
Splits (train/val/test) 100 / 20 / 20 15,000 / 1,000 / 1,000
Epochs 1 2
Batch · accumulation 2 · 1 4 · 4 (effective batch 16)
max_sequence_length 2048 4096
LoRA rank · alpha 8 · 16 16 · 32
eval.max_new_tokens 256 512
GPU A10G L40S
Planning estimates (data/train/each eval) 900 / 3600 / 1800 s 1800 / 28800 / 7200 s
Outer admission floor from estimates 8,100 s 45,000 s; documented launch at 86,400 s
tracking section omitted (disabled by default) explicit, disabled

config.full.yaml is the current runnable English-only default. It preserves the published reference run's scale and QLoRA/evaluation settings while pinning immutable base, tokenizer, and root-dataset revisions; any new launch receives its own run identity. The published run's resolved config and checksummed split/report artifacts remain the authority for the historical numbers.

The French v2 result is deliberately not encoded in this default. Its historical paired-dataset commit has a v1 translation summary and no current publication manifest, so strict reproduction under the current full-run contract is unavailable until a provenance-complete immutable republish exists. A future French full config must pin that new commit. Start English changes from config.smoke.yaml or config.full.yaml, and paired Hebrew work from the v3 pair.

Setting config.v3-he-smoke.yaml config.v3-he-full.yaml
Purpose Diagnostic bilingual wiring only Preregistered Hebrew evidence run
Splits (train/val/test) 100 / 20 / 20 15,000 / 1,000 / 1,000
Epochs 1 2
Sequence budget 2,048 4,096
GPU A10G L40S
Planning estimates (data/train/each eval) 900 / 3,600 / 1,800 s 1,800 / 43,200 / 18,000 s
Outer admission floor from estimates 8,100 s 81,000 s; launch at 86,400 s

The Hebrew dataset revision remains main only as a visible preregistration placeholder. It must be replaced with the immutable, provenance-complete publication commit before any full command can run or any result can be cited.