Customizing the starter templates
The scaffolder writes a working trainer insrc/arkor/trainer.ts. The templates are a starting point: every field is yours to change, and most projects will outgrow the defaults within the first few runs. This recipe walks the four customizations that come up first.
The starting trainer (after --template triage) looks like this:
1. Swap the dataset
The dataset is what the model actually learns from. The most common change is moving from the demo dataset to your own. Use a different HuggingFace dataset. Passname, optionally pin split and subset:
{ type: "file" } option today. Local files have to be hosted somewhere the backend can reach. See SDK § DatasetSource.
2. Adjust hyperparameters
The typed optionals onTrainerInput are the safe knobs. Each takes the cloud-API default if omitted:
dryRun:
dryRun: true runs the full pipeline against a truncated dataset and a capped step count. It still uses GPU time (it is a smoke test, not a no-op), but the run finishes in a couple of minutes so you can check that your config and callbacks behave before committing to a long run. See SDK § createTrainer.
The advanced fields (warmupSteps, loggingSteps, saveSteps, evalSteps, trainOnResponsesOnly, datasetFormat, datasetSplit) are typed as unknown and forwarded to the cloud API verbatim. Use them only if you already know the backend’s expected shape; the SDK does not type-check the values you pass.
3. Add lifecycle callbacks
Callbacks are how every other recipe in this section plugs in. Even the scaffolded trainer can grow callbacks one at a time:- Mid-run evaluation plugs into
onCheckpoint. - Early stopping plugs into
onLogand the trainer’sabortSignal. - Slack / Discord notifications plug into
onCompletedandonFailed.
4. Change the base model
Themodel field is forwarded to the cloud API as a string. Today the curated path uses gemma-4-E4B-it, which is what every starter template ships with. The cloud API decides what other identifiers it accepts; sending an unsupported value produces a 4xx from upstream and a training.failed event with the backend’s error message.
model field as a single supported value rather than an open menu.
Putting it together
A trainer that uses every customization above looks like this:AbortController and trainer.cancel() pair you need so an aborted run does not keep burning GPU on the backend.