> ## Documentation Index
> Fetch the complete documentation index at: https://docs.andromeda.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Cluster API calls are made as a signed-in person with an OIDC bearer token. There are no API keys, and service-account tokens are refused (Business returns 401, Platform returns 403).
> Platform takes the organization as the query parameter businessOrgId on most cluster routes, but as organizationId on /clusters/{clusterId}/ssh-access and /clusters/{clusterId}/kubeconfig.
> The Business API uses snake_case. The Platform API uses camelCase, except /ssh-access and /machines, which use snake_case.
> Business write requests need Idempotency-Key and Audit-Reason headers.
> Storage capacity can grow but cannot shrink, including disk and PVC resizing. Each purchase adds capacity.
> A cluster's storage can be Ceph, WEKA, or both, or NFS on its own. The Ceph quota, the purchased bytes, and Slurm's default 100 GiB shared-volume request are three different quantities.
> Organization permissions cover every cluster the organization owns. A Kubernetes resource grant shares one cluster or namespace, possibly with someone outside the organization, and lets them read that cluster and fetch its kubeconfig. A grant does not give Slurm SSH, Slurm configuration, or organization storage inventory access. Slurm SSH requires organization membership and clusters.ssh.
> The SSH login name is <cluster-id>.<username>. The gateway supports shells, commands, SFTP (including modern scp), and forwarding to loopback ports on the login node. Legacy scp and rsync need their programs on the login node. Remote forwarding and non-loopback destinations are refused.
> Use POST /me/ssh-keys for personal key registration. POST /organizations/{orgID}/ssh-keys is a deprecated alias and requires no membership. Read the preferred shell from GET /me as user.login_shell; update it with PUT /me/login-preferences.
> GET /clusters/{clusterId}/ssh-access returns 200 with ready and reason, even when access is not ready. ready: true does not mean compute nodes or Slurm accounting are ready. To confirm a key or shell change reached a cluster, require observation_current: true and compare ssh_key_set_generation with generation from GET /me/ssh-keys, and shell with user.login_shell from GET /me.
> Adding or removing a login account restarts the cluster's login nodes, Slurm controller, and accounting service, then its compute nodes one at a time; jobs running on a restarting node end. An account is added or removed when a person with an active key gains or loses SSH access, or a person with SSH access registers their first key or revokes their last. Other key changes and shell changes restart no nodes.

# Quickstart

> Sign in, find your cluster, register an SSH key, and run nvidia-smi on a GPU node through Slurm in about ten minutes.

This walkthrough is for organization members with Slurm SSH access. If someone shared a Kubernetes cluster or
namespace with you, start with [Access to a shared cluster](/clusters/permissions#access-to-a-shared-cluster).

## Before you start

You need:

* An Andromeda account in an organization that has a running Slurm cluster.
* The `clusters.read` and `clusters.ssh` permissions in that organization. The `Engineer` profile includes both. If
  you're not sure, continue: step 2 shows how to check.
* The `andromeda` CLI, `jq`, and OpenSSH. [Authentication](/clusters/authentication#install-the-cli) explains how to get the
  CLI.

<Steps>
  <Step title="Sign in">
    ```sh theme={null}
    andromeda auth login
    ```

    Open the URL the CLI prints, sign in, and enter the code. See [Authentication](/clusters/authentication) for details.
  </Step>

  <Step title="Find your organization">
    ```sh theme={null}
    andromeda call business GET /me > me.json
    jq -c '.memberships[] | {org_id, role}' me.json
    ```

    ```json theme={null}
    {"org_id":"org_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3","role":"member"}
    ```

    Save the organization ID:

    ```sh theme={null}
    export ORG_ID=$(jq -r '.default_org_id // empty' me.json)
    echo "$ORG_ID"
    ```

    If this prints nothing, you belong to more than one organization. Set `ORG_ID` to the `org_id` of the one that owns
    the cluster, from the list above.

    Check which permissions you have in it:

    ```sh theme={null}
    USER_ID=$(jq -r .user.id me.json)
    andromeda call business GET "/organizations/$ORG_ID/members/$USER_ID/permissions" | jq -c .permissions
    ```

    ```json theme={null}
    ["clusters.read","clusters.ssh"]
    ```

    `organization.owner` or `organization.admin` also covers everything on this page. If you have neither, and
    `clusters.read` or `clusters.ssh` is missing, ask an owner or admin of the organization to grant it. See
    [Permissions](/clusters/permissions#grant-permissions).
  </Step>

  <Step title="Find your cluster">
    ```sh theme={null}
    andromeda call platform GET "/clusters?businessOrgId=$ORG_ID" > clusters.json
    jq -r '.items[] | [.id, .spec.name, .status.lifecycleState] | @tsv' clusters.json
    ```

    ```text theme={null}
    0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b	training-h200	active
    ```

    Save the ID of the first `active` cluster. If the organization has several, set `CLUSTER_ID` to the one you want
    instead.

    ```sh theme={null}
    export CLUSTER_ID=$(jq -r 'first(.items[] | select(.status.lifecycleState == "active")) | .id' clusters.json)
    ```

    Check that the cluster runs Slurm and that Slurm is ready:

    ```sh theme={null}
    andromeda call platform GET "/clusters/$CLUSTER_ID/options?businessOrgId=$ORG_ID" |
      jq -c '{scheduler: .scheduler.configured.value, ready: .scheduler.ready.status}'
    ```

    ```json theme={null}
    {"scheduler":"sunk","ready":"True"}
    ```

    `sunk` means the cluster runs Slurm. If it shows `kubernetes`, the cluster has no Slurm login node; use
    [kubectl](/clusters/kubernetes) instead.
  </Step>

  <Step title="Register your SSH key">
    The key must be Ed25519. Create one with `ssh-keygen -t ed25519` if you don't have one.

    <Warning>
      Your first key adds you to the user list of every cluster where you have SSH access, which restarts their compute
      nodes and ends the jobs running on them. If others are running jobs, register your key when they are done; see
      [Access changes restart nodes](/clusters/ssh#access-changes-restart-nodes).
    </Warning>

    ```sh theme={null}
    jq -n --arg key "$(cat ~/.ssh/id_ed25519.pub)" '{public_key: $key}' |
      andromeda call \
        --header "Idempotency-Key: $(uuidgen)" \
        --header 'Audit-Reason: Register SSH key' \
        --data @- \
        business POST /me/ssh-keys |
      jq -r .ssh_key.fingerprint
    ```

    ```text theme={null}
    SHA256:Qm9vbGVhbiBhbGdlYnJhIGlzIHRoZSBrZXkgdG8gaXQ
    ```

    The cluster now sets up your login. Wait until it is ready:

    ```sh theme={null}
    for attempt in $(seq 60); do
      andromeda call platform GET "/clusters/$CLUSTER_ID/ssh-access?organizationId=$ORG_ID" > ssh-access.json || break
      jq -e .ready ssh-access.json > /dev/null && { echo 'SSH access is ready'; break; }
      jq -r .reason ssh-access.json
      sleep 10
    done
    ```

    While your login is being set up, the endpoint returns `200` with `ready: false` and a `reason`, which the loop
    prints. The loop gives up after ten minutes, or at the first HTTP error. If it ends without printing `SSH access is ready`, see [Troubleshooting](/clusters/ssh#troubleshooting).

    `srun` can still fail for a few minutes after this, while compute nodes and Slurm accounting catch up; see
    [Wait for access](/clusters/ssh#wait-for-access).
  </Step>

  <Step title="Connect">
    ```sh theme={null}
    andromeda call platform GET "/clusters/$CLUSTER_ID/ssh-access?organizationId=$ORG_ID" > ssh-access.json
    HOST=$(jq -r .hostname ssh-access.json)
    LOGIN="$CLUSTER_ID.$(jq -r .username ssh-access.json)"

    echo "$HOST $(jq -r .host_key ssh-access.json)" >> ~/.ssh/known_hosts
    ssh -l "$LOGIN" "$HOST"
    ```

    The login name is the cluster ID, a dot, and your username. You land in your home directory on the cluster's login
    node.
  </Step>

  <Step title="Run on a GPU">
    On the login node, `sinfo` lists the partitions and nodes. Run `nvidia-smi` on one node, with all 8 of its GPUs:

    ```sh theme={null}
    sinfo
    srun --nodes=1 --gres=gpu:8 nvidia-smi -L
    ```

    ```text theme={null}
    GPU 0: NVIDIA H200 (UUID: GPU-...)
    GPU 1: NVIDIA H200 (UUID: GPU-...)
    ...
    GPU 7: NVIDIA H200 (UUID: GPU-...)
    ```
  </Step>
</Steps>

## Next steps

* [Train nanoGPT in a batch job](/clusters/examples/nanogpt-speedrun), a complete example on one 8-GPU node.
* [Connect over SSH](/clusters/ssh): moving files, `~/.ssh/config`, and why long work belongs in `sbatch`.
* [Configure Slurm](/clusters/slurm-configuration): partitions, prolog scripts, packages.
* [Concepts](/clusters/concepts): organizations, the two cluster APIs, and how access reaches a cluster.
* [API reference](/api-reference/overview).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.