Skip to content

[Presets] Support for dstack preset push and dstack preset pull - #4194

Merged
peterschmidt85 merged 9 commits into
masterfrom
preset-registry-push-pull
Aug 24, 2026
Merged

[Presets] Support for dstack preset push and dstack preset pull#4194
peterschmidt85 merged 9 commits into
masterfrom
preset-registry-push-pull

Conversation

@peterschmidt85

@peterschmidt85 peterschmidt85 commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Push and pull

A preset created on one machine can now be used on another. Push it to the registry:

$ dstack preset push qwen38-27b-mi300x main/qwen38-27b-mi300x
OK

Then, on any other machine, pull it from the registry and export it to a service configuration:

$ dstack preset pull main/qwen38-27b-mi300x
OK

$ dstack preset export main/qwen38-27b-mi300x -f qwen38.dstack.yml
OK

$ dstack apply -f qwen38.dstack.yml

export writes the preset's patch files next to the configuration, so the service is applied
exactly as it was verified.

Push shares the verified service, its benchmark, and the hardware it was verified on. The
configuration, prompt, and trials that produced it stay on the machine that created it.

A pulled preset is used like any other, and is named <project>/<name>, which can never clash
with a preset of your own:

$ dstack preset list -a
 NAME                      ID                                    BASE              CONSTRAINTS      BENCHMARK                             STATUS           SUBMITTED
 main/qwen38-27b-mi300x    e7c8b170-8ca6-41cc-bfa9-ed1ba71c8c88  Qwen/Qwen3.8-27B  io=10K/1.5K c=4  tps/user=138 ttft=852ms ctx=1M        pulled           11 mins ago
 qwen38-27b-mi300x-crack2  6900d9d7                              Qwen/Qwen3.8-27B  io=10K/1.5K c=4  tps/user=138 ttft=852ms ctx=1M  ████  verified (4/15)  1 week ago

Its status is pulled, in the table above and in dstack preset get --json.

Names

A name is a moving reference, as a Docker tag is. Pushing one that already exists transfers it to
the new preset, and the superseded preset keeps existing without a name, reached as
<project>/<id>, which pull also accepts. A preset pulled that way lands untagged, so it never
shadows the one the name points at. Deleting a preset releases its name rather than handing it
back to an older one.

Registry

The registry is part of the dstack server. On dstack Sky, that is https://sky.dstack.ai. Push and
pull require membership in the project. If the server has no registry, both say so.

The server comes from the project's entry in ~/.dstack/config.yml. A project that is not there
falls back to dstack Sky; DSTACK_NO_SKY_FALLBACK turns the fallback off.

Note

The fallback is exactly the one dstack login applies.

UI

Presets are listed with filters for project, user, and base model. A preset opens on what it was
verified on, the benchmark and the constraints it holds under, and the commands to pull, export,
and apply it. The pages are Sky-only, gated as Billing is.

Also here

  • dstack preset export no longer fails with IsADirectoryError when the preset mounts a
    directory in files.
  • Presets can be the target of events, and list_events filters by them, so a server with a
    registry can record who pushed what. The events table shows them and filters by them.
  • Events moves down the sidebar to sit next to Projects.

Breaking changes

  • dstack preset get --json reports the served model repository as repo instead of model, so
    base (the model family), repo (what the service loads), and service.model (what the
    endpoint serves it as) are now distinct.

Backward compatibility

  • Presets created by earlier versions are upgraded when read.

Note

The registry that push and pull talk to is implemented separately and is not part of this
PR.

Andrey Cheptsov and others added 7 commits August 23, 2026 14:24
Adds the client half of the preset registry: a preset is pushed to a
project as `<project>/<name>` and pulled anywhere else by name or ID.
Push carries the verified service, its benchmark, the hardware it was
verified on, and the preset's files; the creation session stays local.

Stored presets are now tagged by status, `verified` for a local creation
and `pulled` for a registry copy, and the served model repository is
reported as `repo` instead of `model`. Presets written by earlier
versions are upgraded when read.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PresetConfiguration` and its neighbours moved to `configurations.py`, but
the reference page still imported them from `core.models.presets`, which
failed the docs build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`get_files` replaces `get_file`: one request returns every archive the
preset carries, framed by path and length, so a pull costs one round trip
and one preset lookup however many files there are.

The archives are also keyed by their path in the container now, which is
what `RunSpec` carries, so `PresetArchiveMapping` is gone and the envelope
is the same as a run's. Where each archive lands on disk is what the
preset's own `files` already say.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Presets can be the target of events, and `list_events` filters by them,
so a server extending dstack with a preset registry can record who pushed
what.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`files` may mount a directory, and exporting a preset carrying one failed
with `IsADirectoryError`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The events table rendered a preset target as `---`, and neither the type
filter nor the target ID filter knew about presets.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The presets docs cover pushing, pulling, and the registry behind them.
Traces move under Monitor presets, the intro is shorter, and the export
snippet matches what the command prints now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@peterschmidt85
peterschmidt85 marked this pull request as ready for review August 24, 2026 13:31
Andrey Cheptsov and others added 2 commits August 24, 2026 19:38
Pushing a name that already exists transfers it to the new preset, the way
a Docker tag moves. The superseded preset keeps existing without a name and
is reached as `<project>/<id>`, so `name` is optional on the wire and
`is_current` is gone: a preset that arrives without one is a preset the name
has moved on from, and it lands untagged locally.

Also adds the list and delete request schemas the registry UI calls, and
`project_name` to the record, so presets can be listed across projects.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Lists the presets in the registry, filtered by project, user, and base
model, and opens each one to show what it was verified on, how it performs,
and the commands to pull, export, and apply it.

The pages are Sky-only, gated as Billing is. Events moves down the sidebar
to sit next to Projects.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@peterschmidt85
peterschmidt85 merged commit e44c6e4 into master Aug 24, 2026
27 checks passed
@peterschmidt85
peterschmidt85 deleted the preset-registry-push-pull branch August 24, 2026 19:02
Comment on lines +48 to +52
def resolve_registry_client(project: str) -> APIClient:
"""The server hosting the registry a ref points at: the config entry with
the project's name, or
Sky with any configured Sky token (dstack tokens are user tokens, so one Sky
entry authenticates any Sky project the user is a member of)."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if I have several Sky users, the CLI will select a random one?

This might be unexpected — that random user may have insufficient permissions, or it may be a user that I just wouldn't want to be used and recorded as actor in events.

Long-term, this could be solved by redesigning CLI authorization. Short term — by not falling back to Sky if it's not clear which user to choose (if there are more than one)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants