CLI reference
The distil CLI drives the whole platform. Install it from
Install the CLI. Check your version with
distil --version, run distil update to move to the current one, and distil <group> --help
for a command’s flags.
The entity model
Section titled “The entity model”Every stage is an entity created by one command, from local files or by running a job over the entity before it. How the platform works explains the chain.
| Stage | Entity it creates |
|---|---|
| Traces | traces object (PreparedTraces) |
| Dataset, from files or from a traces object | dataset (Dataset) |
| Relabel traces, test or train | dataset, with the parent’s ID and the operation |
| Synthetic data generation, test or train | dataset, with the parent’s ID and the operation |
| Teacher evaluation | teacher evaluation (TeacherEvaluation) |
| Model training | model (SLM) |
| Deployment | deployment (Deployment) |
| Inference endpoint | inference endpoint (InferenceEndpoint) |
The command that creates each one:
distil traces upload --traces <file>
distil traces create-from-inference-endpoint <unique-endpoint-name>
distil dataset create --data <dir>
distil dataset create-from-traces --config <file> --job-description <file> <traces-id>
distil dataset relabel-traces-test [--smoke] <dataset-id>
distil dataset relabel-traces-train [--smoke] <dataset-id>
distil dataset generate-synthetic-data-test [--smoke] <dataset-id>
distil dataset generate-synthetic-data-train [--smoke] <dataset-id>
distil teacher-evaluation create-from-dataset <dataset-id>
distil slm create-from-dataset [--smoke] <dataset-id>
distil deployment create-from-slm <slm-id>
distil inference-endpoint create-from-deployment --name <prefix> \
--fallback-model <owner/model> <deployment-id>
The commands that read each one, as subcommands of its group:
| Command group | Read subcommands |
|---|---|
distil traces |
download |
distil dataset |
status, logs, metrics, download, download-metadata |
distil teacher-evaluation |
status, logs, metrics, download-metadata, download-predictions |
distil slm |
status, logs, metrics, download, download-metadata, download-predictions |
distil deployment |
status, logs |
distil inference-endpoint |
download-traces |
Every group also has list (alias ls) and show. status and logs on a dataset report the
expand job that produced it; a dataset created from files or from a traces object has no job, so
its status reads Success at once and its logs are empty.
distil seed-dataset and distil training-dataset read old entities: list, show,
download and download-metadata. Their other commands print the replacement and exit 1. See
Migrating old entities.
Authentication
Section titled “Authentication”You can create an account and sign in without leaving the terminal. distil signup (aliases
register, join) creates an account, distil auth (alias login) signs in to an existing one,
distil whoami prints the current user, distil access-token prints an access token for the
REST API, and distil logout signs out:
distil signup
distil auth
distil whoami
distil access-token
distil logout
distil signup and distil auth are the same command: each prints a one-time code, opens the
sign-in page in your browser, and finishes with Logged in as <email>. The full flow and its
messages are on Account and authentication. The session
is kept in ~/.config/distillabs/session.json (under $XDG_CONFIG_HOME when set) and refreshed,
so a run spanning hours needs no second login.
Access tokens for the REST API
Section titled “Access tokens for the REST API”distil access-token refreshes the session and prints a new access token, and nothing else, so
it drops straight into a header:
curl -H "Authorization: Bearer $(distil access-token)" https://api.distillabs.ai/datasets
Tokens are short-lived, so fetch a new one rather than holding it. Signed out, the command exits 1
with Not logged in or session expired. See Using the REST API.
Commands that accept –output json
Section titled “Commands that accept –output json”--output json (-o json) is registered on every command that reads, creates, deletes, links
or downloads. It prints one JSON object or array on stdout and nothing else:
- reads and creates print the entity as the API returns it;
inference-endpoint create-traces-exportadds the file it wrote underfiles; - deletes print
{"id": ..., "deleted": true}(nameinstead ofidforapi-keys delete); inference-endpoint link-api-keyandunlink-api-keyprint{"unique_endpoint_name": ..., "api_key_name": ..., "linked": true}(falseafter unlinking);- downloads print
{"files": [...]}with every file written, or an empty list when there was nothing to write.
An error prints {"error": "..."} and exits 1. --output isn’t registered on auth, signup,
logout, access-token (it already prints the bare token), update, docs, skill install,
skill uninstall or the deprecated commands; passing it there fails with
No flag registered for --output.
Without --output json a command prints its result formatted for reading, which is what the
examples on this page show. Use the JSON form in scripts; the
agent skill does.
Supplying files
Section titled “Supplying files”--data <dir> names a directory, and the CLI uploads the files in it by name.
| Command | Required in --data <dir> |
Optional |
|---|---|---|
distil traces upload |
traces.jsonl |
none |
distil dataset create |
config.yaml, job_description.json |
train.jsonl, test.jsonl, traces.jsonl; a missing one is stored as an empty split |
distil slm create |
model.tar, config.yaml |
none |
config.yml is accepted for config.yaml. The per-file flags (--traces, --train, --test,
--config, --job-description, --model) replace one path each, and combining them with
--data is refused; with per-file flags, dataset create needs --config and
--job-description and any of the other three. Only the files you give are uploaded: the
platform reads a missing data file as “this dataset has none of this kind”
(Dataset overview). A file named but not found is reported before
anything uploads.
The download commands write these same names, so a downloaded directory is accepted unchanged by
dataset create --data. That is how a change to the rows is made, since no override reaches the
data.
distil dataset create-from-traces takes --config and --job-description as required inputs,
because a traces object holds neither file. distil slm create --data <dir> registers an
existing model.tar and config.yaml as an SLM; the tarball must hold the LoRA adapter under
model-adapter/. It doesn’t train a model.
Credits
Section titled “Credits”Print your credit balances:
distil credits-balance
The output has one row per metered route, sorted by name. An excerpt:
datasets_from_datasets_generate_synthetic_data_post 5
datasets_from_datasets_relabel_traces_post 5
datasets_from_datasets_smoke_post 20
datasets_from_prepared_traces_post 5
datasets_post 5
prepared_traces_post 100
slms_from_datasets_post 5
slms_from_datasets_smoke_post 20
teacher_evaluations_post 5
An account with nothing metered prints No metered endpoints. A --smoke submission spends the *_smoke_post key of its route.
The route keys and starting balances are in How the platform works.
Creating the job inputs
Section titled “Creating the job inputs”The traces object
Section titled “The traces object”Upload a trace file, or have the platform pull an endpoint’s records:
distil traces upload --traces traces.jsonl
distil traces create-from-inference-endpoint <unique-endpoint-name>
Both print Prepared traces created. ID: <traces-id>. traces upload checks only that the file
is there; a malformed trace fails the first expand that reads it, and the job log names the
cause. --data <dir> with a traces.jsonl in it replaces --traces.
The dataset
Section titled “The dataset”From a traces object, with the config and the job description written first (Dataset overview):
distil dataset create-from-traces --config input/config.yaml \
--job-description input/job_description.json <traces-id>
The command prints Dataset created. ID: <dataset-id>. No job runs: the traces are copied,
train and test are empty, and the dataset is ready at once. The trace file’s shape must match
trace_processing.observation_format in the config: langfuse for a traces object from an
endpoint (Traces). A traces.jsonl downloaded from such a traces
object uploads again with dataset create --traces and the same langfuse setting, which is how
a test set is put next to new endpoint traces (Model iterations).
From files on disk, any subset of the three data files:
distil dataset create --data input
distil dataset create --config input/config.yaml --job-description input/job_description.json \
--traces traces.jsonl --test test.jsonl
dataset create validates the files before creating anything, exactly as the jobs will parse
them. An invalid bundle exits 1 with the reason on stderr and creates nothing: a file missing from
the directory is caught locally, and an unsupported task, a row in the wrong shape or a row
present in both splits come back from the platform with the row named
(Uploads and validation).
Running the expand operations
Section titled “Running the expand operations”Each expand creates a new dataset whose parent is the one you name, and prints the new ID (The expand operations). Relabel traces into the test split or the train split:
distil dataset relabel-traces-test <dataset-id>
distil dataset relabel-traces-train <dataset-id>
The count comes from trace_processing.num_test_relabelled or num_train_relabelled in the
parent’s config, or from the override. Generate synthetic rows into the test split or the train
split:
distil dataset generate-synthetic-data-test <dataset-id>
distil dataset generate-synthetic-data-train <dataset-id>
The target comes from synthgen.test_generation_target or train_generation_target. All four
take --smoke, which forces the count or the target to 128 and spends the smoke credit
(Smoke runs):
distil dataset relabel-traces-test --smoke <dataset-id>
distil dataset generate-synthetic-data-train --smoke \
--config synthgen/smoke-2/config.yaml <dataset-id>
Poll the new dataset’s status until it reads Success:
distil dataset status <new-dataset-id>
Overrides
Section titled “Overrides”Six creates accept --config <file> (-c) and --job-description <file>: the four expand
commands, teacher-evaluation create-from-dataset and slm create-from-dataset. Both flags are
optional and independent; an omitted one is inherited from the parent. Each file replaces the
parent’s whole (Overrides), so read the parent’s file, edit
it, and send it back. Download the parent’s files into iter-2, which is free:
distil dataset download-metadata -d iter-2 <dataset-id>
dataset download-metadata writes config.yaml and job_description.json and nothing else.
Edit iter-2/config.yaml and submit it with the create:
distil dataset generate-synthetic-data-train --config iter-2/config.yaml <dataset-id>
The config of a dataset written by an expand is fully expanded: every default written out, keys
sorted, comments dropped. A dataset from dataset create --data returns its config as uploaded;
one from dataset create-from-traces returns it normalized (comments dropped).
A config with a complete base but no synthgen or tuning section is accepted, and those
sections take their defaults with no error. A config missing base.task is refused with
Invalid config: ... base.task Field required. To check what a submission ran with, read the new
dataset’s config back and diff it against what you sent.
Running the other stages
Section titled “Running the other stages”Each create prints the new entity’s ID. Teacher evaluation:
distil teacher-evaluation create-from-dataset <dataset-id>
Model training, as a smoke run and as a full run:
distil slm create-from-dataset --smoke <dataset-id>
distil slm create-from-dataset <dataset-id>
--smoke runs the small version of the job (Smoke runs)
and combines with the override flags. Training takes its config from the dataset. A sweep is one
submission per config against the same dataset; submissions run concurrently. Retraining the
same dataset under a new config regenerates nothing:
distil dataset download-metadata -d retrain <dataset-id>
# in retrain/config.yaml, under tuning: num_train_epochs: 6
distil slm create-from-dataset --config retrain/config.yaml <dataset-id>
Monitoring jobs
Section titled “Monitoring jobs”<group> is a command group such as slm or dataset, and <id> is the entity’s ID:
distil <group> status <id>
distil <group> logs <id>
distil <group> list
status prints the job’s status; the values are in
Job status. Deployments report deployment_status and
endpoint_status instead.
Read the status field, not the exit code: a status command that reaches the platform exits 0
whatever the job did. Creates and downloads report through the exit code: a rejected bundle, an
invalid config or a download of something not produced yet exits 1 with the reason on stderr
(Dataset <id> is not ready. Its job status is JOB_RUNNING.).
logs prints the whole job log. It fills while the job runs; in the first seconds it reads
No logs for this dataset.
list returns one object per entity, newest first, with id, created_at and the parent’s ID
under its own key (dataset_id, slm_id, and so on). A dataset also carries its operation
and its parent as parent_dataset_id or parent_prepared_traces_id; a traces object its
source. dataset show <id> prints the same for one dataset, plus its status (Success at once
for a dataset no job produced). list is how you recover a lost ID, and show walks a chain back to its root.
Fetching metrics and predictions
Section titled “Fetching metrics and predictions”Read the scores of each stage that has them, then download the per-example predictions:
distil teacher-evaluation metrics <teacher-evaluation-id>
distil slm metrics <slm-id>
distil teacher-evaluation download-predictions <teacher-evaluation-id>
distil slm download-predictions <slm-id>
The *_performance object maps metric name to score
(Metrics). A metric the run didn’t compute is null rather than
absent. A predictions file is JSONL, one test example per line, with the prompt (the test row’s
messages), the reference completion, the prediction and that example’s score under each metric
name.
slm download-predictions holds the tuned model’s predictions only; the base model’s scores are
in slm metrics.
Reading a dataset
Section titled “Reading a dataset”Download the whole dataset into data, count the rows, and read the sizes:
distil dataset download -d data <dataset-id>
wc -l data/train.jsonl data/test.jsonl data/traces.jsonl
distil dataset metrics <dataset-id>
Both are free. download writes all five files; an empty split is an empty file. metrics reports train_data_size_bytes, test_data_size_bytes
and traces_size_bytes. The rows of a split are the parent’s rows followed by the ones the
expand added; to see only the new rows, download the parent too and diff.
Downloads
Section titled “Downloads”| Entity | Data files | Config + job description |
|---|---|---|
| Traces object | traces download |
none: it holds neither |
| Dataset | dataset download |
dataset download-metadata |
| Teacher evaluation | none | teacher-evaluation download-metadata |
| SLM | slm download |
slm download-metadata |
Every command that writes a directory takes --destination <dir> (-d) and otherwise names one
after the entity (<id>-traces, <id>-data, <id>-metadata, <id>-slm). The *-predictions
commands write a single file, take --file-name <path> (-d), and default to
<id>-teacher-evaluation-predictions.jsonl or <id>-slm-predictions.jsonl. Downloads overwrite
what is there.
distil slm download writes model.tar (the LoRA adapter under model-adapter/, the inference
client and the licenses) and config.yaml, and checks free disk space first.
distil slm download-metadata writes config.yaml, job_description.json and model_client.py,
a few kilobytes.
Deployment
Section titled “Deployment”Deploy a model, check its status, and delete it:
distil deployment create-from-slm <slm-id>
distil deployment status <deployment-id>
distil deployment delete <deployment-id>
Poll deployment_status to JOB_SUCCESS before creating the endpoint;
create-from-deployment refuses earlier with Deployment is not ready. After
deployment delete, deployment_status stays JOB_SUCCESS; endpoint_status reading
stopped confirms the deployment is down. How deployments behave:
distil labs inference.
Inference endpoints
Section titled “Inference endpoints”Create an endpoint, with or without a deployment behind it, and list or show endpoints. list
has the alias ls:
distil inference-endpoint create --name <prefix> \
--fallback-model <owner/model> [--trace-sample-rate <0-1>]
distil inference-endpoint create-from-deployment --name <prefix> \
--fallback-model <owner/model> <deployment-id>
distil inference-endpoint list
distil inference-endpoint show <unique-endpoint-name>
For example, this creates an endpoint with the prefix support:
distil inference-endpoint create --name support --fallback-model "openai/gpt-4.1-mini"
The command prints the unique endpoint name on its Endpoint Name line, such as
support-yeOdAS. create makes an endpoint in front of your production model; create-from-deployment one with
a deployed model as its primary. --name is a prefix: record the unique endpoint name the
command prints, which every other command and the model field of every request take.
--fallback-model is an OpenRouter slug in owner/model form.
--trace-sample-rate sets the fraction of calls recorded, default 1; show reports it as
trace_sampling_rate.
API keys
Section titled “API keys”Create, list and delete keys, and link a key to an endpoint or unlink it:
distil api-keys create <key-name>
distil api-keys list
distil api-keys delete <key-name>
distil inference-endpoint link-api-key <unique-endpoint-name> <key-name>
distil inference-endpoint unlink-api-key <unique-endpoint-name> <key-name>
api-keys create prints the secret once and writes it to <key-name>.json. --no-file skips
the file, for a key that goes straight into a secret store.
Calling an endpoint
Section titled “Calling an endpoint”Call an endpoint with a chat completions request, where support-yeOdAS is the unique endpoint
name and <api-key> is the secret of a key linked to it:
curl https://inference.distillabs.ai/v1/chat/completions \
-H "Authorization: Bearer <api-key>" -H "Content-Type: application/json" -d '{"model": "support-yeOdAS", "messages": [{"role": "user", "content": "Say hi."}]}'
model carries the unique endpoint name; the rest is an ordinary chat completions request. A
trained model behind an endpoint is queried with its own client:
Querying your model.
Downloading the traces
Section titled “Downloading the traces”Download the newest 1,000 records from the last day, every record since a date, up to 5,000 records, or records into a named file:
distil inference-endpoint download-traces <unique-endpoint-name>
distil inference-endpoint download-traces --from-start-time 2026-09-01 --all <unique-endpoint-name>
distil inference-endpoint download-traces --count 5000 <unique-endpoint-name>
distil inference-endpoint download-traces --file-name raw-traces.jsonl <unique-endpoint-name>
The command writes JSONL, one record per call, to <unique-endpoint-name>-traces.jsonl unless
--file-name says otherwise. --from-start-time and --to-start-time take an ISO 8601 date or
date-time; the default window is the last day. Within it, --count (-c) caps the records
(default 1000) and --all takes every one; passing both is refused. With no records in the window, no file is written.
The file holds endpoint records, not traces: convert it as in
Endpoint records to traces and upload the result with
distil dataset create --traces or distil traces upload --traces.
Traces from an endpoint
Section titled “Traces from an endpoint”Create a traces object from the endpoint’s records, with no download:
distil traces create-from-inference-endpoint <unique-endpoint-name>
The command prints Prepared traces created. ID: <traces-id>. The platform pulls the records,
so nothing is downloaded or converted; the dataset you create from it needs
trace_processing.observation_format: langfuse in its config. Which records it includes and
when: Endpoint records to traces.
Other commands
Section titled “Other commands”| Command | What it does |
|---|---|
distil --version |
Prints the installed version |
distil update |
Replaces the binary in place |
distil docs |
Opens these docs |
distil skill install |
Installs or updates the agent skill for every coding agent |
distil skill uninstall |
Removes the agent skill |