Skip to content

CLI & API

Prerequisites

Ensure the server is up and running. To use dstack with AI agents, install skills.

The primary way to use dstack is the CLI. It can be used to manage fleets, runs, volumes, and gateways, view logs, and inspect events. Use the HTTP API for functionality not available in the CLI or for integrations that need to call the server directly.

CLI

See installation on how to install the CLI.

Configuration

The CLI requires a project configuration with the project name, server URL, and user token in ~/.dstack/config.yml.

projects:
  - name: main
    url: http://127.0.0.1:3000
    token: <user token>
    default: true
  - name: octocat
    url: https://sky.dstack.ai
    token: <user token>

Use dstack project to list, add, delete, and set the default project configurations. To run a command against a non-default project, pass --project NAME, or set DSTACK_PROJECT in the current shell.

Projects

Projects enable the isolation of different teams and their resources. Users can be added to projects and assigned roles. Each user has a user token for authentication.

Manage fleets

Before submitting runs, you must create at least one fleet. Fleets act as both pools of instances and templates for how those instances are provisioned.

Use dstack fleet to list existing fleets, their configurations, and instances (if any):

$ dstack fleet
Offers

Offers are available instance configurations that match resource requirements.

$ dstack offer --gpu H100 --max-offers 10

If no fleet is specified, dstack offer shows offers from all configured backends.

Use --fleet NAME to restrict offers to a fleet. Listing offers does not create capacity.

Define a fleet configuration in a YAML file. The filename must end with .dstack.yml, for example fleet.dstack.yml:

type: fleet
name: default

nodes: 0..1
idle_duration: 1h

resources:
  gpu: 0

Pass the fleet configuration to dstack apply:

$ dstack apply -f fleet.dstack.yml

If the nodes range starts with 0, dstack creates a fleet template. Instances are provisioned when matching runs are submitted.

Submit runs

To submit a run, define a dev environment, task, or service configuration. The example below submits a task.

type: task
name: hello

commands:
  - echo hello world

Submit the run:

$ dstack apply -f .dstack.yml

Plan and confirmation

dstack apply shows the plan and asks for confirmation before submitting the run. To only see the plan, answer n at the prompt:

$ echo "n" | dstack apply -f .dstack.yml

Use -y to skip confirmation.

Attached by default

For run configurations, dstack apply automatically attaches after submitting the run. This streams logs, forwards declared ports, and configures SSH access. See Attach to runs.

Use -d to submit in detached mode.

Attach to runs

If the run was submitted with -d, or if you need to attach to another job in a multi-job run, use dstack attach:

$ dstack attach &lt;run name&gt;

SSH

During dstack apply in attached mode and during dstack attach <run name>, the CLI downloads the current user's built-in private SSH key if needed and stores it under ~/.dstack/ssh/.

While attached, the CLI updates ~/.dstack/ssh/config with the run name as an SSH host alias and ensures this file is included from ~/.ssh/config:

Host &lt;run name&gt;
    HostName localhost
    Port &lt;local SSH port&gt;
    User root
    IdentityFile ~/.dstack/ssh/&lt;key&gt;
    IdentitiesOnly yes

For VM-based and SSH fleets, dstack may also configure the <run name>-host alias for SSH access to the host.

While attached, connect to the run with:

$ ssh &lt;run name&gt;

Use --job JOB_NUMBER with dstack attach to attach to another job. Ports declared in the run configuration are forwarded while attached.

User SSH keys

The server stores a built-in SSH key pair for each user.

Users can add custom public SSH keys via the UI or the users API. To use a custom private key for a particular run, pass --ssh-identity to dstack apply or dstack attach.

Browse logs

When dstack apply is attached, it streams logs for job 0 automatically. Use dstack logs to view logs in detached mode, or to view logs for a specific job:

$ dstack logs &lt;run name&gt;

Use --job JOB_NUMBER to select a job and --since to filter by time.

Attached logs

Use --logs with dstack attach to stream logs while attaching:

$ dstack attach &lt;run name&gt; --logs

Commands

Other common CLI commands include dstack ps, dstack stop, and dstack event.

Verbose and JSON modes

Use -v for more details where supported. For automation, use --json, e.g. dstack ps --json, dstack run get <run name> --json, or dstack fleet get <fleet name> --json.

API

The dstack API is represented by the HTTP API. Use it for functionality not available in the CLI or for integrations that need to call the server directly.

Authenticate

The HTTP API requires the Authorization header for user authentication:

Authorization: Bearer <user token>

Manage fleets

The fleets API can list existing fleets, their configurations, and instances (if any):

$ curl "&lt;server URL&gt;/api/project/&lt;project name&gt;/fleets/list" \
    -X POST \
    -H "Authorization: Bearer &lt;user token&gt;" \
    -H 'Content-Type: application/json' \
    -d '{"include_imported": true}'
Offers

To check available offers via the HTTP API, call /runs/get_plan with the same lightweight task specification used by dstack offer:

$ curl "&lt;server URL&gt;/api/project/&lt;project name&gt;/runs/get_plan" \
    -X POST \
    -H "Authorization: Bearer &lt;user token&gt;" \
    -H 'Content-Type: application/json' \
    -d '{
      "run_spec": {
        "configuration": {
          "type": "task",
          "commands": [":"],
          "image": "scratch",
          "user": "root",
          "resources": {
            "gpu": 0
          }
        }
      },
      "max_offers": 5
    }'

If fleets is not set in the run configuration, offers are returned from all configured backends. Use "fleets": ["default"] to restrict offers to a fleet.

To group offers by GPU and other fields, use the gpus API.

Creating fleets uses /fleets/get_plan followed by /fleets/apply:

$ curl "&lt;server URL&gt;/api/project/&lt;project name&gt;/fleets/get_plan" \
    -X POST \
    -H "Authorization: Bearer &lt;user token&gt;" \
    -H 'Content-Type: application/json' \
    -d '{
      "spec": {
        "configuration": {
          "type": "fleet",
          "name": "cpu-fleet",
          "nodes": "0..1",
          "idle_duration": "1h",
          "resources": {
            "gpu": 0
          }
        },
        "profile": {}
      }
    }'

Then apply the fleet plan:

$ curl "&lt;server URL&gt;/api/project/&lt;project name&gt;/fleets/apply" \
    -X POST \
    -H "Authorization: Bearer &lt;user token&gt;" \
    -H 'Content-Type: application/json' \
    -d '{
      "plan": {
        "spec": {
          "configuration": {
            "type": "fleet",
            "name": "cpu-fleet",
            "nodes": "0..1",
            "idle_duration": "1h",
            "resources": {
              "gpu": 0
            }
          },
          "profile": {}
        }
      },
      "force": false
    }'

Submit runs

Use the runs API to submit dev environments, tasks, and services. The example below submits a task:

$ curl "&lt;server URL&gt;/api/project/&lt;project name&gt;/runs/apply" \
    -X POST \
    -H "Authorization: Bearer &lt;user token&gt;" \
    -H 'Content-Type: application/json' \
    -d '{
      "plan": {
        "run_spec": {
          "run_name": "hello-api",
          "configuration": {
            "type": "task",
            "commands": ["echo hello world"]
          }
        }
      },
      "force": false
    }'

Set run_name if a stable run name is needed. Otherwise, the server can generate a run name.

Poll /runs/get to check the run status:

$ curl "&lt;server URL&gt;/api/project/&lt;project name&gt;/runs/get" \
    -X POST \
    -H "Authorization: Bearer &lt;user token&gt;" \
    -H 'Content-Type: application/json' \
    -d '{"run_name": "hello-api"}'

Poll logs

Use the logs API to poll logs. Get job_submission_id from /runs/get, e.g. from latest_job_submission.id.

$ curl "&lt;server URL&gt;/api/project/&lt;project name&gt;/logs/poll" \
    -X POST \
    -H "Authorization: Bearer &lt;user token&gt;" \
    -H 'Content-Type: application/json' \
    -d '{
      "run_name": "hello-api",
      "job_submission_id": "&lt;job submission id&gt;",
      "limit": 100
    }'

Use next_token from the response to continue polling.

Reference

For complete details on specific CLI commands and HTTP APIs, see the dstack server and server references.

OpenAPI

For complete information on the HTTP API, or to generate native clients, refer to openapi.json.

What's next?

  1. Follow the installation guide
  2. Read about projects
  3. Check fleets, dev environments, tasks, and services